1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> 6 <title>æ¸ä½æåä¸å¿</title> 7 <link rel="icon" href="/auth-assets-7q2k9x4m/favicon.png"> 8 <link rel="stylesheet" href="/auth-assets-7q2k9x4m/auth.css"> 9 <style nonce="OEJNNdEDZn0oGoyYA3Jbug">.captcha-zone{display:flex;flex-direction:column;align-items:center;gap:.55rem}.tsr-hidden{display:none}.cap-fallback-note{font-size:12px;line-height:1.4;opacity:.75;margin:0;text-align:left}.cap-toggle{font-size:12.5px}.cap-back{font-size:12.5px}.cap-help{font-size:13px;text-align:center}</style> 10 <style nonce="OEJNNdEDZn0oGoyYA3Jbug">.cap-bar{display:flex;align-items:center;justify-content:center;gap:13px;flex-wrap:wrap;margin-top:4px} 11.cap-switch{display:flex;flex-direction:column;gap:3px;align-items:flex-start;text-align:left;min-width:0} 12.cap-switch:empty{display:none} 13.cd-row{display:flex;flex-direction:column;align-items:center;gap:1px;margin:0;position:relative} 14.cd-row[hidden]{display:none} 15.cd-ring-wrap{position:relative;width:42px;height:42px;flex:none;cursor:help} 16.cd-ring-wrap svg{display:block} 17.cd-arc{transition:stroke-dashoffset .5s linear,stroke .3s} 18.cd-num{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:500;font-variant-numeric:tabular-nums} 19.cd-state{font-size:11px;opacity:.6;text-align:center;white-space:nowrap} 20.cd-tip{position:absolute;left:0;bottom:calc(100% + 8px);width:240px;max-width:78vw;background:rgba(18,20,26,.96);color:#fff;font-size:12px;line-height:1.5;padding:8px 10px;border-radius:8px;opacity:0;visibility:hidden;transition:opacity .15s;pointer-events:none;z-index:30} 21.cd-ring-wrap:hover ~ .cd-tip,.cd-ring-wrap:focus ~ .cd-tip{opacity:1;visibility:visible} 22.cd-expired{display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;padding:10px 0 4px} 23.cd-expired.tsr-hidden{display:none} 24.cd-expired .cd-ring-wrap{width:50px;height:50px} 25.cd-expired .cd-num{color:#E24B4A} 26.cd-exp-title{font-size:1.05rem;margin:.2rem 0 0} 27.cd-exp-body{margin:0} 28.cd-locked > form{display:none} 29@media (prefers-reduced-motion:reduce){.cd-arc{transition:none}}</style>
vendor: 84 bytes, lines 29-30
29 30 <script src="https://www.google.com/recaptcha/api.js?hl=en" async defer></script>
31</head> 32<body data-layout="split"> 33 <div class="bg"></div> 34 35 <header class="topbar"> 36 <a class="brand" data-link="official" href="https://ascdc.sinica.edu.tw/" target="_blank" rel="noopener noreferrer"> 37 <img class="brand-logo" src="/auth-assets-7q2k9x4m/logo-ascdc.png" alt=""> 38 <span class="brand-name" data-i18n="brand">Academia Sinica Center for Digital Cultures</span> 39 </a> 40 <div class="controls"> 41 <div class="lang-switch"><select id="langSelect" aria-label="Language"></select></div> 42 <button class="theme-toggle" id="themeToggle" type="button" aria-label="Toggle theme"> 43 <svg class="i-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.8A9 9 0 1111.2 3 7 7 0 0021 12.8z"/></svg> 44 <svg class="i-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2M5 5l1.5 1.5M17.5 17.5L19 19M19 5l-1.5 1.5M6.5 17.5L5 19"/></svg> 45 </button> 46 </div> 47 </header> 48 49 <main class="scene"> 50 <aside class="scene-brand" aria-hidden="true"> 51 <img class="scene-logo" src="/auth-assets-7q2k9x4m/logo-ascdc.png" alt=""> 52 <div class="scene-id"><span class="scene-name" data-i18n="brand">Academia Sinica Center for Digital Cultures</span><span class="scene-tag" data-i18n="org">Academia Sinica</span></div> 53 <div class="scene-art" aria-hidden="true"></div> 54 </aside> 55 <div class="scene-main"> 56 <section class="card"> 57 <img class="card-logo" src="/auth-assets-7q2k9x4m/logo-ascdc.png" alt=""> 58 <h1 class="card-title" data-i18n="login_title">Identity Verification</h1> 59 <p class="card-desc" data-i18n="login_desc">Please sign in to continue to the page you requested.</p> 60 61 <form action="" method="post" autocomplete="off" novalidate> 62 <input type="hidden" name="token" value="17406a004ba69562a15d21907ae8f6e2708d6b18443722848215d2706d663c19"> 63 64 <div class="alert" role="alert"> 65 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v6M12 16.5v.5"/></svg> 66 <span class="alert-msg"></span> 67 </div> 68 <div class="captcha-zone"> 69 <div class="g-recaptcha" data-sitekey="6Ld8ibYUAAAAAHM8poK5jPvY897LD_aSja2xrtz-" data-callback="__cdRcSolved" data-expired-callback="__cdRcExpired"></div> 70 <!-- Tessera:$tesseraPrimary æç´æ¥é¡¯ç¤º;å¦åé è¨é±è,boot.js å¨ reCAPTCHA è¼å ¥å¤±æ(auto)/使ç¨è æå(manual)æåæãproof é¨è¡¨å® POSTã --> 71 <tessera-widget class="tsr-hidden" lang="en" challenge="{"ticket":"eyJkaWZmaWN1bHR5IjoxOCwiZXhwaXJlc19hdCI6MTc5MDkzNzIxNiwiaXBfcHJlZml4X2hpbnQiOiI4MS4xNi4zLjAvMjQiLCJpc3N1ZWRfYXQiOjE3OTA5MzcwMzYsInJhbmRvbV9zZWVkIjoiYzk4NDUwNTMzODg5ZmZkNTgwMjNkZjI4Y2M3YTNmZWYiLCJzY29wZSI6Ii92YWxpZFVzZXIiLCJ0aWNrZXRfaWQiOiJLNDdyRXZTdENBWFJxbTlZdkNYbWx3IiwidWFfaGFzaCI6Im5vbmUiLCJ2ZXJzaW9uIjoxfQ.Zo3RuYbenBjY98xRC8VqIuTfZyce20-atktYmp1dp8Q","payload":{"version":1,"ticket_id":"K47rEvStCAXRqm9YvCXmlw","issued_at":1790937036,"expires_at":1790937216,"scope":"/validUser","difficulty":18,"random_seed":"c98450533889ffd58023df28cc7a3fef","ip_prefix_hint":"81.16.3.0/24","ua_hash":"none"}}" challenge-url="/validUser?from=/" field-prefix="tessera"></tessera-widget> 72 <!-- 忏ç°(å·¦)èåææç¤º/ååé(å³)ä½µæåä¸å,çåç´ç©ºéãcd-row ä»»ä½ captcha é é½å¨;cap-switch å Tessera å¯ç¨æã --> 73 <div class="cap-bar"> 74 <div class="cd-row" hidden> 75 <div class="cd-ring-wrap" tabindex="0" role="timer" aria-live="off" aria-label="" aria-describedby="cd-tip"> 76 <svg viewBox="0 0 42 42" width="42" height="42" aria-hidden="true"> 77 <circle cx="21" cy="21" r="18" fill="none" stroke="rgba(128,128,128,.25)" stroke-width="3.5"></circle> 78 <circle class="cd-arc" cx="21" cy="21" r="18" fill="none" stroke="#1D9E75" stroke-width="3.5" stroke-linecap="round" transform="rotate(-90 21 21)" stroke-dasharray="113.1" stroke-dashoffset="0"></circle> 79 </svg> 80 <span class="cd-num">--:--</span> 81 </div> 82 <span class="cd-state"></span> 83 <span class="cd-tip" id="cd-tip" role="tooltip">How long the current verification stays valid. If it expires, refresh the page to verify again â your account name is kept.</span> 84 </div> 85 <div class="cap-switch"> 86 <!-- primary ä¸é¡¯ç¤º;fallback é è¨é±è,åææ boot.js ä¾ auto/manual å data-* æåå¾é¡¯ç¤ºã --> 87 <p class="cap-fallback-note tsr-hidden" data-auto="The CAPTCHA couldnât load, so we switched to built-in verification." data-manual="Switched to built-in verification.">The CAPTCHA couldnât load, so we switched to built-in verification.</p> 88 <a href="#" class="cap-toggle tsr-hidden">Use built-in verification</a> 89 <!-- åå Google reCAPTCHA:å æååå° Tessera å¾é¡¯ç¤º(auto 失æä¸æä¾)ã --> 90 <a href="#" class="cap-back tsr-hidden">Switch back to Google reCAPTCHA</a> 91 </div> 92 </div> 93 <!-- é£çºé©è失æ(>=2 次)æé¡¯ç¤ºçæ±å©é£çµ;å°åè¯çµ¡æåã --> 94 <a class="cap-help tsr-hidden" data-link="contact" href="https://ascdc.sinica.edu.tw/contact" target="_blank" rel="noopener noreferrer">Still canât verify? Contact us</a> 95 </div> 96 97 <button class="btn btn-primary" type="submit"> 98 <span class="label" data-i18n="btn_continue">Continue</span> 99 </button> 100 </form>
101 <div class="cd-expired tsr-hidden" role="status" aria-live="polite"> 102 <div class="cd-ring-wrap"> 103 <svg viewBox="0 0 42 42" width="50" height="50" aria-hidden="true"> 104 <circle cx="21" cy="21" r="18" fill="none" stroke="rgba(128,128,128,.25)" stroke-width="3.5"></circle> 105 <circle cx="21" cy="21" r="18" fill="none" stroke="#E24B4A" stroke-width="3.5" stroke-linecap="round" transform="rotate(-90 21 21)" stroke-dasharray="113.1" stroke-dashoffset="113.1"></circle> 106 </svg> 107 <span class="cd-num"> 108 <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="#E24B4A" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="9"></circle><path d="M9 9l6 6M15 9l-6 6"></path></svg> 109 </span> 110 </div> 111 <p class="card-title cd-exp-title">Verification has expired</p> 112 <p class="card-desc cd-exp-body">For your security, refresh the page to get a new verification. Your account name is kept; youâll need to re-enter your password.</p> 113 <button type="button" class="btn btn-primary cd-reload"> 114 <span class="label cd-reload-label">Refresh</span> 115 </button> 116 </div> 117 </section> 118 119 <footer class="footer"> 120 <div class="links"> 121 <a data-link="about" href="https://ascdc.sinica.edu.tw/about" target="_blank" rel="noopener noreferrer" data-i18n="nav_about">About</a> 122 <a data-link="contact" href="https://ascdc.sinica.edu.tw/contact" target="_blank" rel="noopener noreferrer" data-i18n="nav_contact">Contact</a> 123 </div> 124 <!-- è±æ brand æ¬èº«å³å ¨ç¨±(å« Academia Sinica),ç¨ brand é¿å ãæ©æ§ Â· ãæå稱åå;å ¶é¤èªè¨æ©æ§èä¸å¿æ¯åéçèª,ç¨ tagline ä¿çãæ©æ§ Â· ä¸å¿ããèªè¨åææéè¼,æ ä¾ $uiLang åæµæ£ç¢ºã --> 125 <div class="copyright">© 2026 <span data-i18n="brand">Academia Sinica Center for Digital Cultures</span>. <span data-i18n="footer_rights">All rights reserved.</span></div> 126 </footer> 127 </div> 128 </main> 129 130
130<script src="/auth-assets-7q2k9x4m/showcase.js"></script>
130 131
131<script src="/auth-assets-7q2k9x4m/fonts.js"></script>
131 132
132<script src="/auth-assets-7q2k9x4m/auth.js"></script>
132 133 <!-- Tessera fallback widget + boot:åºå®èµ° /next.php?tessera=â¦(åæº,CSP script-src 'self' æ¾è¡)ã 134 ç¨ /next.php çµå°è·¯å¾ â ä¸è«æ¬é URL æ¯ /validUser æ /next.php é½è¼å¾å° 135 (/validUser?tessera=⦠ä¸è¢« HAProxy ç ?from= rewrite èç,æ 404)ã --> 136
136<script nonce="OEJNNdEDZn0oGoyYA3Jbug">/* Tessera widget â èªå« drop-in ç(ç± widget/build.mjs çµè£,è«å¿ææ¹)ã 137 ASCDC ååµããæä¸æ¯æ©å¨äººãPoW 人æ©é©è,WCAG 2.2 AA + i18nã 138 注æ:é è¨ç¨ Blob Worker æ±è§£,CSP éå 許 worker-src 'self' blob:; 139 è¥ CSP å 'self',è«ä»¥ <tessera-widget worker-src="/path/tessera-worker.js"> æå®å¤é¨ workerã */ 140/* Tessera â ç´ JS SHA-256(忥)ãæ¼ç®æ³çºæ¨æº SHA-256(NIST FIPS 180-4,å ¬æé å);æ¤çº ASCDC èªæå¯¦ä½(é宣稱æ¼ç®æ³ååµ)ã 141 ç¨é:ç¶çè¦½å¨ WebCrypto `crypto.subtle` ä¸å¯ç¨æ(éå®å ¨å §å®¹,ä¾å¦ç´ HTTPãé localhost) 142 ä»è½ç® PoW éæ¹ â widget å¨ä»»ä½æ å¢é½è½é©è,䏿å ãéå®å ¨å §å®¹ãè失æã 143 æ¨æº SHA-256:輸åºè WebCrypto / PHP hash('sha256',â¦,true) / å¾ç«¯éä½å çµä¸è´(已尿é©è)ã 144 æ¥åå串(UTF-8 編碼)æ Uint8Array,åå³ 32-byte Uint8Arrayã */ 145(function (global) { 146 'use strict'; 147 var K = new Int32Array([ 148 0x428a2f98|0,0x71374491|0,0xb5c0fbcf|0,0xe9b5dba5|0,0x3956c25b|0,0x59f111f1|0,0x923f82a4|0,0xab1c5ed5|0, 149 0xd807aa98|0,0x12835b01|0,0x243185be|0,0x550c7dc3|0,0x72be5d74|0,0x80deb1fe|0,0x9bdc06a7|0,0xc19bf174|0, 150 0xe49b69c1|0,0xefbe4786|0,0x0fc19dc6|0,0x240ca1cc|0,0x2de92c6f|0,0x4a7484aa|0,0x5cb0a9dc|0,0x76f988da|0, 151 0x983e5152|0,0xa831c66d|0,0xb00327c8|0,0xbf597fc7|0,0xc6e00bf3|0,0xd5a79147|0,0x06ca6351|0,0x14292967|0, 152 0x27b70a85|0,0x2e1b2138|0,0x4d2c6dfc|0,0x53380d13|0,0x650a7354|0,0x766a0abb|0,0x81c2c92e|0,0x92722c85|0, 153 0xa2bfe8a1|0,0xa81a664b|0,0xc24b8b70|0,0xc76c51a3|0,0xd192e819|0,0xd6990624|0,0xf40e3585|0,0x106aa070|0, 154 0x19a4c116|0,0x1e376c08|0,0x2748774c|0,0x34b0bcb5|0,0x391c0cb3|0,0x4ed8aa4a|0,0x5b9cca4f|0,0x682e6ff3|0, 155 0x748f82ee|0,0x78a5636f|0,0x84c87814|0,0x8cc70208|0,0x90befffa|0,0xa4506ceb|0,0xbef9a3f7|0,0xc67178f2|0 156 ]); 157 var _enc = (typeof TextEncoder !== 'undefined') ? new TextEncoder() : null; 158 function utf8(str) { 159 if (_enc) return _enc.encode(str); 160 // 徿´(ç¡ TextEncoder çèç°å¢):æå UTF-8 161 var out = [], i, c; 162 for (i = 0; i < str.length; i++) { 163 c = str.charCodeAt(i); 164 if (c < 0x80) out.push(c); 165 else if (c < 0x800) { out.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f)); } 166 else if (c < 0xd800 || c >= 0xe000) { out.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); } 167 else { i++; c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)); out.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 0x3f), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); } 168 } 169 return new Uint8Array(out); 170 } 171 function ROTR(n, x) { return (x >>> n) | (x << (32 - n)); } 172 173 function sha256(data) { 174 var msg = (typeof data === 'string') ? utf8(data) : data; 175 var len = msg.length; 176 var bitLenHi = Math.floor(len / 0x20000000); // (len*8) é« 32 bit 177 var bitLenLo = (len << 3) >>> 0; // (len*8) ä½ 32 bit 178 var withOne = len + 1; 179 var pad = (56 - (withOne % 64) + 64) % 64; 180 var total = withOne + pad + 8; 181 var m = new Uint8Array(total); 182 m.set(msg); 183 m[len] = 0x80; 184 m[total - 8] = (bitLenHi >>> 24) & 0xff; m[total - 7] = (bitLenHi >>> 16) & 0xff; 185 m[total - 6] = (bitLenHi >>> 8) & 0xff; m[total - 5] = bitLenHi & 0xff; 186 m[total - 4] = (bitLenLo >>> 24) & 0xff; m[total - 3] = (bitLenLo >>> 16) & 0xff; 187 m[total - 2] = (bitLenLo >>> 8) & 0xff; m[total - 1] = bitLenLo & 0xff; 188 189 var H0 = 0x6a09e667|0, H1 = 0xbb67ae85|0, H2 = 0x3c6ef372|0, H3 = 0xa54ff53a|0, 190 H4 = 0x510e527f|0, H5 = 0x9b05688c|0, H6 = 0x1f83d9ab|0, H7 = 0x5be0cd19|0; 191 var w = new Int32Array(64), off, i; 192 for (off = 0; off < total; off += 64) { 193 for (i = 0; i < 16; i++) { 194 w[i] = (m[off + i*4] << 24) | (m[off + i*4 + 1] << 16) | (m[off + i*4 + 2] << 8) | (m[off + i*4 + 3]); 195 } 196 for (i = 16; i < 64; i++) { 197 var x15 = w[i-15], x2 = w[i-2]; 198 var s0 = ROTR(7, x15) ^ ROTR(18, x15) ^ (x15 >>> 3); 199 var s1 = ROTR(17, x2) ^ ROTR(19, x2) ^ (x2 >>> 10); 200 w[i] = (w[i-16] + s0 + w[i-7] + s1) | 0; 201 } 202 var a=H0,b=H1,c=H2,d=H3,e=H4,f=H5,g=H6,h=H7; 203 for (i = 0; i < 64; i++) { 204 var S1 = ROTR(6, e) ^ ROTR(11, e) ^ ROTR(25, e); 205 var ch = (e & f) ^ (~e & g); 206 var t1 = (h + S1 + ch + K[i] + w[i]) | 0; 207 var S0 = ROTR(2, a) ^ ROTR(13, a) ^ ROTR(22, a); 208 var maj = (a & b) ^ (a & c) ^ (b & c); 209 var t2 = (S0 + maj) | 0; 210 h=g; g=f; f=e; e=(d + t1)|0; d=c; c=b; b=a; a=(t1 + t2)|0; 211 } 212 H0=(H0+a)|0; H1=(H1+b)|0; H2=(H2+c)|0; H3=(H3+d)|0;
212 H4=(H4+e)|0; H5=(H5+f)|0; H6=(H6+g)|0; H7=(H7+h)|0; 213 } 214 var Hs = [H0,H1,H2,H3,H4,H5,H6,H7], out = new Uint8Array(32); 215 for (i = 0; i < 8; i++) { 216 out[i*4] = (Hs[i] >>> 24) & 0xff; out[i*4+1] = (Hs[i] >>> 16) & 0xff; 217 out[i*4+2] = (Hs[i] >>> 8) & 0xff; out[i*4+3] = Hs[i] & 0xff; 218 } 219 return out; 220 } 221 222 global.tesseraSha256 = sha256; 223 if (typeof module !== 'undefined' && module.exports) module.exports = sha256; 224})(typeof self !== 'undefined' ? self : typeof globalThis !== 'undefined' ? globalThis : this); 225 226/* ============================================================================= 227 * Tessera widget â <tessera-widget> èªè¨å ä»¶(Web Component) 228 * ASCDC ååµããæä¸æ¯æ©å¨äººã人æ©é©è UI;æ¯ reCAPTCHA/ALTCHA æ´ç²¾ç·»,WCAG 2.2 AA + i18nã 229 * 230 * æ¤æªæ¯ãå ä»¶é輯åå§ç¢¼ããbuild.mjs ææä¸åä½ä½ç¬¦ææå §åµè³ç¢, 231 * ç¢åºèªå«ãé¶é¡å¤è«æ±ãå¯å®æª drop-in ç widget/tessera.js: 232 * '__TESSERA_CSS__' â tessera.css å ¨æ(å串) 233 * __TESSERA_I18N__ â i18n.json ç©ä»¶ 234 * '__TESSERA_WORKER_SRC__' â vendored miner + worker åä½µåå§ç¢¼(å串,ä¾ Blob Worker) 235 * 236 * è¨è¨è¦é»: 237 * - Shadow DOM å°è£æ¨£å¼;hidden æ¬ä½å¯«å¨ light DOM(ææé¨è¡¨å®éåº)ã 238 * - role="checkbox" + éµç¤æä½ + aria-live çæ (WCAG 4.1.2 / 2.1.1 / 4.1.3)ã 239 * - æ±è§£åªå ç¨ Worker(ä¸å¡ UI);Worker ä¸å¯ç¨æ fallback 主å·è¡ç·å塿±è§£ã 240 * - å¾ç«¯å¯ä¸å¯ä¿¡:widget åªè² è²¬æ± nonce + 帶å ticket/nonce,ééç±å¾ç«¯æ¸å¸é©èã 241 * ===========================================================================*/ 242(function () { 243 'use strict'; 244 245 if (typeof window === 'undefined' || !window.customElements) return; 246 if (customElements.get('tessera-widget')) return; 247 248 var CSS = "/* =============================================================================\n * Tessera widget æ¨£å¼ â ãæä¸æ¯æ©å¨äººã人æ©é©è\n * ASCDC ååµãè¨è¨ç®æ¨:æ¯ reCAPTCHA / ALTCHA æ´ç²¾ç·»,ä¸ç¬¦å WCAG 2.2 AAã\n *\n * ç¡éç¤éé»:\n * - å°æ¯:æå/éæ¡ ⥠4.5:1ã⥠3:1(éæå),深淺è²é½éæ¨ã\n * - ç¦é»::focus-visible æ 2px é«å°æ¯å¤æ¡(1.4.11 / 2.4.7 / 2.4.13)ã\n * - ç®æ¨å¤§å°:å¯é»å ⥠24Ã24 CSS px(2.5.8 Target Size Minimum)ã\n * - åæ å好:prefers-reduced-motion ééæè½/ä½ç§»åç«(2.3.3)ã\n * - 主é¡:prefers-color-scheme + [data-theme] è¦å¯«;RTL ç± :host([dir=rtl])ã\n *\n * é份 CSS æ¯ã樣å¼å¯ä¸ç坦便ºã;tessera.js å §åµåä¸ä»½å串以便é¶é¡å¤è«æ± drop-inã\n * æ¹æ¨£å¼è«æ¹é裡,åç¨ build 忥(æç´æ¥è¦å¯« CSS è®æ¸å®¢è£½ä¸»é¡)ã\n * ===========================================================================*/\n\n:host,\n.tessera-scope {\n /* ---- å¯å®¢è£½ä¸»é¡è®æ¸(è¦å¯«éäºå³å¯æ¹è²,ä¸å¿ åçµæ§)---- */\n --tsr-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans TC\",\n \"Microsoft JhengHei\", Roboto, Helvetica, Arial, sans-serif;\n --tsr-radius: 14px;\n --tsr-bg: #ffffff;\n --tsr-bg-2: #f7f8fa;\n --tsr-fg: #1d2433; /* 主æå,å°ç½åº > 12:1 */\n --tsr-fg-muted: #5b6472; /* 次æå,å°ç½åº ⥠4.6:1 */\n --tsr-border: #c7cdd6; /* éæ¡,å°ç½åº ⥠3:1 */\n --tsr-accent: #4f46e5; /* 主è²(é)*/\n --tsr-accent-2: #06b6d4; /* 漸層å¯è²(é)*/\n --tsr-accent-fg: #ffffff;\n --tsr-success: #0f9d6b; /* æåç¶ ,å°ç½åº ⥠3.3:1 */\n --tsr-danger: #d23b3b; /* 失æç´ ,å°ç½åº ⥠4.5:1 */\n --tsr-focus: #2563eb;\n --tsr-shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 6px 20px rgba(16, 24, 40, .08);\n --tsr-shadow-hover: 0 2px 4px rgba(16, 24, 40, .08), 0 12px 32px rgba(16, 24, 40, .14);\n\n display: inline-block;\n font-family: var(--tsr-font);\n -webkit-font-smoothing: antialiased;\n text-rendering: optimizeLegibility;\n line-height: 1.4;\n}\n\n/* ---- æ·±è²:è·é¨ç³»çµ±,æç± [data-theme=\"dark\"] å¼·å¶ ---- */\n@media (prefers-color-scheme: dark) {\n :host(:not([theme=\"light\"])),\n .tessera-scope:not([data-theme=\"light\"]) {\n --tsr-bg: #181b22;\n --tsr-bg-2: #20242d;\n --tsr-fg: #f1f3f7;\n --tsr-fg-muted: #aab2c0; /* å°æ·±åº ⥠4.7:1 */\n --tsr-border: #3a4150; /* å°æ·±åº ⥠3:1 */\n --tsr-accent: #8b8bff;\n --tsr-accent-2: #2dd4bf;\n --tsr-success: #34d399;\n --tsr-danger: #f87171;\n --tsr-focus: #93c5fd;\n --tsr-shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 6px 20px rgba(0, 0, 0, .5);\n --tsr-shadow-hover: 0 2px 6px rgba(0, 0, 0, .5), 0 14px 36px rgba(0, 0, 0, .6);\n }\n}\n:host([theme=\"dark\"]),\n.tessera-scope[data-theme=\"dark\"] {\n --tsr-bg: #181b22;\n --tsr-bg-2: #20242d;\n --tsr-fg: #f1f3f7;\n --tsr-fg-muted: #aab2c0;\n --tsr-border: #3a4150;\n --tsr-accent: #8b8bff;\n --tsr-accent-2: #2dd4bf;\n --tsr-success: #34d399;\n --tsr-danger: #f87171;\n --tsr-focus: #93c5fd;\n --tsr-shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 6px 20px rgba(0, 0, 0, .5);\n --tsr-shadow-hover: 0 2px 6px rgba(0, 0, 0, .5), 0 14px 36px rgba(0, 0, 0, .6);\n}\n\n* { box-sizing: border-box; }\n\n/* ---- 夿¡å¡ç ---- */\n.tsr {\n position: relative;\n display: flex;\n align-items: center;\n gap: 13px;\n width: 300px;\n max-width: 100%;\n min-height: 74px;\n padding: 14px 16px;\n background: var(--tsr-bg);\n border: 1px solid var(--tsr-border);\n border-radius: var(--tsr-radius);\n box-shadow: var(--tsr-shadow);\n color: var(--tsr-fg);\n cursor: pointer;\n overflow: hidden;\n transition: box-shadow .25s ease, border-color .25s ease, transform .15s ease;\n -webkit-tap-highlight-color: transparent;\n}\n.tsr:hover { box-shadow: var(--tsr-shadow-hover); }\n.tsr:active { transform: translateY(1px); }\n.tsr[aria-disabled=\"true\"] { cursor: default; opacity: .8; }\n\n/* é 緣漸層細æ¢(åå³ç´°ç¯,éè³è¨è¼é«) */\n.tsr::before {\n content: \"\";\n position: absolute; inset: 0 0 auto 0;\n height: 3px;\n background: linear-gradient(90deg, var(--tsr-accent), var(--tsr-accent-2));\n opacity: .9;\n transform: scaleX(0);\n transform-origin: left;\n transition: transform .5s ease;\n}\n.tsr[data-state=\"solving\"]::before,\n.tsr[data-state=\"verifying\"]::before { transform: scaleX(1); }\n.tsr[data-state=\"success\"]::before {\n transform: scaleX(1);\n background: var(--tsr-success);\n}\n\n/* ---- ç¦é»å¤æ¡(WCAG 2.4.7 / 2.4.13)---- */\n.tsr:focus-visible {\n outline: 3px solid var(--tsr-focus);\n outline-offset: 2px;\n}\n/* èç覽å¨å¾æ´ */\n.tsr.tsr-focus { outline: 3px solid var(--tsr-focus); outline-offset: 2px; }\n\n/* ---- å·¦å´å¾é¸æ¹å¡(åææ¯ spinner / å¾ / å ç容å¨)---- */\n.tsr-box {\n position: relative;\n flex: 0 0 auto;\n width: 28px; height: 28px; /* ç®æ¨ ⥠24px(2.5.8)*/\n border: 2px solid var(--tsr-border);\n border-radius: 7px;\n background: var(--tsr-bg-2);\n transition: border-color .2s ease, background .2s ease;\n}\n.tsr:hover .tsr-box { border-color: var(--tsr-accent); }\n\n/* å¾(SVG path ç¨ stroke-dashoffset ç«åºä¾)*/\n.tsr-check {\n position: absolute; inset: 0;\n width: 100%; height: 100%;\n stroke: var(--tsr-accent-fg);\n stroke-width: 3.5;\n stroke-linecap: round;\n stroke-linejoin: round;\n fill: none;\n opacity: 0;\n transform: scale(.5);\n transition: opacity .2s ease, transform .2s ease;\n}\n.tsr-check path {\n stroke-dasharray: 24;\n stroke-dashoffset: 24;\n}\n\n/* spinner */\n.tsr-spinner {\n position: absolute; inset: 50% auto auto 50%;\n width: 18px; height: 18px;\n margin: -9px 0 0 -9px;\n border: 2.5px solid color-mix(in srgb, var(--tsr-accent) 25%, transparent);\n border-top-color: var(--tsr-accent);\n border-radius: 50%;\n opacity: 0;\n animation: tsr-spin .8s linear infinite;\n}\n/* 䏿¯æ´ color-mix ç徿´ */\n@supports not (color: color-mix(in srgb, red, blue)) {\n .tsr-spinner { border-color: rgba(120,120,160,.3); border-top-color: var(--tsr-accent); }\n}\n\n/* å(失æ)*/\n.tsr-cross {\n position: absolute; inset: 0;\n width: 100%; height: 100%;\n stroke: var(--tsr-accent-fg);\n stroke-width: 3.5; stroke-linecap: round;\n fill: none; opacity: 0; transform: scale(.5);\n transition: opacity .2s ease, transform .2s ease;\n}\n\n/* ---- åçæ ä¸æ¹å¡çåç¾ ---- */\n.tsr[data-state=\"solving\"] .tsr-box,\n.tsr[data-state=\"verifying\"] .tsr-box { border-color: var(--tsr-accent); background: transparent; }\n.tsr[data-state=\"solving\"] .tsr-spinner,\n.tsr[data-state=\"verifying\"] .tsr-spinner { opacity: 1; }\n\n.tsr[data-state=\"success\"] .tsr-box {\n border-color: var(--tsr-success);\n background: var(--tsr-success);\n}\n.tsr[data-state=\"success\"] .tsr-check {\n opacity: 1; transform: scale(1);\n}\n/* åç«æå¨ path(stroke-dashoffset å¨ path ä¸);æå¨ .tsr-check(svg)ç¡æ â å¾ç«ä¸åºä¾ */\n.tsr[data-state=\"success\"] .tsr-check path {\n animation: tsr-draw .45s ease forwards .05s;\n}\n\n.tsr[data-state=\"error\"] .tsr-box,\n.tsr[data-state=\"expired\"] .tsr-box {\n border-color: var(--tsr-danger);\n background: var(--tsr-danger);\n}\n.tsr[data-state=\"error\"] .tsr-cross,\n.tsr[data-state=\"expired\"] .tsr-cross { opacity: 1; transform: scale(1); }\n\n/* ---- ä¸éæå ---- */\n.tsr-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }\n.tsr-label {\n font-size: 15px;\n font-weight: 600;\n color: var(--tsr-fg);\n letter-spacing: .01em;\n}\n.tsr-status {\n margin-top: 2px;\n font-size: 12.5px;\n color: var(--tsr-fg-muted);\n min-height: 1.2em;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.tsr[data-state=\"success\"] .tsr-status { color: var(--tsr-success); font-weight: 600; }\n.tsr[data-state=\"error\"] .tsr-status,\n.tsr[data-state=\"expired\"] .tsr-status { color: var(--tsr-danger); font-weight: 600; }\n\n/* ---- å³å´åçæ¨è¨ ---- */\n.tsr-brand {\n flex: 0 0 auto;\n display: flex; flex-direction: column; align-items: center; gap: 2px;\n opacity: .85;\n user-select: none;\n}\n.tsr-mark {\n width: 26px;
248 height: 26px;\n display: block;\n}\n.tsr-mark .tsr-tile { transition: opacity .3s ease, transform .3s ease; transform-origin: center; }\n.tsr[data-state=\"solving\"] .tsr-mark .tsr-tile,\n.tsr[data-state=\"verifying\"] .tsr-mark .tsr-tile { animation: tsr-pulse 1.4s ease-in-out infinite; }\n.tsr-mark .tsr-tile:nth-child(2) { animation-delay: .15s; }\n.tsr-mark .tsr-tile:nth-child(3) { animation-delay: .3s; }\n.tsr-mark .tsr-tile:nth-child(4) { animation-delay: .45s; }\n.tsr-brand-text {\n font-size: 9px; font-weight: 700; letter-spacing: .06em;\n color: var(--tsr-fg-muted); text-transform: uppercase;\n}\n\n/* ---- åºé¨é²åº¦æ¢(åªå¨æ±è§£æåºç¾)---- */\n.tsr-progress {\n position: absolute; left: 0; right: 0; bottom: 0;\n height: 3px;\n background: transparent;\n overflow: hidden;\n opacity: 0;\n transition: opacity .2s ease;\n}\n.tsr[data-state=\"solving\"] .tsr-progress,\n.tsr[data-state=\"verifying\"] .tsr-progress { opacity: 1; }\n.tsr-bar {\n height: 100%;\n width: 30%;\n background: linear-gradient(90deg, var(--tsr-accent), var(--tsr-accent-2));\n border-radius: 3px;\n /* æ±è§£é²åº¦æªç¥æèµ° indeterminate ä¾åæå;æ % æåæ determinate(JS è¨ width)*/\n}\n.tsr-progress[data-mode=\"indeterminate\"] .tsr-bar {\n width: 35%;\n animation: tsr-sweep 1.3s ease-in-out infinite;\n}\n.tsr-progress[data-mode=\"determinate\"] .tsr-bar {\n transition: width .25s ease;\n}\n\n/* RTL:é¿æä¼¯èªç,æ°´å¹³é¡å */\n:host([dir=\"rtl\"]) .tsr,\n.tessera-scope[dir=\"rtl\"] .tsr { direction: rtl; }\n\n/* ---- åç« ---- */\n@keyframes tsr-spin { to { transform: rotate(360deg); } }\n@keyframes tsr-draw { to { stroke-dashoffset: 0; } }\n@keyframes tsr-sweep {\n 0% { transform: translateX(-120%); }\n 100% { transform: translateX(420%); }\n}\n@keyframes tsr-pulse {\n 0%, 100% { opacity: .35; transform: scale(.9); }\n 50% { opacity: 1; transform: scale(1.05); }\n}\n\n/* WCAG 2.3.3:å°éãæ¸å°åæ ææãå好 ââ éæææéå¿ è¦åç« */\n@media (prefers-reduced-motion: reduce) {\n .tsr,\n .tsr *,\n .tsr-check,\n .tsr-spinner,\n .tsr-bar,\n .tsr-mark .tsr-tile {\n animation: none !important;\n transition: none !important;\n }\n .tsr[data-state=\"success\"] .tsr-check path { stroke-dashoffset: 0; }\n /* æ±è§£æç¨éæ èåæ¿ä»£æå,仿ä¾ãé²è¡ä¸ãåé¥ä½ä¸ä½ç§» */\n .tsr-progress[data-mode=\"indeterminate\"] .tsr-bar { width: 100%; opacity: .6; }\n}\n\n/* é«å°æ¯æ¨¡å¼:å¼·å¶å¯è¦éç */\n@media (forced-colors: active) {\n .tsr { border: 1px solid CanvasText; }\n .tsr-box { border: 2px solid CanvasText; }\n .tsr:focus-visible { outline: 3px solid Highlight; }\n}\n"; 249 var I18N = {"_rtl":["ar","he","fa","ur"],"_fallback":"en","en":{"label":"I'm not a robot","aria_checkbox":"Verify that you are human","status_idle":"Click to verify","status_start":"Preparing verificationâ¦","status_solving":"Verifying, please waitâ¦","status_verifying":"Confirmingâ¦","status_success":"Verified","status_error":"Verification failed â try again","status_expired":"Verification timed out â try again","status_offline":"Connection problem â try again","retry":"Try again","brand_title":"Fallback verification mode by ASCDC","progress_label":"Verification progress"},"zh-Hant":{"label":"æä¸æ¯æ©å¨äºº","aria_checkbox":"è«ç¢ºèªæ¨ä¸æ¯æ©å¨äºº","status_idle":"é»é¸ä»¥éå§é©è","status_start":"æ£å¨æºåé©èâ¦","status_solving":"é©èä¸,è«ç¨åâ¦","status_verifying":"æ£å¨ç¢ºèªâ¦","status_success":"é©èéé","status_error":"é©è失æ,è«é試","status_expired":"é©è已龿,è«é試","status_offline":"é£ç·ç¼çåé¡,è«é試","retry":"é試","brand_title":"ç± ASCDC æä¾çåç¨é©è模å¼","progress_label":"é©èé²åº¦"},"zh-Hans":{"label":"æä¸æ¯æºå¨äºº","aria_checkbox":"请确认æ¨ä¸æ¯æºå¨äºº","status_idle":"ç¹å»ä»¥å¼å§éªè¯","status_start":"æ£å¨åå¤éªè¯â¦","status_solving":"æ£å¨éªè¯,请ç¨åâ¦","status_verifying":"æ£å¨ç¡®è®¤â¦","status_success":"éªè¯éè¿","status_error":"éªè¯å¤±è´¥,请éè¯","status_expired":"éªè¯å·²è¶ æ¶,请éè¯","status_offline":"è¿æ¥åºç°é®é¢,请éè¯","retry":"éè¯","brand_title":"ç± ASCDC æä¾çå¤ç¨éªè¯æ¨¡å¼","progress_label":"éªè¯è¿åº¦"}
249,"ja":{"label":"ç§ã¯ããããã§ã¯ããã¾ãã","aria_checkbox":"ããªãã人éã§ãããã¨ã確èªãã¾ã","status_idle":"ã¯ãªãã¯ãã¦ç¢ºèªãéå§","status_start":"確èªãæºåãã¦ãã¾ãâ¦","status_solving":"確èªä¸ã§ãããå¾ ã¡ãã ããâ¦","status_verifying":"確èªãã¦ãã¾ãâ¦","status_success":"確èªã§ãã¾ãã","status_error":"確èªã«å¤±æãã¾ãããããä¸åº¦ã試ããã ãã","status_expired":"確èªãã¿ã¤ã ã¢ã¦ããã¾ãããããä¸åº¦ã試ããã ãã","status_offline":"æ¥ç¶ã«åé¡ãããã¾ããããä¸åº¦ã試ããã ãã","retry":"å試è¡","brand_title":"ASCDC æä¾ã®äºåèªè¨¼ã¢ã¼ã","progress_label":"確èªã®é²è¡ç¶æ³"},"ko":{"label":"ì ë ë¡ë´ì´ ìëëë¤","aria_checkbox":"ì¬ëì¸ì§ íì¸í©ëë¤","status_idle":"í´ë¦íì¬ íì¸ ìì","status_start":"íì¸ì ì¤ë¹íë ì¤â¦","status_solving":"íì¸ ì¤ì ëë¤. ì ìë§ ê¸°ë¤ë ¤ 주ì¸ìâ¦","status_verifying":"íì¸íë ì¤â¦","status_success":"íì¸ë¨","status_error":"íì¸ì ì¤í¨íìµëë¤. ë¤ì ìëíì¸ì","status_expired":"íì¸ ìê°ì´ ì´ê³¼ëììµëë¤. ë¤ì ìëíì¸ì","status_offline":"ì°ê²°ì 문ì ê° ììµëë¤. ë¤ì ìëíì¸ì","retry":"ë¤ì ìë","brand_title":"ASCDC ì ê³µ ìë¹ ì¸ì¦ 모ë","progress_label":"íì¸ ì§í ìí©"},"es":{"label":"No soy un robot","aria_checkbox":"Verifica que eres humano","status_idle":"Haz clic para verificar","status_start":"Preparando la verificaciónâ¦","status_solving":"Verificando, espera un momentoâ¦","status_verifying":"Confirmandoâ¦","status_success":"Verificado","status_error":"La verificación falló: inténtalo de nuevo","status_expired":"La verificación caducó: inténtalo de nuevo","status_offline":"Problema de conexión: inténtalo de nuevo","retry":"Reintentar","brand_title":"Modo de verificación alternativo de ASCDC","progress_label":"Progreso de la verificación"},"fr":{"label":"Je ne suis pas un robot","aria_checkbox":"Vérifiez que vous êtes humain","status_idle":"Cliquez pour vérifier","status_start":"Préparation de la vérificationâ¦","status_solving":"Vérification en cours, veuillez patienterâ¦","status_verifying":"Confirmationâ¦","status_success":"Vérifié","status_error":"Ãchec de la vérification â réessayez","status_expired":"Vérification expirée â réessayez","status_offline":"Problème de connexion â réessayez","retry":"Réessayer","brand_title":"Mode de vérification de secours par ASCDC","progress_label":"Progression de la vérification"},"de":{"label":"Ich bin kein Roboter","aria_checkbox":"Bestätigen Sie, dass Sie ein Mensch sind","status_idle":"Zum Verifizieren klicken","status_start":"Ãberprüfung wird vorbereitetâ¦","status_solving":"Ãberprüfung läuft, bitte wartenâ¦","status_verifying":"Wird bestätigtâ¦","status_success":"Bestätigt","status_error":"Ãberprüfung fehlgeschlagen â erneut versuchen","status_expired":"Ãberprüfung abgelaufen â erneut versuchen","status_offline":"Verbindungsproblem â erneut versuchen","retry":"Erneut versuchen","brand_title":"Ersatz-Verifizierungsmodus von ASCDC","progress_label":"Fortschritt der Ãberprüfung"},"pt-BR":{"label":"Não sou um robô","aria_checkbox":"Confirme que você é humano","status_idle":"Clique para verificar","status_start":"Preparando a verificaçãoâ¦","status_solving":"Verificando, aguardeâ¦","status_verifying":"Confirmandoâ¦","status_success":"Verificado","status_error":"Falha na verificação â tente novamente","status_expired":"A verificação expirou â tente novamente","status_offline":"Problema de conexão â tente novamente","retry":"Tentar novamente","brand_title":"Modo de verificação alternativo da ASCDC","progress_label":"Progresso da verificação"},"ru":{"label":"Я не ÑобоÑ","aria_checkbox":"ÐодÑвеÑдиÑе, ÑÑо Ð²Ñ Ñеловек","status_idle":"ÐажмиÑе Ð´Ð»Ñ Ð¿ÑовеÑки","status_start":"ÐодгоÑовка пÑовеÑкиâ¦","status_solving":"ÐдÑÑ Ð¿ÑовеÑка, подождиÑеâ¦","status_verifying":"ÐодÑвеÑждениеâ¦","status_success":"ÐÑовеÑено","status_error":"ÐÑовеÑка не ÑдалаÑÑ â повÑоÑиÑе","status_expired":"ÐÑÐµÐ¼Ñ Ð¿ÑовеÑки иÑÑекло â повÑоÑиÑе","status_offline":"ÐÑоблема Ñ Ð¿Ð¾Ð´ÐºÐ»ÑÑением â повÑоÑиÑе","retry":"ÐовÑоÑиÑÑ","brand_title":"РезеÑвнÑй Ñежим пÑовеÑки Ð¾Ñ ASCDC","progress_label":"Ход пÑовеÑки"},"it":{"label":"Non sono un robot","aria_checkbox":"Verifica di essere umano","status_idle":"Fai clic per verificare","status_start":"Preparazione della verificaâ¦","status_solving":"Verifica in corso, attendereâ¦","status_verifying":"Conferma in corsoâ¦","status_success":"Verificato","status_error":"Verifica non riuscita â riprova","status_expired":"Verifica scaduta â riprova","status_offline":"Problema di connessione â riprova","retry":"Riprova","brand_title":"Modalità di verifica alternativa di ASCDC","progress_label":"Avanzamento della verifica"},"nl":{"label":"Ik ben geen robot","aria_checkbox":"Bevestig dat je een mens bent","status_idle":"Klik om te verifiëren","status_start":"Verificatie voorbereidenâ¦","status_solving":"Bezig met verifiëren, even geduldâ¦","status_verifying":"Bevestigenâ¦","status_success":"Geverifieerd","status_error":"Verificatie mislukt â probeer opnieuw","status_expired":"Verificatie verlopen â probeer opnieuw","status_offline":"Verbindingsprobleem â probeer opnieuw","retry":"Opnieuw proberen","brand_title":"ReserveÂverificatiemodus van ASCDC","progress_label":"Voortgang van de verificatie"},"vi":{"label":"Tôi không phải là ngưá»i máy","aria_checkbox":"Xác minh bạn là con ngưá»i","status_idle":"Nhấp Äá» xác minh","status_start":"Äang chuẩn bá» xác minhâ¦","status_solving":"Äang xác minh, vui lòng Äợiâ¦","status_verifying":"Äang xác nháºnâ¦","status_success":"Äã xác minh","status_error":"Xác minh thất bại â thá» lại","status_expired":"Xác minh Äã hết hạn â thá» lại","status_offline":"Sá»± cá» kết ná»i â thá» lại","retry":"Thá» lại","brand_title":"Chế Äá» xác minh dá»± phòng bá»i ASCDC","progress_label":"Tiến trình xác minh"},"th":{"label":"à¸à¸±à¸à¹à¸¡à¹à¹à¸à¹à¹à¸à¸£à¹à¸à¸£à¸¡à¸à¸±à¸à¹à¸à¸¡à¸±à¸à¸´","aria_checkbox":"ยืà¸à¸¢à¸±à¸à¸§à¹à¸²à¸à¸¸à¸à¹à¸à¹à¸à¸¡à¸à¸¸à¸©à¸¢à¹","status_idle":"à¸à¸¥à¸´à¸à¹à¸à¸·à¹à¸à¸¢à¸·à¸à¸¢à¸±à¸","status_start":"à¸à¸³à¸¥à¸±à¸à¹à¸à¸£à¸µà¸¢à¸¡à¸à¸²à¸£à¸¢à¸·à¸à¸¢à¸±à¸â¦","status_solving":"à¸à¸³à¸¥à¸±à¸à¸¢à¸·à¸à¸¢à¸±à¸ à¹à¸à¸£à¸à¸£à¸à¸ªà¸±à¸à¸à¸£à¸¹à¹â¦","status_verifying":"à¸à¸³à¸¥à¸±à¸à¸à¸£à¸§à¸à¸ªà¸à¸â¦","status_success":"ยืà¸à¸¢à¸±à¸à¹à¸¥à¹à¸§","status_error":"à¸à¸²à¸£à¸¢à¸·à¸à¸¢à¸±à¸à¸¥à¹à¸¡à¹à¸«à¸¥à¸§ â ลà¸à¸à¸à¸µà¸à¸à¸£à¸±à¹à¸","status_expired":"à¸à¸²à¸£à¸¢à¸·à¸à¸¢à¸±à¸à¸«à¸¡à¸à¹à¸§à¸¥à¸² â ลà¸à¸à¸à¸µà¸à¸à¸£à¸±à¹à¸","status_offline":"à¸à¸²à¸£à¹à¸à¸·à¹à¸à¸¡à¸à¹à¸à¸¡à¸µà¸à¸±à¸à¸«à¸² â ลà¸à¸à¸à¸µà¸à¸à¸£à¸±à¹à¸","retry":"ลà¸à¸à¸à¸µà¸à¸à¸£à¸±à¹à¸","brand_title":"à¹à¸«à¸¡à¸à¸à¸²à¸£à¸¢à¸·à¸à¸¢à¸±à¸à¸ªà¸³à¸£à¸à¸à¹à¸à¸¢ ASCDC","progress_label":"à¸à¸§à¸²à¸¡à¸à¸·à¸à¸«à¸à¹à¸²à¸à¸²à¸£à¸¢à¸·à¸à¸¢à¸±à¸"},"id":{"label":"Saya bukan robot","aria_checkbox":"Verifikasi bahwa Anda manusia","status_idle":"Klik untuk memverifikasi","status_start":"Menyiapkan verifikasiâ¦","status_solving":"Memverifikasi, mohon tungguâ¦","status_verifying":"Mengonfirmasiâ¦","status_success":"Terverifikasi","status_error":"Verifikasi gagal â coba lagi","status_expired":"Verifikasi kedaluwarsa â coba lagi","status_offline":"Masalah koneksi â coba lagi","retry":"Coba lagi","brand_title":"Mode verifikasi cadangan oleh ASCDC","progress_label":"Kemajuan verifikasi"},"ar":{"label":"ÙØ³Øª Ø±ÙØ¨ÙØªÙØ§","aria_checkbox":"تأÙÙÙØ¯ ٠٠أÙÙ Ø¥ÙØ³Ø§Ù","status_idle":"اÙÙØ± ÙÙØªØÙÙ","status_start":"Ø¬Ø§Ø±Ù Ø§ÙØªØØ¶Ùر ÙÙØªØÙÙâ¦","status_solving":"Ø¬Ø§Ø±Ù Ø§ÙØªØÙÙØ ÙÙØ±Ø¬Ù Ø§ÙØ§Ùتظارâ¦","status_verifying":"Ø¬Ø§Ø±Ù Ø§ÙØªØ£ÙÙØ¯â¦","status_success":"ØªÙ Ø§ÙØªØÙÙ","status_error":"ÙØ´Ù Ø§ÙØªØÙÙ â Ø£Ø¹Ø¯ اÙÙ ØØ§ÙÙØ©","status_expired":"Ø§ÙØªÙت Ù ÙÙØ© Ø§ÙØªØÙÙ â Ø£Ø¹Ø¯ اÙÙ ØØ§ÙÙØ©","status_offline":"Ù Ø´ÙÙØ© ÙÙ Ø§ÙØ§ØªØµØ§Ù â Ø£Ø¹Ø¯ اÙÙ ØØ§ÙÙØ©","retry":"إعادة اÙÙ ØØ§ÙÙØ©","brand_title":"ÙØ¶Ø¹ Ø§ÙØªØÙÙ Ø§ÙØ§ØØªÙاط٠٠٠ASCDC","progress_label":"ØªÙØ¯ÙÙ Ø§ÙØªØÙÙ"},"pt":{"label":"Não sou um robô","aria_checkbox":"Confirme que é humano","status_idle":"Clique para verificar","status_start":"A preparar a verificaçãoâ¦","status_solving":"A verificar, aguardeâ¦","status_verifying":"A confirmarâ¦","status_success":"Verificado","status_error":"A verificação falhou â tente novamente","status_expired":"A verificação expirou â tente novamente","status_offline":"Problema de ligação â tente novamente","retry":"Tentar novamente","brand_title":"Modo de verificação alternativo da ASCDC","progress_label":"Progresso da verificação"},"ms":{"label":"Saya bukan robot","aria_checkbox":"Sahkan bahawa anda manusia","status_idle":"Klik untuk mengesahkan","status_start":"Menyediakan pengesahanâ¦","status_solving":"Mengesahkan, sila tungguâ¦","status_verifying":"Mengesahkan dengan pelayanâ¦","status_success":"Disahkan","status_error":"Pengesahan gagal â cuba lagi","status_expired":"Pengesahan tamat masa â cuba lagi","status_offline":"Masalah sambungan â cuba lagi","retry":"Cuba lagi","brand_title":"Mod pengesahan sandaran oleh ASCDC","progress_label":"Kemajuan pengesahan"},"fil":{"label":"Hindi ako robot","aria_checkbox":"Patunayang ikaw ay tao","status_idle":"I-click para mag-verify","status_start":"Inihahanda ang pag-verifyâ¦","status_solving":"Nagve-verify, mangyaring maghintayâ¦","status_verifying":"Kinukumpirmaâ¦","status_success":"Na-verify","status_error":"Nabigo ang pag-verify â subukang muli","status_expired":"Nag-expire ang pag-verify â subukang muli","status_offline":"Problema sa koneksyon â subukang muli","retry":"Subukang muli","brand_title":"Backup na mode ng pag-verify ng ASCDC","progress_label":"Progreso ng pag-verify"}}; 250 var WORKER_SRC = "/* Tessera â ç´ JS SHA-256(忥)ãæ¼ç®æ³çºæ¨æº SHA-256(NIST FIPS 180-4,å ¬æé å);æ¤çº ASCDC èªæå¯¦ä½(é宣稱æ¼ç®æ³ååµ)ã\r\n ç¨é:ç¶çè¦½å¨ WebCrypto `crypto.subtle` ä¸å¯ç¨æ(éå®å ¨å §å®¹,ä¾å¦ç´ HTTPãé localhost)\r\n ä»è½ç® PoW éæ¹ â widget å¨ä»»ä½æ å¢é½è½é©è,䏿å ãéå®å ¨å §å®¹ãè失æã\r\n æ¨æº SHA-256:輸åºè WebCrypto / PHP hash('sha256',â¦,true) / å¾ç«¯éä½å çµä¸è´(已尿é©è)ã\r\n æ¥åå串(UTF-8 編碼)æ Uint8Array,åå³ 32-byte Uint8Arrayã */\r\n(function (global) {\r\n 'use strict';\r\n var K = new Int32Array([\r\n 0x428a2f98|0,0x71374491|0,0xb5c0fbcf|0,0xe9b5dba5|0,0x3956c25b|0,0x59f111f1|0,0x923f82a4|0,0xab1c5ed5|0,\r\n 0xd807aa98|0,0x12835b01|0,0x243185be|0,0x550c7dc3|0,0x72be5d74|0,0x80deb1fe|0,0x9bdc06a7|0,0xc19bf174|0,\r\n 0xe49b69c1|0,0xefbe4786|0,0x0fc19dc6|0,0x240ca1cc|0,0x2de92c6f|0,0x4a7484aa|0,0x5cb0a9dc|0,0x76f988da|0,\r\n 0x983e5152|0,0xa831c66d|0,0xb00327c8|0,0xbf597fc7|0,0xc6e00bf3|0,0xd5a79147|0,0x06ca6351|0,0x14292967|0,\r\n 0x27b70a85|0,0x2e1b2138|0,0x4d2c6dfc|0,0x53380d13|0,0x650a7354|0,0x766a0abb|0,0x81c2c92e|0,0x92722c85|0,\r\n 0xa2bfe8a1|0,0xa81a664b|0,0xc24b8b70|0,0xc76c51a3|0,0xd192e819|0,0xd6990624|0,0xf40e3585|0,0x106aa070|0,\r\n 0x19a4c116|0,0x1e376c08|0,0x2748774c|0,0x34b0bcb5|0,0x391c0cb3|0,0x4ed8aa4a|0,0x5b9cca4f|0,0x682e6ff3|0,\r\n 0x748f82ee|0,0x78a5636f|0,0x84c87814|0,0x8cc70208|0,0x90befffa|0,0xa4506ceb|0,0xbef9a3f7|0,0xc67178f2|0\r\n ]);\r\n var _enc = (typeof TextEncoder !== 'undefined') ? new TextEncoder() : null;\r\n function utf8(str) {\r\n if (_enc) return _enc.encode(str);\r\n // 徿´(ç¡ TextEncoder çèç°å¢):æå UTF-8\r\n var out = [], i, c;\r\n for (i = 0; i < str.length; i++) {\r\n c = str.charCodeAt(i);\r\n if (c < 0x80) out.push(c);\r\n else if (c < 0x800) { out.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f)); }\r\n else if (c < 0xd800 || c >= 0xe000) { out.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); }\r\n else { i++; c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)); out.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 0x3f), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); }\r\n }\r\n return new Uint8Array(out);\r\n }\r\n function ROTR(n, x) { return (x >>> n) | (x << (32 - n)); }\r\n\r\n function sha256(data) {\r\n var msg = (typeof data === 'string') ? utf8(data) : data;\r\n var len = msg.length;\r\n var bitLenHi = Math.floor(len / 0x20000000); // (len*8) é« 32 bit\r\n var bitLenLo = (len << 3) >>> 0; // (len*8) ä½ 32 bit\r\n var withOne = len + 1;\r\n var pad = (56 - (withOne % 64) + 64) % 64;\r\n var total = withOne + pad + 8;\r\n var m = new Uint8Array(total);\r\n m.set(msg);\r\n m[len] = 0x80;\r\n m[total - 8] = (bitLenHi >>> 24) & 0xff; m[total - 7] = (bitLenHi >>> 16) & 0xff;\r\n m[total - 6] = (bitLenHi >>> 8) & 0xff; m[total - 5] = bitLenHi & 0xff;\r\n m[total - 4] = (bitLenLo >>> 24) & 0xff; m[total - 3] = (bitLenLo >>> 16) & 0xff;\r\n m[total - 2] = (bitLenLo >>> 8) & 0xff; m[total - 1] = bitLenLo & 0xff;
250\r\n\r\n var H0 = 0x6a09e667|0, H1 = 0xbb67ae85|0, H2 = 0x3c6ef372|0, H3 = 0xa54ff53a|0,\r\n H4 = 0x510e527f|0, H5 = 0x9b05688c|0, H6 = 0x1f83d9ab|0, H7 = 0x5be0cd19|0;\r\n var w = new Int32Array(64), off, i;\r\n for (off = 0; off < total; off += 64) {\r\n for (i = 0; i < 16; i++) {\r\n w[i] = (m[off + i*4] << 24) | (m[off + i*4 + 1] << 16) | (m[off + i*4 + 2] << 8) | (m[off + i*4 + 3]);\r\n }\r\n for (i = 16; i < 64; i++) {\r\n var x15 = w[i-15], x2 = w[i-2];\r\n var s0 = ROTR(7, x15) ^ ROTR(18, x15) ^ (x15 >>> 3);\r\n var s1 = ROTR(17, x2) ^ ROTR(19, x2) ^ (x2 >>> 10);\r\n w[i] = (w[i-16] + s0 + w[i-7] + s1) | 0;\r\n }\r\n var a=H0,b=H1,c=H2,d=H3,e=H4,f=H5,g=H6,h=H7;\r\n for (i = 0; i < 64; i++) {\r\n var S1 = ROTR(6, e) ^ ROTR(11, e) ^ ROTR(25, e);\r\n var ch = (e & f) ^ (~e & g);\r\n var t1 = (h + S1 + ch + K[i] + w[i]) | 0;\r\n var S0 = ROTR(2, a) ^ ROTR(13, a) ^ ROTR(22, a);\r\n var maj = (a & b) ^ (a & c) ^ (b & c);\r\n var t2 = (S0 + maj) | 0;\r\n h=g; g=f; f=e; e=(d + t1)|0; d=c; c=b; b=a; a=(t1 + t2)|0;\r\n }\r\n H0=(H0+a)|0; H1=(H1+b)|0; H2=(H2+c)|0; H3=(H3+d)|0; H4=(H4+e)|0; H5=(H5+f)|0; H6=(H6+g)|0; H7=(H7+h)|0;\r\n }\r\n var Hs = [H0,H1,H2,H3,H4,H5,H6,H7], out = new Uint8Array(32);\r\n for (i = 0; i < 8; i++) {\r\n out[i*4] = (Hs[i] >>> 24) & 0xff; out[i*4+1] = (Hs[i] >>> 16) & 0xff;\r\n out[i*4+2] = (Hs[i] >>> 8) & 0xff; out[i*4+3] = Hs[i] & 0xff;\r\n }\r\n return out;\r\n }\r\n\r\n global.tesseraSha256 = sha256;\r\n if (typeof module !== 'undefined' && module.exports) module.exports = sha256;\r\n})(typeof self !== 'undefined' ? self : typeof globalThis !== 'undefined' ? globalThis : this);\r\n\n/* Tessera â PoW 人æ©é©èçè¦½å¨æ±è§£ç«¯(UMD)ãPoW æ¹æ¡çº Hashcash å¼ leading-zero-bits(æ¦å¿µ:Adam Back 1997,å
¬æé å);ç¨å¼ç¢¼çº ASCDC èªæå¯¦ä½(ç§»æ¤èªå
§é¨ PoW Gate å°æ¡)ã\r\n å®å
¨æ§ä¸ä¾è³´æ¤æªä¿å¯:å®åªãæ¾ nonceã,ééç± server æ¸å¸é©èã */\r\n/* eslint-disable */\r\n// =============================================================================\r\n// public/ClientPoWMiner.js\r\n// -----------------------------------------------------------------------------\r\n// 鿝ç覽å¨ç«¯çãæç¤¦ç«¯ãæ±è§£å¨ã\r\n//\r\n// è¨è¨ååï¼èæ¯ç¹å¹£å·¥ä½èæç²¾ç¥ä¸è´ï¼ï¼\r\n// 1. 鿝 JS å¯ä»¥è¢«ä»»ä½äººçå°ãè¤è£½ãä¿®æ¹ï¼å®å
¨æ§ä¸ä¾è³´å®ä¿å¯ã\r\n// 2. å®åªè² 責ãåªåæ¾ nonceãã\r\n// 3. å®ä¸è² 責å¤å®èªå·±æ¯å¦ééï¼ä¹ä¸å¯ä»¥èªå·±ç°½ç¼ pass tokenã\r\n// 4. æ¾å° nonce å¾ï¼å¿
é 交給 server ç¨æ¸å¸æ¹å¼é©èã\r\n//\r\n// çºä»éº¼çå
乿²éä¿ï¼\r\n// ééæ¢ä»¶æ¯ SHA256(pow-v1|ticket_id|random_seed|scope|difficulty|nonce) ç\r\n// å difficulty å bit çº 0ãæ»æè
çæå
¨é¨ç¨å¼ä¹ç¡æ³è·³éââä»ä»ç¶å¿
é 實é\r\n// æ¾å°æ»¿è¶³æ¢ä»¶ç nonceï¼è server æèªå·±éç® hash é©èã\r\n//\r\n// æ¬æªä»¥ UMD å½¢å¼å°è£ï¼å¯å¨ä»¥ä¸ç°å¢éä½ï¼\r\n// - ç覽å¨ä¸»å·è¡ç·ï¼
250<script src=\"/ClientPoWMiner.js\">ï¼\r\n// - Web Workerï¼importScripts('/ClientPoWMiner.js')ï¼\r\n// - Node.js 測試ï¼require('../public/ClientPoWMiner.js')ï¼\r\n// =============================================================================\r\n\r\n(function (global) {\r\n 'use strict';\r\n\r\n // ---- åå¾ WebCrypto subtleï¼çè¦½å¨ / Worker / Node é½å試ï¼----------------\r\n var _subtle =\r\n typeof crypto !== 'undefined' && crypto.subtle\r\n ? crypto.subtle\r\n : global.crypto && global.crypto.subtle\r\n ? global.crypto.subtle\r\n : null;\r\n // Node 測試ç°å¢ç徿´ï¼è¥å
¨å crypto ä¸åå¨ï¼\r\n if (!_subtle && typeof module !== 'undefined' && module.exports) {\r\n try {\r\n _subtle = require('node:crypto').webcrypto.subtle;\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n }\r\n\r\n function nowMs() {\r\n if (typeof performance !== 'undefined' && performance.now) return performance.now();\r\n return Date.now();\r\n }\r\n\r\n class ClientPoWMiner {\r\n constructor(options = {}) {\r\n this.baseUrl = options.baseUrl || '';\r\n this.challengePath = options.challengePath || '/challenge';\r\n this.verifyPath = options.verifyPath || '/verify';\r\n\r\n // è¥è¨å® workerUrl ä¸ç°å¢æ¯æ´ Workerï¼solveChallenge ææè¨ç®ä¸å° Workerï¼\r\n // é¿å
å¡ä½ä¸» UIï¼å¦å fallback çºä¸»å·è¡ç· inline æ±è§£ï¼Node æ¸¬è©¦èµ°éæ¢ï¼ã\r\n this.workerUrl = options.workerUrl || null;\r\n\r\n this.onProgress = typeof options.onProgress === 'function' ? options.onProgress : null;\r\n this.onStatus = typeof options.onStatus === 'function' ? options.onStatus : null;\r\n\r\n // æ¯éå¤å°æ¬¡å試åå ±ä¸æ¬¡ progress\r\n this.progressInterval = options.progressInterval || 20000;\r\n // nonce æå°ä¸éï¼ä¿éªï¼é¿å
ç¡çª®è¿´åï¼\r\n this.maxNonce = options.maxNonce || Number.MAX_SAFE_INTEGER;\r\n\r\n this._encoder = new TextEncoder();\r\n }\r\n\r\n _status(state, info) {\r\n if (this.onStatus) this.onStatus(state, info || {});\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // 1) åå¾ challengeï¼å /challenge?scope=... è¦ HMAC ç°½ç« éç ticket\r\n // -------------------------------------------------------------------------\r\n async fetchChallenge(scope) {\r\n const url =\r\n this.baseUrl + this.challengePath + '?scope=' + encodeURIComponent(scope || '/');\r\n const res = await fetch(url, { credentials: 'same-origin' });\r\n const data = await res.json();\r\n if (!data || !data.ok || !data.challenge) {\r\n throw new Error('fetchChallenge 失æï¼' + (data && data.error ? data.error : res.status));\r\n }\r\n // challenge = { ticket, payload }\r\n return data.challenge;\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // 2) æ±è§£ nonceï¼ä¸æ·å試ç´å° hash å difficulty å bit çº 0\r\n // -------------------------------------------------------------------------\r\n async solveChallenge(challenge) {\r\n const payload = challenge.payload || challenge;\r\n const difficulty = payload.difficulty;\r\n\r\n // è¥å¯ç¨ Workerï¼ä¸çµ¦ Worker æ±è§£ï¼é¿å
å¡ UIï¼\r\n if (this.workerUrl && typeof Worker !== 'undefined') {\r\n return this._solveWithWorker(challenge);\r\n }\r\n\r\n // ---- 主å·è¡ç· inline æ±è§£ï¼fallback / Node 測試ï¼----\r\n const start = nowMs();\r\n let nonce = 0;\r\n let attempts = 0;\r\n\r\n while (nonce <= this.maxNonce) {\r\n const input = this.buildMiningInput(challenge, nonce);\r\n const hash = await this.sha256Bytes(input);\r\n attempts++;\r\n\r\n if (this.hasLeadingZeroBits(hash, difficulty)) {\r\n return {\r\n nonce: String(nonce),\r\n hash: this.bytesToHex(hash),\r\n attempts,\r\n elapsed_ms: nowMs() - start,\r\n };\r\n }\r\n\r\n if (this.onProgress && attempts % this.progressInterval === 0) {\r\n this.onProgress({ attempts, nonce, elapsed_ms: nowMs() - start });\r\n }\r\n nonce++;\r\n }\r\n throw new Error('nonce 空éå·²èç¡ï¼æªæ¾å°è§£');\r\n }\r\n\r\n // 以 Worker æ±è§£ï¼ç覽å¨ï¼\r\n _solveWithWorker(challenge) {\r\n const self_ = this;\r\n return new Promise(function (resolve, reject) {\r\n const worker = new Worker(self_.workerUrl);\r\n worker.onmessage = function (e) {\r\n const m = e.data || {};\r\n if (m.type === 'progress') {\r\n if (self_.onProgress) self_.onProgress(m);\r\n } else if (m.type === 'solved') {\r\n worker.terminate();
250\r\n resolve({\r\n nonce: m.nonce,\r\n hash: m.hash,\r\n attempts: m.attempts,\r\n elapsed_ms: m.elapsed_ms,\r\n });\r\n } else if (m.type === 'error') {\r\n worker.terminate();\r\n reject(new Error(m.message || 'worker error'));\r\n }\r\n };\r\n worker.onerror = function (err) {\r\n worker.terminate();\r\n reject(err);\r\n };\r\n worker.postMessage({\r\n type: 'solve',\r\n challenge: challenge,\r\n progressInterval: self_.progressInterval,\r\n });\r\n });\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // 3) éåº proof 給 server é©è\r\n // 注æï¼client_hash / elapsed_ms / solved åªæ¯ãé¤é¯èå±ç¤ºç¨ãï¼\r\n // server 䏿æ¡ä¿¡å®åå°å®å
¨æ§çå½±é¿ã\r\n // -------------------------------------------------------------------------\r\n async submitProof(challenge, proof) {\r\n const payload = challenge.payload || challenge;\r\n const res = await fetch(this.baseUrl + this.verifyPath, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n credentials: 'same-origin',\r\n body: JSON.stringify({\r\n ticket: challenge.ticket,\r\n ticket_id: payload.ticket_id,\r\n nonce: proof.nonce,\r\n client_hash: proof.hash, // debug onlyï¼server æèªå·±éç®\r\n elapsed_ms: proof.elapsed_ms, // debug onlyï¼server 忽ç¥\r\n attempts: proof.attempts, // debug only\r\n solved: true, // server å¿½ç¥æ¤æ¬ä½\r\n }),\r\n });\r\n let data = {};\r\n try {\r\n data = await res.json();\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n return { ok: res.ok && !!data.ok, status: res.status, data: data };\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // 4) 宿´æµç¨ï¼åå¾ challenge â æ±è§£ â éé©è â 顯示ééçæ
\r\n // -------------------------------------------------------------------------\r\n async run(scope) {\r\n this._status('fetching', { scope: scope });\r\n const challenge = await this.fetchChallenge(scope);\r\n const payload = challenge.payload || challenge;\r\n\r\n this._status('solving', { difficulty: payload.difficulty, scope: payload.scope });\r\n const proof = await this.solveChallenge(challenge);\r\n\r\n this._status('submitting', proof);\r\n const result = await this.submitProof(challenge, proof);\r\n\r\n this._status(result.ok ? 'passed' : 'failed', { proof: proof, result: result });\r\n return { challenge: challenge, proof: proof, result: result };\r\n }\r\n\r\n // =========================================================================\r\n // æ¼ç®æ³åèªï¼å¿
é è server 端 crypto-utils.js å®å
¨ä¸è´ï¼\r\n // =========================================================================\r\n\r\n // SHA-256ï¼åªå
WebCrypto;éå®å
¨å
§å®¹(ç´ HTTPãç¡ crypto.subtle)â ç´ JS 忥徿´ã\r\n async sha256Bytes(data) {\r\n if (!_subtle) {\r\n var _sha = (typeof tesseraSha256 !== 'undefined') ? tesseraSha256 : null;\r\n if (!_sha && typeof require !== 'undefined') { try { _sha = require('./tessera-sha256.js'); } catch (e) {} }\r\n if (!_sha) throw new Error('æ¤ç°å¢ä¸æ¯æ´ WebCrypto subtle ä¸ç¡ç´ JS SHA-256 徿´');\r\n return _sha(data);\r\n }\r\n const bytes = typeof data === 'string' ? this._encoder.encode(d
250ata) : data;\r\n const digest = await _subtle.digest('SHA-256', bytes);\r\n return new Uint8Array(digest);\r\n }\r\n\r\n // æª¢æ¥ hash å difficulty å bit æ¯å¦çº 0ï¼è server æ¼ç®æ³éåä¸è´ï¼ã\r\n // éåªæ¯ client èªå·±ç¨ä¾ã忢æå°ãï¼çæ£é©èä»å¨ serverã\r\n hasLeadingZeroBits(hashBytes, difficulty) {\r\n if (!Number.isInteger(difficulty) || difficulty < 0) return false;\r\n const fullBytes = difficulty >> 3;\r\n const remBits = difficulty & 7;\r\n if (fullBytes + (remBits > 0 ? 1 : 0) > hashBytes.length) return false;\r\n for (let i = 0; i < fullBytes; i++) {\r\n if (hashBytes[i] !== 0) return false;\r\n }\r\n if (remBits > 0) {\r\n const mask = (0xff << (8 - remBits)) & 0xff;\r\n if ((hashBytes[fullBytes] & mask) !== 0) return false;\r\n }\r\n return true;\r\n }\r\n\r\n // ç¢çæç¤¦è¼¸å ¥å串ï¼pow-v1|ticket_id|random_seed|scope|difficulty|nonce\r\n // æ ¼å¼å¿ é è· server verifier å®å ¨ä¸è´ã\r\n buildMiningInput(challenge, nonce) {\r\n const p = challenge.payload || challenge;\r\n return (\r\n 'pow-v1|' +\r\n String(p.ticket_id) +\r\n '|' +\r\n String(p.random_seed) +\r\n '|' +\r\n String(p.scope) +\r\n '|' +\r\n String(p.difficulty) +\r\n '|' +\r\n String(nonce)\r\n );\r\n }\r\n\r\n // å·¥å ·ï¼Uint8Array â hex å串ï¼debug 顯示ç¨ï¼\r\n bytesToHex(u8) {\r\n var s = '';\r\n for (var i = 0; i < u8.length; i++) {\r\n s += u8[i].toString(16).padStart(2, '0');\r\n }\r\n return s;\r\n }\r\n }\r\n\r\n // ---- UMD å¯åº -------------------------------------------------------------\r\n global.ClientPoWMiner = ClientPoWMiner;\r\n if (typeof module !== 'undefined' && module.exports) {\r\n module.exports = { ClientPoWMiner: ClientPoWMiner };\r\n }\r\n})(\r\n typeof self !== 'undefined'\r\n ? self\r\n : typeof globalThis !== 'undefined'\r\n ? globalThis\r\n : this\r\n);\r\n\n/* Tessera â PoW 人æ©é©èæ±è§£ Web WorkerãPoW æ¹æ¡çº Hashcash å¼ leading-zero-bits(æ¦å¿µ:Adam Back 1997,å ¬æé å);ç¨å¼ç¢¼çº ASCDC èªæå¯¦ä½(ç§»æ¤èªå §é¨ PoW Gate å°æ¡)ã\r\n å®å ¨æ§ä¸ä¾è³´æ¤æªä¿å¯:å®åªãæ¾ nonceã,ééç± server æ¸å¸é©èã */\r\n/* eslint-disable */\r\n// =============================================================================\r\n// public/pow-worker.js\r\n// -----------------------------------------------------------------------------\r\n// Web Worker æ±è§£å¨ã\r\n//\r\n// è·è²¬ï¼\r\n// 1. å¨ Workerï¼èæ¯å·è¡ç·ï¼å §å·è¡ nonce æå°ï¼é¿å å¡ä½ä¸» UIã\r\n// 2. æ¯éåºå®å試次æ¸åå ± progressã\r\n// 3. æ¾å° nonce å¾åå³ proofï¼nonce / hash / attempts / elapsed_msï¼ã\r\n// 4. ä¸èªè¡å¤å® server æ¯å¦ééââå®åªåå³ãæ¾å°çè§£ãï¼ç± server é©èã\r\n//\r\n// å®ç´æ¥ importScripts è¼å ¥ ClientPoWMinerï¼éç¨åä¸ä»½ buildMiningInput /\r\n// sha256Bytes / hasLeadingZeroBitsï¼ç¢ºä¿è server æ¼ç®æ³éåä¸è´ã\r\n// =============================================================================\r// (importScripts å·²ç± build å §è¯ miner å代)\nvar miner = new self.ClientPoWMiner();\r\n\r\n// è¨ç®ä¸å hash çãåå° 0 bit æ¸ãï¼ç´å±ç¤ºç¨ï¼ä¸å½±é¿æ±è§£æ¢ä»¶ï¼ã\r\nfunction leadingZeroBits(hashBytes) {\r\n var bits = 0;\r\n for (var i = 0; i < hashBytes.length; i++) {\r\n var b = hashBytes[i];\r\n if (b === 0) { bits += 8; continue; }\r\n var m = 0x80;\r\n while (m && (b & m) === 0) { bits++; m >>= 1; }\r\n break;\r\n }\r\n return bits;\r\n}\r\n\r\nself.onmessage = async function (e) {\r\n var msg = e.data || {};\r\n if (msg.type !== 'solve') return;\r\n\r\n var challenge = msg.challenge;\r\n var payload = challenge.payload || challenge;\r\n var difficulty = payload.difficulty;\r\n var interval = msg.progressInterval || 20000;\r\n\r\n var start = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();\r\n var nonce = 0;\r\n var attempts = 0;\r\n var bestBits = 0; // ç®åçéçæä½³åå° 0 bit æ¸ï¼å±ç¤ºãè¶ä¾è¶æ¥è¿ç®æ¨ãï¼\r\n\r\n function elapsed() {\r\n var t = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();\r\n return t - start;\r\n }\r\n\r\n try {\r\n while (true) {\r\n var input = miner.buildMiningInput(challenge, nonce);\r\n // ç¨ç´ JS SHA-256(忥):éå®å ¨å §å®¹(ç´ HTTP)ä¹è½ç®,ä¸ tight loop æ¯ WebCrypto ç async æ´å¿«ã\r\n // tesseraSha256 ç± build å §è¯å¨æ¬ worker ä¹å(WORKER_SRC = sha256 + miner + worker)ã\r\n var hash = tesseraSha256(input);\r\n attempts++;\r\n\r\n var bits = leadingZeroBits(hash);\r\n if (bits > bestBits) bestBits = bits;\r\n\r\n // çæ£çé鿢件ä»ç¶æ¯ ServerPoWGate è client å ±ç¨ç hasLeadingZeroBitsã\r\n if (miner.hasLeadingZeroBits(hash, difficulty)) {\r\n self.postMessage({\r\n type: 'solved',\r\n nonce: String(nonce),\r\n hash: miner.bytesToHex(hash),\r\n leadingZeroBits: bits,\r\n attempts: attempts,\r\n elapsed_ms: elapsed(),\r\n });\r\n return;\r\n }\r\n\r\n if (attempts % interval === 0) {\r\n self.postMessage({\r\n type: 'progress',\r\n attempts: attempts,\r\n nonce: nonce,\r\n bestBits: bestBits,\r\n difficulty: difficulty,\r\n elapsed_ms: elapsed(),\r\n });\r\n }\r\n nonce++;\r\n }\r\n } catch (err) {\r\n self.postMessage({ type: 'error', message: String((err && err.message) || err) });\r\n }\r\n};\r\n"; 251 var MEMORY_WORKER_SRC = "/* Tessera â ç´ JS SHA-256(忥)ãæ¼ç®æ³çºæ¨æº SHA-256(NIST FIPS 180-4,å ¬æé å);æ¤çº ASCDC èªæå¯¦ä½(é宣稱æ¼ç®æ³ååµ)ã\r\n ç¨é:ç¶çè¦½å¨ WebCrypto `crypto.subtle` ä¸å¯ç¨æ(éå®å ¨å §å®¹,ä¾å¦ç´ HTTPãé localhost)\r\n ä»è½ç® PoW éæ¹ â widget å¨ä»»ä½æ å¢é½è½é©è,䏿å ãéå®å ¨å §å®¹ãè失æã\r\n æ¨æº SHA-256:輸åºè WebCrypto / PHP hash('sha256',â¦,true) / å¾ç«¯éä½å çµä¸è´(已尿é©è)ã\r\n æ¥åå串(UTF-8 編碼)æ Uint8Array,åå³ 32-byte Uint8Arrayã */\r\n(function (global) {\r\n 'use strict';\r\n var K = new Int32Array([\r\n 0x428a2f98|0,0x71374491|0,0xb5c0fbcf|0,0xe9b5dba5|0,0x3956c25b|0,0x59f111f1|0,0x923f82a4|0,0xab1c5ed5|0,\r\n 0xd807aa98|0,0x12835b01|0,0x243185be|0,0x550c7dc3|0,0x72be5d74|0,0x80deb1fe|0,0x9bdc06a7|0,0xc19bf174|0,\r\n 0xe49b69c1|0,0xefbe4786|0,0x0fc19dc6|0,0x240ca1cc|0,0x2de92c6f|0,0x4a7484aa|0,0x5cb0a9dc|0,0x76f988da|0,\r\n 0x983e5152|0,0xa831c66d|0,0xb00327c8|0,0xbf597fc7|0,0xc6e00bf3|0,0xd5a79147|0,0x06ca6351|0,0x14292967|0,\r\n 0x27b70a85|0,0x2e1b2138|0,0x4d2c6dfc|0,0x53380d13|0,0x650a7354|0,0x766a0abb|0,0x81c2c92e|0,0x92722c85|0,\r\n 0xa2bfe8a1|0,0xa81a664b|0,0xc24b8b70|0,0xc76c51a3|0,0xd192e819|0,0xd6990624|0,0xf40e3585|0,0x106aa070|0,\r\n 0x19a4c116|0,0x1e376c08|0,0x2748774c|0,0x34b0bcb5|0,0x391c0cb3|0,0x4ed8aa4a|0,0x5b9cca4f|0,0x682e6ff3|0,\r\n 0x748f82ee|0,0x78a5636f|0,0x84c87814|0,0x8cc70208|0,0x90befffa|0,0xa4506ceb|0,0xbef9a3f7|0,0xc67178f2|0\r\n ]);\r\n var _enc = (typeof TextEncoder !== 'undefined') ? new TextEncoder() : null;\r\n function utf8(str) {\r\n if (_enc) return _enc.encode(str);\r\n // 徿´(ç¡ TextEncoder çèç°å¢):æå UTF-8\r\n var out = [], i, c;\r\n for (i = 0; i < str.length; i++) {\r\n c = str.charCodeAt(i);\r\n if (c < 0x80) out.push(c);\r\n else if (c < 0x800) { out.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f)); }\r\n else if (c < 0xd800 || c >= 0xe000) { out.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); }\r\n else { i++; c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)); out.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 0x3f), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); }\r\n }\r\n return new Uint8Array(out);\r\n }\r\n function ROTR(n, x) { return (x >>> n) | (x << (32 - n)); }\r\n\r\n function sha256(data) {\r\n var msg = (typeof data === 'string') ? utf8(data) : data;\r\n var len = msg.length;\r\n var bitLenHi = Math.floor(len / 0x20000000); // (len*8) é« 32 bit\r\n var bitLenLo = (len << 3) >>> 0; // (len*8) ä½ 32 bit\r\n var withOne = len + 1;\r\n var pad = (56 - (withOne % 64) + 64) % 64;\r\n var total = withOne + pad + 8;\r\n var m = new Uint8Array(total);\r\n m.set(msg);\r\n m[len] = 0x80;\r\n m[total - 8] = (bitLenHi >>> 24) & 0xff; m[total - 7] = (bitLenHi >>> 16) & 0xff;\r\n m[total - 6] = (bitLenHi >>> 8) & 0xff; m[total - 5] = bitLenHi & 0xff;\r\n m[total - 4] = (bitLenLo >>> 24) & 0xff; m[total - 3] = (bitLenLo >>> 16) & 0xff;\r\n m[total - 2] = (bitLenLo >>> 8) & 0xff; m[total - 1] = bitLenLo & 0xff;
251\r\n\r\n var H0 = 0x6a09e667|0, H1 = 0xbb67ae85|0, H2 = 0x3c6ef372|0, H3 = 0xa54ff53a|0,\r\n H4 = 0x510e527f|0, H5 = 0x9b05688c|0, H6 = 0x1f83d9ab|0, H7 = 0x5be0cd19|0;\r\n var w = new Int32Array(64), off, i;\r\n for (off = 0; off < total; off += 64) {\r\n for (i = 0; i < 16; i++) {\r\n w[i] = (m[off + i*4] << 24) | (m[off + i*4 + 1] << 16) | (m[off + i*4 + 2] << 8) | (m[off + i*4 + 3]);\r\n }\r\n for (i = 16; i < 64; i++) {\r\n var x15 = w[i-15], x2 = w[i-2];\r\n var s0 = ROTR(7, x15) ^ ROTR(18, x15) ^ (x15 >>> 3);\r\n var s1 = ROTR(17, x2) ^ ROTR(19, x2) ^ (x2 >>> 10);\r\n w[i] = (w[i-16] + s0 + w[i-7] + s1) | 0;\r\n }\r\n var a=H0,b=H1,c=H2,d=H3,e=H4,f=H5,g=H6,h=H7;\r\n for (i = 0; i < 64; i++) {\r\n var S1 = ROTR(6, e) ^ ROTR(11, e) ^ ROTR(25, e);\r\n var ch = (e & f) ^ (~e & g);\r\n var t1 = (h + S1 + ch + K[i] + w[i]) | 0;\r\n var S0 = ROTR(2, a) ^ ROTR(13, a) ^ ROTR(22, a);\r\n var maj = (a & b) ^ (a & c) ^ (b & c);\r\n var t2 = (S0 + maj) | 0;\r\n h=g; g=f; f=e; e=(d + t1)|0; d=c; c=b; b=a; a=(t1 + t2)|0;\r\n }\r\n H0=(H0+a)|0; H1=(H1+b)|0; H2=(H2+c)|0; H3=(H3+d)|0; H4=(H4+e)|0; H5=(H5+f)|0; H6=(H6+g)|0; H7=(H7+h)|0;\r\n }\r\n var Hs = [H0,H1,H2,H3,H4,H5,H6,H7], out = new Uint8Array(32);\r\n for (i = 0; i < 8; i++) {\r\n out[i*4] = (Hs[i] >>> 24) & 0xff; out[i*4+1] = (Hs[i] >>> 16) & 0xff;\r\n out[i*4+2] = (Hs[i] >>> 8) & 0xff; out[i*4+3] = Hs[i] & 0xff;\r\n }\r\n return out;\r\n }\r\n\r\n global.tesseraSha256 = sha256;\r\n if (typeof module !== 'undefined' && module.exports) module.exports = sha256;\r\n})(typeof self !== 'undefined' ? self : typeof globalThis !== 'undefined' ? globalThis : this);\r\n\n/* Tessera â memory-hard(MTP-lite,æ¦å¿µä¾ BiryukovâKhovratovichãEgalitarian Computingã2016)çè¦½å¨æ±è§£ç«¯ãç¨å¼ç¢¼çº ASCDC èªæå¯¦ä½(ç§»æ¤èªå
§é¨ PoW Gate ServerMemoryGate/ClientMemoryMiner)ã\r\n åªè² 責建 dataset/Merkle/æ¾ nonce;ééç±å¾ç«¯ O(K·logN) æ½æ¨£é©èãå®å
¨ä¸ä¾è³´æ¤æªä¿å¯ã */\r\n/* eslint-disable */\r\n// =============================================================================\r\n// public/ClientMemoryMiner.js\r\n// -----------------------------------------------------------------------------\r\n// Memory-hard æ±è§£ç«¯ï¼ç覽å¨ãæç¤¦ç«¯ãï¼ãè src/ServerMemoryGate.js ç dataset /\r\n// Merkle / answer è¦åãéåä¸è´ãï¼ä½¿ç¨ WebCrypto SHA-256ã\r\n//\r\n// å®åªè² 責ï¼é
ç½® dataset â 建 Merkle tree â æ¾ nonce â ç¢çæ½æ¨£ proofã\r\n// å®ä¸å¤å®èªå·±æ¯å¦ééï¼ééç± ServerMemoryGate æ¸å¸é©èã\r\n//\r\n// èæ¢æ ClientPoWMiner 並åï¼æªä¿®æ¹ä»»ä½ Hashcash æ ¸å¿ãUMDï¼å¯å¨çè¦½å¨ / Web Worker\r\n// / Node 測試å·è¡ã\r\n// =============================================================================\r\n\r\n(function (global) {\r\n 'use strict';\r\n\r\n var _subtle =\r\n typeof crypto !== 'undefined' && crypto.subtle\r\n ? crypto.subtle\r\n : global.crypto && global.crypto.subtle\r\n ? global.crypto.subtle\r\n : null;\r\n if (!_subtle && typeof module !== 'undefined' && module.exports) {\r\n try { _subtle = require('node:crypto').webcrypto.subtle; } catch (e) {}\r\n }\r\n\r\n var enc = new TextEncoder();\r\n\r\n function nowMs() {\r\n if (typeof performance !== 'undefined' && performance.now) return performance.now();\r\n return Date.now();\r\n }\r\n function concatBytes(arrays) {\r\n var len = 0, i;\r\n for (i = 0; i < arrays.length; i++) len += arrays[i].length;\r\n var out = new Uint8Array(len), o = 0;\r\n for (i = 0; i < arrays.length; i++) { out.set(arrays[i], o); o += arrays[i].length; }\r\n return out;\r\n }\r\n function u32BE(u8, off) {\r\n return ((u8[off] << 24) | (u8[off + 1] << 16) | (u8[off + 2] << 8) | u8[off + 3]) >>> 0;\r\n }\r\n function toHex(u8) {\r\n var s = '';\r\n for (var i = 0; i < u8.length; i++) s += u8[i].toString(16).padStart(2, '0');\r\n return s;\r\n }\r\n\r\n class ClientMemoryMiner {\r\n constructor(options) {\r\n options = options || {};\r\n this.baseUrl = options.baseUrl || '';
251\r\n this.challengePath = options.challengePath || '/api/memory/challenge';\r\n this.verifyPath = options.verifyPath || '/api/memory/verify';\r\n }\r\n\r\n async sha256Bytes(data) {\r\n if (!_subtle) {\r\n // éå®å
¨å
§å®¹(ç´ HTTPãç¡ crypto.subtle)â ç´ JS 忥徿´(L3 ä¹è½å¨ç´ HTTP éä½)\r\n var _sha = (typeof tesseraSha256 !== 'undefined') ? tesseraSha256 : null;\r\n if (!_sha && typeof require !== 'undefined') { try { _sha = require('./tessera-sha256.js'); } catch (e) {} }\r\n if (!_sha) throw new Error('æ¤ç°å¢ä¸æ¯æ´ WebCrypto subtle ä¸ç¡ç´ JS SHA-256 徿´');\r\n return _sha(data);\r\n }\r\n var bytes = typeof data === 'string' ? enc.encode(data) : data;\r\n var d = await _subtle.digest('SHA-256', bytes);\r\n return new Uint8Array(d);\r\n }\r\n\r\n hasLeadingZeroBits(hashBytes, difficulty) {\r\n if (!Number.isInteger(difficulty) || difficulty < 0) return false;\r\n var fullBytes = difficulty >> 3;\r\n var remBits = difficulty & 7;\r\n if (fullBytes + (remBits > 0 ? 1 : 0) > hashBytes.length) return false;\r\n for (var i = 0; i < fullBytes; i++) if (hashBytes[i] !== 0) return false;\r\n if (remBits > 0) {\r\n var mask = (0xff << (8 - remBits)) & 0xff;\r\n if ((hashBytes[fullBytes] & mask) !== 0) return false;\r\n }\r\n return true;\r\n }\r\n countLeadingZeroBits(u8) {\r\n var bits = 0;\r\n for (var i = 0; i < u8.length; i++) {\r\n var b = u8[i];\r\n if (b === 0) { bits += 8; continue; }\r\n var m = 0x80;\r\n while (m && (b & m) === 0) { bits++; m >>= 1; }\r\n break;\r\n }\r\n return bits;\r\n }\r\n\r\n // ---- dataset / merkleï¼è server éåä¸è´ï¼----\r\n async buildDataset(payload, onProgress) {\r\n var N = payload.block_count, tid = payload.ticket_id, seed = payload.random_seed;\r\n var blocks = new Array(N);\r\n blocks[0] = await this.sha256Bytes('mem-v1|blk|' + tid + '|' + seed + '|0');\r\n for (var i = 1; i < N; i++) {\r\n var prev = blocks[i - 1];\r\n var j = u32BE(prev, 0) % i;\r\n var suffix = enc.encode('|' + tid + '|' + seed + '|' + i);\r\n blocks[i] = await this.sha256Bytes(concatBytes([prev, blocks[j], suffix]));\r\n if (onProgress && i % 512 === 0) onProgress(i, N);\r\n }\r\n return blocks;\r\n }\r\n async _leafHash(block) { return this.sha256Bytes(concatBytes([new Uint8Array([0x00]), block])); }\r\n async _nodeHash(l, r) { return this.sha256Bytes(concatBytes([new Uint8Array([0x01]), l, r])); }\r\n\r\n async buildMerkle(blocks, onProgress) {\r\n var level = [];\r\n for (var i = 0; i < blocks.length; i++) {\r\n level.push(await this._leafHash(blocks[i]));\r\n if (onProgress && i % 512 === 0) onProgress(i, blocks.length);\r\n }\r\n var layers = [level];\r\n while (level.length > 1) {\r\n var next = [];\r\n for (var k = 0; k < level.length; k += 2) next.push(await this._nodeHash(level[k], level[k + 1]));\r\n layers.push(next);\r\n level = next;\r\n }\r\n return { root: level[0], layers: layers };\r\n }\r\n merkleProof(layers, index) {\r\n var path = [], idx = index;\r\n for (var l = 0; l < layers.length - 1; l++) { path.push(toHex(layers[l][idx ^ 1])); idx >>= 1; }\r\n return path;\r\n }\r\n async deriveIndices(rootBytes, nonce, K, N) {\r\n var indices = [];\r\n var pool = await this.sha256Bytes(concatBytes([rootBytes, enc.encode('|' + nonce)]));\r\n var off = 0;\r\n for (var k = 0; k < K; k++) {\r\n if (off + 4 > pool.length) { pool = await this.sha256Bytes(pool); off = 0; }\r\n var v = u32BE(pool, off); off += 4;\r\n indices.push(1 + (v % (N - 1)));\r\n }\r\n return indices;\r\n }\r\n async answerHash(rootBytes, nonce, cellBytes, seed) {\r\n var parts = [rootBytes, enc.encode('|' + nonce + '|')];\r\n for (var i = 0; i < cellBytes.length; i++) parts.push(cellBytes[i]);\r\n parts.push(enc.encode('|' + seed));\r\n return this.sha256Bytes(concatBytes(parts));\r\n }\r\n\r\n // ---- 宿´æ±è§£ï¼å¨ Worker æ Node å
§å¼å«ï¼hooks åå ± phase / progressï¼----\r\n async solveChallenge(challenge, hooks) {\r\n hooks = hooks || {};\r\n var payload = challenge.payload || challenge;\r\n var N = payload.block_count, K = payload.sample_count, diff = payload.difficulty, seed = payload.random_seed;\r\n var t0 = nowMs();\r\n var phase = function (p) { if (hooks.onPhase) hooks.onPhase(p); };\r\n var prog = function (o) { if (hooks.onProgress) hooks.onProgress(o); };\r\n\r\n phase('dataset');\r\n var blocks = await this.buildDataset(payload, function (done, total) {\r\n prog({ phase: 'dataset', done: done, total: total, elapsed_ms: nowMs() - t0 });\r\n });\r\n\r\n phase('merkle');\r\n var m = await this.buildMerkle(blocks, function (done, total) {\r\n prog({ phase: 'merkle', done: done, total: total, elapsed_ms: nowMs() - t0 });\r\n });\r\n var root = m.root, layers = m.layers;\r\n\r\n phase('nonce');\r\n var nonce = 0, required = null, Y = null, attempts = 0;\r\n for (;;) {\r\n required = await this.deriveIndices(root, String(nonce), K, N);\r\n var cells = required.map(function (i) { return blocks[i]; });\r\n Y = await this.answerHash(root, String(nonce), cells, seed);\r\n attempts++;\r\n if (this.hasLeadingZeroBits(Y, diff)) break;
251\r\n if (attempts % 200 === 0) prog({ phase: 'nonce', attempts: attempts, nonce: nonce, elapsed_ms: nowMs() - t0 });\r\n nonce++;\r\n }\r\n\r\n phase('proof');\r\n var self_ = this;\r\n var samples = required.map(function (i) {\r\n var j = u32BE(blocks[i - 1], 0) % i;\r\n return {\r\n index: i,\r\n value: toHex(blocks[i]),\r\n path: self_.merkleProof(layers, i),\r\n prevValue: toHex(blocks[i - 1]),\r\n prevPath: self_.merkleProof(layers, i - 1),\r\n backIndex: j,\r\n backValue: toHex(blocks[j]),\r\n backPath: self_.merkleProof(layers, j),\r\n };\r\n });\r\n var proof = {\r\n challenge_type: 'memory-v1',\r\n root: toHex(root),\r\n nonce: String(nonce),\r\n mem_bytes: N * payload.block_size,\r\n sample_indexes: required,\r\n answer_hash: toHex(Y),\r\n samples: samples,\r\n };\r\n var stats = {\r\n attempts: attempts,\r\n nonce: String(nonce),\r\n root: toHex(root),\r\n elapsed_ms: nowMs() - t0,\r\n sample_indexes: required,\r\n proof_bytes: JSON.stringify(proof).length,\r\n mem_bytes: N * payload.block_size,\r\n block_count: N,\r\n block_size: payload.block_size,\r\n rounds: payload.rounds,\r\n sample_count: K,\r\n leadingZeroBits: this.countLeadingZeroBits(Y),\r\n answer_hash: toHex(Y),\r\n };\r\n phase('done');\r\n return { proof: proof, stats: stats };\r\n }\r\n\r\n async fetchChallenge(scope) {\r\n var url = this.baseUrl + this.challengePath + '?scope=' + encodeURIComponent(scope || '/memory-demo');\r\n var res = await fetch(url, { credentials: 'same-origin' });\r\n var data = await res.json();\r\n if (!data || !data.ok || !data.challenge) throw new Error('memory challenge 失æ');\r\n return data.challenge;\r\n }\r\n async submitProof(challenge, proof) {\r\n var res = await fetch(this.baseUrl + this.verifyPath, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n credentials: 'same-origin',\r\n body: JSON.stringify({ ticket: challenge.ticket, proof: proof }),\r\n });\r\n var data = {};\r\n try { data = await res.json(); } catch (e) {}\r\n return { ok: res.ok && !!data.ok, status: res.status, data: data };\r\n }\r\n async run(scope) {\r\n var challenge = await this.fetchChallenge(scope);\r\n var solved = await this.solveChallenge(challenge);\r\n var result = await this.submitProof(challenge, solved.proof);\r\n return { challenge: challenge, proof: solved.proof, stats: solved.stats, result: result };\r\n }\r\n }\r\n\r\n global.ClientMemoryMiner = ClientMemoryMiner;\r\n if (typeof module !== 'undefined' && module.exports) {\r\n module.exports = { ClientMemoryMiner: ClientMemoryMiner };\r\n }\r\n})(\r\n typeof self !== 'undefined' ? self : typeof globalThis !== 'undefined' ? globalThis : this\r\n);\r\n\n/* Tessera â memory-hard(MTP-lite,æ¦å¿µä¾ BiryukovâKhovratovich 2016)æ±è§£ Web Workerãç¨å¼ç¢¼çº ASCDC èªæå¯¦ä½(ç§»æ¤èªå §é¨ PoW Gate)ã\r\n èæ¯é ç½® datasetã建 Merkleãæ¾ nonceãç¢çæ½æ¨£ proof,åéæ®µ(dataset/merkle/nonce/proof)åå ±é²åº¦ã\r\n 注æ:æ¬æªç± build å §è¯ tessera-memory-miner.js(å代䏿¹ importScripts);ç¨ç«ä½¿ç¨æè«ç¢ºä¿ miner å è¼å ¥ã */\r// (importScripts å·²ç± build å §è¯ miner å代)\nvar miner = new self.ClientMemoryMiner();\r\n\r\nself.onmessage = async function (e) {\r\n var msg = e.data || {};\r\n if (msg.type !== 'solve') return;\r\n try {\r\n var res = await miner.solveChallenge(msg.challenge, {\r\n onPhase: function (p) { self.postMessage({ type: 'phase', phase: p }); },\r\n onProgress: function (o) { self.postMessage({ type: 'progress', progress: o }); },\r\n });\r\n self.postMessage({ type: 'solved', proof: res.proof, stats: res.stats });\r\n } catch (err) {\r\n self.postMessage({ type: 'error', message: String((err && err.message) || err) });\r\n }\r\n};\r\n"; 252 253 var RTL = (I18N && I18N._rtl) || ['ar', 'he', 'fa', 'ur']; 254 var FALLBACK = (I18N && I18N._fallback) || 'en'; 255 256 // ---- èªè¨è§£æ:attr â <html lang> â navigator;æ£è¦å zh è®é« ------------- 257 function normLang(raw) { 258 if (!raw) return ''; 259 var s = String(raw).trim(); 260 var low = s.toLowerCase().replace('_', '-'); 261 // 䏿è®é«:ç°¡ç¹å¤å® 262 if (low.indexOf('zh') === 0) { 263 if (/hant|tw|hk|mo/.test(low)) return 'zh-Hant'; 264 if (/hans|cn|sg|my/.test(low)) return 'zh-Hans'; 265 return 'zh-Hant'; // é è¨ç¹ä¸(æ¬å°æ¡ä¸»è¦èªå¢) 266 } 267 // è¡èª:巴西(pt-BR)vs ææ´²(pt);åªæå¸¶ br æå¤å·´è¥¿,å ¶é¤(å«è£¸ pt / pt-PT)ç¨ææ´²è¡èª 268 if (low.indexOf('pt') === 0) return low.indexOf('br') >= 0 ? 'pt-BR' : 'pt'; 269 // è²å¾è³èª:tl / tl-* / fil* ä¸å¾å°æ fil 270 if (low === 'tl' || low.indexOf('tl-') === 0 || low.indexOf('fil')
270=== 0) return 'fil'; 271 // 馬ä¾èª:ms / ms-* 272 if (low.indexOf('ms') === 0) return 'ms'; 273 // å主èªè¨ç¢¼ 274 var base = low.split('-')[0]; 275 return base; 276 } 277 278 function pickLang(requested) { 279 var order = []; 280 if (requested) order.push(requested); 281 try { 282 var htmlLang = document.documentElement && document.documentElement.getAttribute('lang'); 283 if (htmlLang) order.push(htmlLang); 284 } catch (e) {} 285 try { 286 var navs = (navigator.languages && navigator.languages.slice()) || [navigator.language]; 287 for (var i = 0; i < navs.length; i++) order.push(navs[i]); 288 } catch (e) {} 289 for (var j = 0; j < order.length; j++) { 290 var n = normLang(order[j]); 291 if (n && I18N[n]) return n; 292 // 主碼 fallback(å¦ es-MX â es) 293 var base = n.split('-')[0]; 294 if (I18N[base]) return base; 295 } 296 return FALLBACK; 297 } 298 299 function t(lang, key) { 300 var pack = I18N[lang] || I18N[FALLBACK] || {}; 301 if (pack[key] != null) return pack[key]; 302 var fb = I18N[FALLBACK] || {}; 303 return fb[key] != null ? fb[key] : key; 304 } 305 306 // ---- å §åµæ±è§£åèª(Worker ä¸å¯ç¨æç主å·è¡ç· fallback)--------------------- 307 var _enc = new TextEncoder(); 308 function buildMiningInput(p, nonce) { 309 return 'pow-v1|' + p.ticket_id + '|' + p.random_seed + '|' + p.scope + '|' + p.difficulty + '|' + nonce; 310 } 311 // SHA-256:åªå ç´ JS 忥(éå®å ¨å §å®¹/ç´ HTTP ä¹è½ç¨);tesseraSha256 ç± build å §è¯çºå ¨åã 312 // ç¡å §è¯æéå WebCrypto(å Promise)ã_solveInline ç¨ await,å°åæ¥/Promise çç¸å®¹ã 313 function sha256(strOrBytes) { 314 if (typeof tesseraSha256 === 'function') return tesseraSha256(strOrBytes); 315 var bytes = typeof strOrBytes === 'string' ? _enc.encode(strOrBytes) : strOrBytes; 316 return crypto.subtle.digest('SHA-256', bytes).then(function (d) { return new Uint8Array(d); }); 317 } 318 function hasLeadingZeroBits(h, diff) { 319 var full = diff >> 3, rem = diff & 7; 320 if (full + (rem > 0 ? 1 : 0) > h.length) return false; 321 for (var i = 0; i < full; i++) if (h[i] !== 0) return false; 322 if (rem > 0) { var m = (0xff << (8 - rem)) & 0xff; if ((h[full] & m) !== 0) return false; } 323 return true; 324 } 325 function leadingZeroBits(h) { 326 var bits = 0; 327 for (var i = 0; i < h.length; i++) { 328 var b = h[i]; 329 if (b === 0) { bits += 8; continue; } 330 var m = 0x80; while (m && (b & m) === 0) { bits++; m >>= 1; } break; 331 } 332 return bits; 333 } 334 335 var _blobUrl = null, _memBlobUrl = null; 336 function workerBlobUrl() { 337 if (_blobUrl) return _blobUrl; 338 try { _blobUrl = URL.createObjectURL(new Blob([WORKER_SRC], { type: 'text/javascript' })); } 339 catch (e) { _blobUrl = null; } 340 return _blobUrl; 341 } 342 function memoryWorkerBlobUrl() { 343 if (_memBlobUrl) return _memBlobUrl; 344 try { _memBlobUrl = URL.createObjectURL(new Blob([MEMORY_WORKER_SRC], { type: 'text/javascript' })); } 345 catch (e) { _memBlobUrl = null; } 346 return _memBlobUrl; 347 } 348 349 // ===================================================================== 350 // <tessera-widget> 351 // ===================================================================== 352 class TesseraWidget extends HTMLElement { 353 static get observedAttributes() { return ['lang', 'theme', 'disabled', 'dir']; } 354 355 constructor() { 356 super(); 357 this.attachShadow({ mode: 'open' }); 358 this._state = 'idle'; 359 this._worker = null; 360 this._inlineAbort = false;
361 this._verified = false; 362 this._timer = null; 363 this._lang = FALLBACK; 364 this._maxSolveMs = 30000; // æ±è§£ç¡¬ä¸é â 龿 365 this._fieldPrefix = 'tessera'; 366 this._hidden = { ticket: null, nonce: null }; 367 } 368 369 // ---- å ¬é屬æ§:embedded challenge {ticket, payload} ---- 370 set challenge(v) { this._challenge = v; } 371 get challenge() { return this._challenge; } 372 373 connectedCallback() { 374 this._fieldPrefix = this.getAttribute('field-prefix') || 'tessera'; 375 if (this.hasAttribute('max-solve-ms')) { 376 var m = parseInt(this.getAttribute('max-solve-ms'), 10); 377 if (m > 0) this._maxSolveMs = m; 378 } 379 // attribute å¸¶å ¥ challenge(JSON) 380 if (!this._challenge && this.hasAttribute('challenge')) { 381 try { this._challenge = JSON.parse(this.getAttribute('challenge')); } catch (e) {} 382 } 383 this._lang = pickLang(this.getAttribute('lang')); 384 this._isRtl = RTL.indexOf(this._lang.split('-')[0]) >= 0; 385 this._render(); 386 this._ensureHiddenFields(); 387 if (this.hasAttribute('auto')) { 388 // èªåéå§(ä¸é黿) 389 this._start(); 390 } 391 } 392 393 disconnectedCallback() { this._cleanup(); } 394 395 attributeChangedCallback(name) { 396 if (!this.shadowRoot || !this._root) return; 397 if (name === 'lang') { 398 this._lang = pickLang(this.getAttribute('lang')); 399 this._isRtl = RTL.indexOf(this._lang.split('-')[0]) >= 0; 400 this._applyLangText(); 401 } else if (name === 'theme') { 402 this._applyTheme(); 403 } else if (name === 'disabled') { 404 this._applyDisabled(); 405 } 406 } 407 408 // ---- 渲æ ---- 409 _render() { 410 var lang = this._lang; 411 // CSS æ³¨å ¥:åªå ç¨ Constructable Stylesheet(adoptedStyleSheets)â å¨å´æ ¼ CSP 412 // (style-src 'self',ç¡ unsafe-inline)ä¸ä»å¯éä½;䏿¯æ´æéå inline <style>ã 413 var styleTag = ''; 414 var adopted = false; 415 try { 416 if (this.shadowRoot.adoptedStyleSheets !== undefined && typeof CSSStyleSheet === 'function') { 417 var sheet = new CSSStyleSheet(); 418 sheet.replaceSync(CSS); 419 this.shadowRoot.adoptedStyleSheets = [sheet]; 420 adopted = true; 421 } 422 } catch (e) { adopted = false; } 423 if (!adopted) styleTag = '<style>' + CSS + '</style>'; 424 this.shadowRoot.innerHTML = 425 styleTag + 426 '<div class="tsr" part="card" role="checkbox" tabindex="0" aria-checked="false" data-state="idle"' + 427 (this._isRtl ? ' dir="rtl"' : '') + '>' + 428 '<span class="tsr-box" aria-hidden="true">' + 429 '<span class="tsr-spinner"></span>' + 430 '<svg class="tsr-check" viewBox="0 0 24 24" aria-hidden="true"><path d="M4.5 12.5l4.5 4.5L19.5 7"/></svg>
430' + 431 '<svg class="tsr-cross" viewBox="0 0 24 24" aria-hidden="true"><path d="M7 7l10 10M17 7L7 17"/></svg>' + 432 '</span>' + 433 '<span class="tsr-body">' + 434 '<span class="tsr-label" id="tsr-lbl"></span>' + 435 '<span class="tsr-status" id="tsr-st" role="status" aria-live="polite"></span>' + 436 '</span>' + 437 '<span class="tsr-brand">' + 438 '<svg class="tsr-mark" viewBox="0 0 24 24" aria-hidden="true">' + 439 '<rect class="tsr-tile" x="2" y="2" width="9" height="9" rx="2.4" fill="var(--tsr-accent)"/>' + 440 '<rect class="tsr-tile" x="13" y="2" width="9" height="9" rx="2.4" fill="var(--tsr-accent-2)"/>' + 441 '<rect class="tsr-tile" x="2" y="13" width="9" height="9" rx="2.4" fill="var(--tsr-accent-2)"/>' + 442 '<rect class="tsr-tile" x="13" y="13" width="9" height="9" rx="2.4" fill="var(--tsr-accent)"/>' + 443 '</svg>' + 444 '<span class="tsr-brand-text">TESSERA</span>' + 445 '</span>' + 446 '<div class="tsr-progress" data-mode="indeterminate"><div class="tsr-bar"></div></div>' + 447 '</div>'; 448 449 this._root = this.shadowRoot.querySelector('.tsr'); 450 this._elLabel = this.shadowRoot.getElementById('tsr-lbl'); 451 this._elStatus = this.shadowRoot.getElementById('tsr-st'); 452 this._elProgress = this.shadowRoot.querySelector('.tsr-progress'); 453 this._elBar = this.shadowRoot.querySelector('.tsr-bar'); 454 this._elBrand = this.shadowRoot.querySelector('.tsr-brand'); 455 456 this._applyTheme(); 457 this._applyLangText(); 458 this._applyDisabled(); 459 460 var self_ = this; 461 this._root.addEventListener('click', function () { self_._activate(); }); 462 this._root.addEventListener('keydown', function (e) { 463 if (e.key === ' ' || e.key === 'Enter' || e.key === 'Spacebar') { 464 e.preventDefault(); 465 self_._activate(); 466 } 467 }); 468 // focus-visible 徿´(èç覽å¨) 469 this._root.addEventListener('focus', function () { self_._root.classList.add('tsr-focus'); }); 470 this._root.addEventListener('blur', function () { self_._root.classList.remove('tsr-focus'); }); 471 } 472 473 _applyTheme() { 474 // 主é¡ç± host ç [theme=light|dark] 屬æ§ç´æ¥é© å(CSS :host([theme=...])); 475 // ä¸è¨å¼=auto(è·é¨ç³»çµ± prefers-color-scheme)ãæ¤èå æ£è¦åéæ³å¼ã 476 var theme = this.getAttribute('theme'); 477 if (theme && theme !== 'light' && theme !== 'dark') this.removeAttribute('theme'); 478 } 479 480 _applyLangText() { 481 if (!this._root) return; 482 var lang = this._lang; 483 this._elLabel.textContent = t(lang, 'label'); 484 this._root.setAttribute('aria-label', t(lang, 'aria_checkbox')); 485 this._elBrand.setAttribute('title', t(lang, 'brand_title')); 486 this._elProgress.setAttribute('aria-label', t(lang, 'progress_label')); 487 if (this._isRtl) this._root.setAttribute('dir', 'rtl'); else this._root.removeAttribute('dir'); 488 if (this._state === 'idle') this._setStatus('status_idle'); 489 } 490 491 _applyDisabled() { 492 var dis = this.hasAttribute('disabled'); 493 if (!this._root) return; 494 if (dis) { 495 this._root.setAttribute('aria-disabled', 'true'); 496 this._root.removeAttribute('tabindex'); 497 } else if (!this._verified && this._state !== 'solving' && this._state !== 'verifying') { 498 this._root.removeAttribute('aria-disabled'); 499 this._root.setAttribute('tabindex', '0'); 500 } 501 } 502 503 _ensureHiddenFields() { 504 // hidden æ¬ä½æ¾ light DOM,ææé¨å¤å±¤ <form> éåº 505 var mk = function (name) { 506 var el = document.createElement('input'); 507 el.type = 'hidden'; 508 el.name = name; 509 return el; 510 }; 511 this._hidden.ticket = mk(this._fieldPrefix + '_ticket'); 512 this._hidden.nonce = mk(this._fieldPrefix + '_nonce'); 513 this.appendChild(this._hidden.ticket); 514 this.appendChild(this._hidden.nonce); 515 } 516 517 // memory-hard æéè¦ç proof æ¬ä½(JSON);å»¶é²å»ºç« 518 _ensureProofField() { 519 if (this._hidden.proof) return; 520 var el = document.createElement('input'); 521 el.type = 'hidden'; 522 el.name = this._fieldPrefix + '_proof'; 523 this._hidden.proof = el; 524 this.appendChild(el); 525 } 526 527 // ---- çæ æ© ---- 528 _setState(s) { 529 this._state = s; 530 if (this._root) { 531 this._root.setAttribute('data-state', s); 532 this._root.setAttribute('aria-busy', (s === 'solving' || s === 'verifying' || s === 'start') ? 'true' : 'false'); 533 } 534 } 535 _setStatus(key) { if (this._elStatus) this._elStatus.textContent = t(this._lang, key); } 536 537 _activate() { 538 if (this.hasAttribute('disabled')) return; 539 if (this._verified) return; 540 if (this._state === 'solving' || this._state === 'verifying' || this._state === 'start') return; 541 if (this._state === 'error' || this._state === 'expired') { this.reset(); } 542 this._start(); 543 } 544 545 async _start() { 546 this._verified = false;
547 this._inlineAbort = false; 548 this._setState('start'); 549 this._setStatus('status_start'); 550 this._setProgress('indeterminate', 0); 551 552 // åå¾ challenge:embedded åªå ,å¦å challenge-url æ 553 var challenge = this._challenge; 554 try { 555 if (!challenge && this.hasAttribute('challenge-url')) { 556 challenge = await this._fetchChallenge(); 557 } 558 } catch (e) { 559 return this._fail('status_offline', 'fetch_failed'); 560 } 561 if (!challenge || !(challenge.payload || challenge.ticket)) { 562 return this._fail('status_error', 'no_challenge'); 563 } 564 this._challenge = challenge; 565 566 var payload = challenge.payload || challenge; 567 // 票å¸éæ:åµå ¥å¼ææ°æéæ(å¾ç«¯ ticketTtl)ãè¥æ challenge-url â éæä¸å¼µæ°ææ°(é£åº¦ä¾ 568 // å¾ç«¯ RiskScore + retry æå);å¦åç¡æ³ refetch,åéæãéä¿®æ£ã龿å¾é»æç¡åæã(éæå¡æ»)ã 569 if (payload.expires_at && (payload.expires_at * 1000) < Date.now()) { 570 if (this.hasAttribute('challenge-url')) { 571 try { challenge = await this._fetchChallenge(); } 572 catch (e) { return this._fail('status_offline', 'fetch_failed'); } 573 if (!challenge || !(challenge.payload || challenge.ticket)) return this._fail('status_error', 'no_challenge'); 574 this._challenge = challenge; 575 payload = challenge.payload || challenge; 576 } 577 if (payload.expires_at && (payload.expires_at * 1000) < Date.now()) { 578 return this._fail('status_expired', 'client_expired'); 579 } 580 } 581 582 this._setState('solving'); 583 this._setStatus('status_solving'); 584 this._deadline = Date.now() + this._maxSolveMs; 585 this._startTimer(); 586 587 var self_ = this; 588 try { 589 var proof = await this._solve(challenge, payload, function (p) { self_._onProgress(p, payload); }); 590 this._clearTimer(); 591 await this._onSolved(challenge, proof); 592 } catch (err) { 593 this._clearTimer(); 594 if (String(err && err.message) === 'timeout') this._fail('status_expired', 'timeout'); 595 else if (this._inlineAbort) { /* reset 主å䏿¢,ä¸å ±é¯ */ } 596 else this._fail('status_error', String((err && err.message) || err)); 597 } 598 } 599 600 async _fetchChallenge() { 601 var scope = this.getAttribute('scope') || (location.pathname || '/'); 602 var url = this.getAttribute('challenge-url') + (this.getAttribute('challenge-url').indexOf('?') < 0 ? '?' : '&') + 'scope=' + encodeURIComponent(scope); 603 // æ¨é å §å®¹åå:宿主端é»(å¦ next.php)以 X-Tessera-Challenge 辨èãè¦æ°ææ° JSONãèéæ´é HTML 604 // (æ£å¼åç«¯ææ ?tessera= query ç«¯é» 302 ææ,æ ç¨åæºé é¢ URL + æ¨é )ãX-Tessera-Retry ä¾é£åº¦æåã 605 var res = await fetch(url, { 606 credentials: 'same-origin', 607 headers: { 'X-Tessera-Challenge': '1', 'X-Tessera-Retry': String(this._retryHint || 0) } 608 }); 609 var data = await res.json(); 610 if (!data || !data.ok || !data.challenge) throw new Error('challenge_failed'); 611 return data.challenge; 612 } 613 614 // æ±è§£:ä¾ challenge_type è·¯ç±(memory-v1 èµ° memory worker);Worker åªå ,fallback 主å·è¡ç· 615 _solve(challenge, payload, onProgress) { 616 if ((payload.challenge_type || '') === 'memory-v1') { 617 return this._solveMemory(challenge, onProgress); 618 } 619 var url = workerBlobUrl(); 620 var external = this.getAttribute('worker-src'); 621 if ((external || url) && typeof Worker !== 'undefined') { 622 return this._solveWorker(external || url, challenge, onProgress); 623 } 624 return this._solveInline(challenge, payload, onProgress); 625 } 626 627 // memory-hard æ±è§£(å Worker;ç¡ Worker ç°å¢æ reject â ä¸å±¤é¡¯ç¤ºé¯èª¤) 628 _solveMemory(challenge, onProgress) { 629 var self_ = this; 630 var url = this.getAttribute('memory-worker-src') || memoryWorkerBlobUrl(); 631 if (!url || typeof Worker === 'undefined') { 632 return Promise.reject(new Error('memory_no_worker')); 633 } 634 return new Promise(function (resolve, reject) { 635 var w; 636 try { w = new Worker(url); } catch (e) { return reject(new Error('memory_worker_spawn')); } 637 self_._worker = w; 638 w.onmessage = function (e) { 639 var m = e.data || {}; 640 if (m.type === 'phase') { 641 // dataset/merkle/nonce/proof â ä»é¡¯ç¤ºãé©èä¸ã,é²åº¦æ¼ progress äºä»¶æ´æ° 642 } else if (m.type === 'progress' && m.progress) { 643 var pr = m.progress; 644 if (pr.total) onProgress({ memFrac: Math.min(pr.done / pr.total, 0.95), phase: pr.phase }); 645 else onProgress({ indeterminate: true, phase: pr.phase }); 646 } else if (m.type === 'solved') { 647 w.terminate(); self_._worker = null; 648 resolve({ memory: true, proof: m.proof, stats: m.stats || {}, nonce: m.proof && m.proof.nonce }); 649 } else if (m.type === 'error') { 650 w.terminate(); self_._worker = null; reject(new Error(m.message || 'memory_worker_error')); 651 } 652 }; 653 w.onerror = function () { w.terminate(); self_._worker = null; reject(new Error('memory_worker_error')); }; 654 w.postMessage({ type: 'solve', challenge: challenge }); 655 }); 656 } 657 658 _solveWorker(workerUrl, challenge, onProgress) { 659 var self_ = this; 660 return new Promise(function (resolve, reject) { 661 var w; 662 try { w = new Worker(workerUrl); } 663 catch (e) { return self_._solveInline(challenge, challenge.payload || challenge, onProgress).then(resolve, reject); } 664 self_._worker = w; 665 w.onmessage = function (e) { 666 var m = e.data || {}; 667 if (m.type === 'progress') onProgress(m); 668 else if (m.type === 'solved') { w.terminate(); self_._worker = null;
668 resolve({ nonce: m.nonce, hash: m.hash, attempts: m.attempts, elapsed_ms: m.elapsed_ms }); } 669 else if (m.type === 'error') { w.terminate(); self_._worker = null; reject(new Error(m.message || 'worker_error')); } 670 }; 671 w.onerror = function () { 672 w.terminate(); self_._worker = null; 673 // Worker è¼å ¥/å·è¡å¤±æ â éå主å·è¡ç· 674 self_._solveInline(challenge, challenge.payload || challenge, onProgress).then(resolve, reject); 675 }; 676 w.postMessage({ type: 'solve', challenge: challenge, progressInterval: 15000 }); 677 }); 678 } 679 680 async _solveInline(challenge, payload, onProgress) { 681 var diff = payload.difficulty; 682 var nonce = 0, attempts = 0, best = 0; 683 var start = (performance && performance.now) ? performance.now() : Date.now(); 684 while (true) { 685 if (this._inlineAbort) throw new Error('aborted'); 686 if (Date.now() > this._deadline) throw new Error('timeout'); 687 var h = await sha256(buildMiningInput(payload, nonce)); 688 attempts++; 689 var bits = leadingZeroBits(h); if (bits > best) best = bits; 690 if (hasLeadingZeroBits(h, diff)) { 691 var hex = ''; for (var i = 0; i < h.length; i++) hex += h[i].toString(16).padStart(2, '0'); 692 return { nonce: String(nonce), hash: hex, attempts: attempts, elapsed_ms: ((performance && performance.now) ? performance.now() : Date.now()) - start }; 693 } 694 if (attempts % 1500 === 0) { 695 onProgress({ attempts: attempts, bestBits: best, difficulty: diff }); 696 // è®åºä¸»å·è¡ç·,é¿å åçµ UI 697 await new Promise(function (r) { setTimeout(r, 0); }); 698 } 699 nonce++; 700 } 701 } 702 703 _onProgress(p, payload) { 704 if (p && typeof p.memFrac === 'number') { this._setProgress('determinate', p.memFrac); return; } 705 if (p && p.indeterminate) { this._setProgress('indeterminate', 0); return; } 706 var diff = (p && p.difficulty) || (payload && payload.difficulty) || 1; 707 var best = (p && p.bestBits) || 0; 708 // 以ãç®åæä½³åå° 0 bit / ç®æ¨é£åº¦ãè¿ä¼¼é²åº¦,å°é 92% ç給æçµå½ä¸ 709 var frac = Math.min(best / diff, 0.92); 710 this._setProgress('determinate', frac); 711 } 712 713 _setProgress(mode, frac) { 714 if (!this._elProgress) return; 715 this._elProgress.setAttribute('data-mode', mode); 716 this._elProgress.setAttribute('role', 'progressbar'); 717 if (mode === 'determinate') { 718 var pct = Math.round(frac * 100); 719 this._elBar.style.width = Math.max(6, pct) + '%'; 720 this._elProgress.setAttribute('aria-valuenow', String(pct)); 721 this._elProgress.setAttribute('aria-valuemin', '0'); 722 this._elProgress.setAttribute('aria-valuemax', '100'); 723 } else { 724 this._elBar.style.width = ''; 725 this._elProgress.removeAttribute('aria-valuenow'); 726 } 727 } 728 729 async _onSolved(challenge, proof) { 730 this._setState('verifying'); 731 this._setStatus('status_verifying'); 732 this._setProgress('determinate', 1); 733 734 var isMemory = !!(proof && proof.memory); 735 // å¯«å ¥ hidden æ¬ä½(é¨è¡¨å®éåºç±å¾ç«¯é©è) 736 if (this._hidden.ticket) this._hidden.ticket.value = challenge.ticket || ''; 737 if (isMemory) { 738 // memory-hard:proof çºç©ä»¶(å« root/nonce/samples)â 以 JSON 帶å 739 this._ensureProofField(); 740 this._hidden.proof.value = JSON.stringify(proof.proof || {}); 741 if (this._hidden.nonce) this._hidden.nonce.value = (proof.proof && proof.proof.nonce) || ''; 742 } else { 743 if (this._hidden.nonce) this._hidden.nonce.value = proof.nonce || ''; 744 } 745 746 // è¥æå® verify-url,主å POST 給å¾ç«¯å³æé©è(å¦å交給表å®éåº) 747 var verifyUrl = this.getAttribute('verify-url'); 748 if (verifyUrl) { 749 try { 750 var body = isMemory 751 ? { ticket: challenge.ticket, proof: proof.proof } 752 : { ticket: challenge.ticket, nonce: proof.nonce }; 753 var res = await fetch(verifyUrl, { 754 method: 'POST', credentials: 'same-origin', 755 headers: { 'Content-Type': 'application/json' }, 756 body: JSON.stringify(body) 757 }); 758 var data = {}; 759 try { data = await res.json(); } catch (e) {} 760 if (!(res.ok && data && data.ok)) { 761 return this._fail('status_error', (data && data.reason) || ('http_' + res.status)); 762 } 763 if (data.passToken && this._hidden.ticket) { 764 // å¾ç«¯å passToken æ,æ¹å¸¶ passToken(å¯é¸æ¬ä½) 765 var pt = document.createElement('input'); 766 pt.type = 'hidden'; pt.name = this._fieldPrefix + '_pass'; 767 pt.value = data.passToken; this.appendChild(pt); 768 } 769 } catch (e) { 770 return this._fail('status_offline', 'verify_network'); 771 } 772 } 773 this._succeed(challenge, proof); 774 } 775 776 _succeed(challenge, proof) { 777 this._verified = true; 778 this._setState('success'); 779 this._setStatus('status_success'); 780 this._root.setAttribute('aria-checked', 'true'); 781 this._root.setAttribute('aria-disabled', 'true'); 782 this._root.removeAttribute('tabindex'); 783 // çµ±ä¸äºä»¶å½¢ç:memory è pow 齿´é² {ticket, type, nonce, proof, stats} 784 var isMemory = !!(proof && proof.memory); 785 var detail = isMemory 786 ? { ticket: challenge.ticket, type: 'memory-v1', nonce: proof.nonce, proof: proof.proof, stats: proof.stats || {} } 787 : { ticket: challenge.ticket, type: 'pow-v1', nonce: proof.nonce, proof: proof, stats: proof }; 788 this.dispatchEvent(new CustomEvent('tessera-verified', { bubbles: true, composed: true, detail: detail })); 789 } 790 791 _fail(statusKey, reason) { 792 var expired = statusKey === 'status_expired'; 793 // 龿/éæ:å°é½ Google reCAPTCHA ââ åãæªæå¾ãidle çæ (空æ¹å¡ãå¯éé»), 794 // å çæ åé¡¯ç¤ºé¾æè¨æ¯;ä¸åå¨ error åãå ¶ä»é¯èª¤ç¶æ error åã 795 this._setState(expired ? 'idle' : 'error'); 796 this._setStatus(statusKey); 797 this._setProgress('indeterminate', 0); 798 this._verified = false;
799 this._root.setAttribute('aria-checked', 'false'); 800 this._root.removeAttribute('aria-disabled'); 801 this._root.setAttribute('tabindex', '0'); 802 // é¾æç´¯è¨ â 䏿¬¡éæ°é©èæé£åº¦æåç便(帶é²äºä»¶ detail.retry;æ±è§£æåå¸¶çµ¦ææ° gateLevel)ã 803 if (expired) this._retryHint = (this._retryHint || 0) + 1; 804 this.dispatchEvent(new CustomEvent(expired ? 'tessera-expired' : 'tessera-error', { 805 bubbles: true, composed: true, detail: { reason: reason, retry: this._retryHint || 0 } 806 })); 807 } 808 809 _startTimer() { 810 var self_ = this; 811 this._clearTimer(); 812 this._timer = setInterval(function () { 813 if (Date.now() > self_._deadline) { 814 self_._clearTimer(); 815 self_._cleanupWorker(); 816 self_._inlineAbort = true; 817 self_._fail('status_expired', 'timeout'); 818 } 819 }, 1000); 820 } 821 _clearTimer() { if (this._timer) { clearInterval(this._timer); this._timer = null; } } 822 823 _cleanupWorker() { if (this._worker) { tr
823y { this._worker.terminate(); } catch (e) {} this._worker = null; } } 824 _cleanup() { this._clearTimer(); this._cleanupWorker(); this._inlineAbort = true; } 825 826 // ---- å ¬éæ¹æ³ ---- 827 reset() { 828 this._cleanup(); 829 this._inlineAbort = true; 830 this._verified = false; 831 if (this._hidden.ticket) this._hidden.ticket.value = ''; 832 if (this._hidden.nonce) this._hidden.nonce.value = ''; 833 if (this._hidden.proof) this._hidden.proof.value = ''; 834 this._setState('idle'); 835 this._setProgress('indeterminate', 0); 836 this._root.setAttribute('aria-checked', 'false'); 837 this._root.removeAttribute('aria-disabled'); 838 this._root.setAttribute('tabindex', '0'); 839 this._setStatus('status_idle'); 840 } 841 start() { this._activate(); } 842 isVerified() { return !!this._verified; } 843 844 // ---- åæ è¨å®èªç³» / 主é¡(ä¾å®¿ä¸»å¥ç¨ä½¿ç¨è ä¿åçå好,ä¸å¯é¨ææ¹)---- 845 /** è¨å®èªç³»(BCP-47,å¦ 'ja' / 'zh-Hant' / 'ar');峿é繪æåè RTLãçå setAttribute('lang', â¦)ã */ 846 setLang(lang) { if (lang != null && lang !== '') this.setAttribute('lang', String(lang)); } 847 /** è¨å®ä¸»é¡:'light' | 'dark' | 'auto'(æç©º=è·é¨ç³»çµ± prefers-color-scheme);峿å¥ç¨(CSS é© å)ã */ 848 setTheme(theme) { 849 var v = (theme == null ? '' : String(theme)).toLowerCase(); 850 if (v === 'light' || v === 'dark') this.setAttribute('theme', v); 851 else this.removeAttribute('theme'); // auto / 系統 852 } 853 } 854 855 customElements.define('tessera-widget', TesseraWidget); 856})(); 857</script>
857 858
858<script nonce="OEJNNdEDZn0oGoyYA3Jbug">(function(){ 859 'use strict'; 860 function $(s,r){return (r||document).querySelector(s);} 861 function ready(fn){ if(document.readyState!=='loading') fn(); else document.addEventListener('DOMContentLoaded',fn); } 862 ready(function(){ 863 var zone=$('.captcha-zone'); if(!zone) return; 864 var rc=$('.g-recaptcha',zone); 865 var tw=$('tessera-widget',zone); 866 var toggle=$('.cap-toggle',zone); 867 var note=$('.cap-fallback-note',zone); 868 var help=$('.cap-help',zone); 869 var back=$('.cap-back',zone); 870 if(!tw) return; 871 // æ auth é é¢å好(<html data-theme> / <html lang>,使ç¨è ä¿åæç¶å ´åæçè¨å®)åæ¥çµ¦ widget,ä¸¦åæ è·é¨ã 872 function syncPrefs(){ 873 var dt=document.documentElement.getAttribute('data-theme'); 874 if(dt==='dark'||dt==='light'){ tw.setTheme?tw.setTheme(dt):tw.setAttribute('theme',dt); } 875 else { tw.setTheme?tw.setTheme('auto'):tw.removeAttribute('theme'); } 876 var lg=document.documentElement.getAttribute('lang'); if(lg){ tw.setLang?tw.setLang(lg):tw.setAttribute('lang',lg); } 877 } 878 syncPrefs(); 879 try{ new MutationObserver(syncPrefs).observe(document.documentElement,{attributes:true,attributeFilter:['data-theme','lang','dir']}); }catch(e){} 880 881 // é£çºé©è失æ â 顯示ãè¯ç¹«æåãæ±å©é£çµ(widget æ¯æ¬¡å¤±ææ bubble tessera-error / tessera-expired; 882 // composed:true å¯ç©¿åº Shadow DOM åæ³¡å° zone)ãæå忏 é¤ãéæª» 2 次,é¿å 宿¬¡ææ»å°±åºç¾ã 883 var troubles=0; 884 function onTrouble(){ if(++troubles>=2 && help){ help.classList.remove('tsr-hidden'); } } 885 zone.addEventListener('tessera-error', onTrouble); 886 zone.addEventListener('tessera-expired', onTrouble); 887 zone.addEventListener('tessera-verified', function(){ troubles=0; if(help){ help.classList.add('tsr-hidden'); } }); 888 889 // primary:伺æå¨ç«¯å·²ç´æ¥é¡¯ç¤º Tessera(reCAPTCHA æªè¨å® / CAPTCHA_PRIMARY=tessera)ã 890 // æ¤æ¨¡å¼ãæ¬ä¾å°±ç¨å §å»ºé©èã,ä¸¦ç¡ reCAPTCHA 失æ / åææ å¢ â ä¸é¡¯ç¤ºä»»ä½åææç¤ºã 891 var primary = !tw.classList.contains('tsr-hidden'); 892 if(primary) return; 893 894 // ---- 以ä¸çºãreCAPTCHA çºä¸»ãTessera çºåæ´ãçåæé輯 ---- 895 var shown=false; 896 function showTessera(reason){ 897 if(shown) return; shown=true; 898 tw.classList.remove('tsr-hidden'); 899 if(rc) rc.classList.add('tsr-hidden'); 900 if(toggle) toggle.classList.add('tsr-hidden'); 901 if(note){ 902 // ææ¡ä¾åæåå :auto=reCAPTCHA è¼å ¥å¤±æ(é³è¿°å·²èªåæ¹ç¨);manual=使ç¨è 主ååæ(䏿§ç¢ºèª)ã 903 var msg=note.getAttribute(reason==='manual' ? 'data-manual' : 'data-auto'); 904 if(msg){ note.textContent=msg; } 905 note.classList.remove('tsr-hidden'); 906 } 907 // åªæãæååæã(reCAPTCHA å ¶å¯¦æ£å¸¸)ææä¾åå Google;auto(reCAPTCHA 壿)ååæ²æç¾©ã 908 if(reason==='manual' && back){ back.classList.remove('tsr-hidden'); } 909 } 910 // åå Google reCAPTCHA(reverse of showTessera):é±è Tessera/æç¤º/ååé,éæ°é¡¯ç¤º reCAPTCHA + åæéã 911 function showRecaptcha(){ 912 shown=false; 913 tw.classList.add('tsr-hidden'); 914 if(rc) rc.classList.remove('tsr-hidden'); 915 if(note) note.classList.add('tsr-hidden'); 916 if(back) back.classList.add('tsr-hidden'); 917 if(toggle) toggle.classList.remove('tsr-hidden'); 918 } 919 function recaptchaRendered(){ 920 // reCAPTCHA è¼å ¥å¾æå¨ .g-recaptcha å §æå ¥ iframe 921 return !!(rc && rc.querySelector('iframe')) || (typeof window.grecaptcha!=='undefined' && window.grecaptcha.render); 922 } 923 // æååæ(reCAPTCHA æ£å¸¸ææä¾çé¸é )+ åå 924 if(toggle){ toggle.addEventListener('click',function(e){ e.preventDefault(); showTessera('manual'); }); } 925 if(back){ back.addEventListener('click',function(e){ e.preventDefault(); showRecaptcha(); }); } 926 // èªå嵿¸¬:è¥è©²ç¶²åæªè¨»å reCAPTCHA / è¼å ¥è¢«æ â 䏿®µæé徿²æ¸²æå°±èªåå Tessera 927 if(!rc){ showTessera('auto'); return; } 928 var waited=0, iv=setInterval(function(){ 929 waited+=500; 930 if(recaptchaRendered()){ clearInterval(iv); if(toggle) toggle.classList.remove('tsr-hidden'); return; } 931 if(waited>=5000){ clearInterval(iv); showTessera('auto'); } 932 },500); 933 }); 934})();</script>
934 935
935<script nonce="OEJNNdEDZn0oGoyYA3Jbug">window.__CD__={teExp:1790937216000,teWin:180,now:1790937036742,tePrimary:false,orangeFrac:0.6667,redFrac:0.1667,preempt:0.95,rcWin:110,lang:"en"};window.__CD_I18N__={"zh-Hant":{"label":"é©èæææé","ok":"æéå
è¶³","warn":"è«åå¿«å®æ","danger":"å³å°é¾æ","tip":"éæ¯æ¬æ¬¡äººæ©é©èçæææéã龿ééæ°æ´çé é¢åé©è䏿¬¡,æ¨è¼¸å
¥ç帳èæä¿çã","exp_title":"é©èæææéå·²é","exp_body":"çºäºå®å
¨,è«éæ°æ´çé é¢å徿°çé©èãæ¨è¼¸å
¥ç帳èæä¿ç,å¯ç¢¼ééæ°è¼¸å
¥ã","reload":"éæ°æ´ç"},"zh-Hans":{"label":"éªè¯æææ¶é´","ok":"æ¶é´å
è¶³","warn":"è¯·å°½å¿«å®æ","danger":"å³å°è¶
æ¶","tip":"è¿æ¯æ¬æ¬¡äººæºéªè¯çæææ¶é´ãè¶
æ¶éå·æ°é¡µé¢åéªè¯ä¸æ¬¡,æ¨è¾å
¥çè´¦å·ä¼ä¿çã","exp_title":"éªè¯æææ¶é´å·²è¿","exp_body":"为äºå®å
¨,è¯·å·æ°é¡µé¢è·åæ°çéªè¯ãæ¨è¾å
¥çè´¦å·ä¼ä¿ç,å¯ç ééæ°è¾å
¥ã","reload":"å·æ°é¡µé¢"},"en":{"label":"Verification time left","ok":"Plenty of time","warn":"Please finish soon","danger":"About to expire","tip":"How long the current verification stays valid. If it expires, refresh the page to verify again â your account name is kept.","exp_title":"Verification has expired","exp_body":"For your security, refresh the page to get a new verification. Your account name is kept; youâll need to re-enter your password.","reload":"Refresh"},"ja":{"label":"èªè¨¼ã®æå¹æé","ok":"æéã«ä½è£ãã","warn":"ãæ©ãã«å®äºã","danger":"ã¾ããªãæéåã","tip":"ç¾å¨ã®ç¢ºèªãæå¹ãªæ®ãæéã§ããæéåãã®å ´åã¯ãã¼ã¸ãåèªã¿è¾¼ã¿ãã¦å度確èªãã¦ãã ãããå
¥åããã¢ã«ã¦ã³ãã¯ä¿æããã¾ãã","exp_title":"èªè¨¼ã®æå¹æéãåãã¾ãã","exp_body":"å®å
¨ã®ããããã¼ã¸ãåèªã¿è¾¼ã¿ãã¦æ°ãã確èªãåå¾ãã¦ãã ãããã¢ã«ã¦ã³ãã¯ä¿æããã¾ããããã¹ã¯ã¼ãã¯åå
¥åãå¿
è¦ã§ãã","reload":"åèªã¿è¾¼ã¿"},"ko":{"label":"ì¸ì¦ ì í¨ ìê°","ok":"ìê° ì¶©ë¶","warn":"ê³§ ìë£í´ 주ì¸ì","danger":"ê³§ ë§ë£ë¨","tip":"íì¬ ì¸ì¦ì´ ì í¨í ë¨ì ìê°ì
ëë¤. ë§ë£ëë©´ íì´ì§ë¥¼ ìë¡ ê³ ì³ ë¤ì ì¸ì¦íì¸ì. ì
ë ¥í ê³ì ì ì ì§ë©ëë¤.","exp_title":"ì¸ì¦ ì í¨ ìê°ì´ ì§ë¬ìµëë¤","exp_body":"ë³´ìì ìí´ íì´ì§ë¥¼ ìë¡ ê³ ì³ ì ì¸ì¦ì ë°ì¼ì¸ì. ê³ì ì ì ì§ëë©° ë¹ë°ë²í¸ë ë¤ì ì
ë ¥í´ì¼ í©ëë¤.","reload":"ìë¡ ê³ ì¹¨"},"es":{"label":"Tiempo de verificación restante","ok":"Tiempo de sobra","warn":"Termina pronto, por favor","danger":"A punto de caducar","tip":"Tiempo durante el cual la verificación actual sigue siendo válida. Si caduca, actualiza la página para verificar de nuevo; se conservará tu cuenta.","exp_title":"La verificación ha caducado","exp_body":"Por seguridad, actualiza la página para obtener una nueva verificación. Se conservará tu cuenta; tendrás que volver a escribir la contraseña.","reload":"Actualizar"},"fr":{"label":"Temps de vérification restant","ok":"Largement le temps","warn":"à terminer rapidement","danger":"Bientôt expiré","tip":"Durée pendant laquelle la vérification actuelle reste valable. En cas dâexpiration, actualisez la page pour vérifier à nouveau ; votre identifiant est conservé.","exp_title":"La vérification a expiré","exp_body":"Par sécurité, actualisez la page pour obtenir une nouvelle vérification. Votre identifiant est conservé ; vous devrez ressaisir le mot de passe.","reload":"Actualiser"},"de":{"label":"Verbleibende Prüfzeit","ok":"Genug Zeit","warn":"Bitte bald abschlieÃen","danger":"Läuft gleich ab","tip":"So lange bleibt die aktuelle Prüfung gültig. Nach Ablauf die Seite neu laden und erneut verifizieren â Ihr Konto bleibt erhalten.","exp_title":"Die Prüfung ist abgelaufen","exp_body":"Bitte laden Sie die Seite aus Sicherheitsgründen neu, um eine neue Prüfung zu erhalten. Ihr Konto bleibt erhalten; das Passwort müssen Sie erneut eingeben.","reload":"Neu laden"},"ru":{"label":"ÐÑÑалоÑÑ Ð²Ñемени на пÑовеÑкÑ","ok":"ÐÑемени доÑÑаÑоÑно","warn":"ÐавеÑÑиÑе поÑкоÑее","danger":"СкоÑо иÑÑеÑÑÑ","tip":"СколÑко еÑÑ Ð´ÐµÐ¹ÑÑвиÑелÑна ÑекÑÑÐ°Ñ Ð¿ÑовеÑка. ÐоÑле иÑÑеÑÐµÐ½Ð¸Ñ Ð¾Ð±Ð½Ð¾Ð²Ð¸Ñе ÑÑÑаниÑÑ Ð¸ пÑойдиÑе пÑовеÑÐºÑ Ñнова â Ð²Ð°Ñ Ð»Ð¾Ð³Ð¸Ð½ ÑоÑ
ÑаниÑÑÑ.","exp_title":"СÑок пÑовеÑки иÑÑÑк","exp_body":"Ð ÑелÑÑ
безопаÑноÑÑи обновиÑе ÑÑÑаниÑÑ, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ Ð½Ð¾Ð²ÑÑ Ð¿ÑовеÑкÑ. ÐогиÐ
935½ ÑоÑ
ÑаниÑÑÑ, паÑÐ¾Ð»Ñ Ð½Ñжно ввеÑÑи заново.","reload":"ÐбновиÑÑ"},"vi":{"label":"Thá»i gian xác minh còn lại","ok":"Còn nhiá»u thá»i gian","warn":"Vui lòng hoà n tất sá»m","danger":"Sắp hết hạn","tip":"Äây là thá»i gian hiá»u lá»±c cá»§a lần xác minh nà y. Nếu hết hạn, vui lòng tải lại trang Äá» xác minh lại; tà i khoản bạn Äã nháºp sẽ ÄÆ°á»£c giữ lại.","exp_title":"Xác minh Äã hết hạn","exp_body":"Vì lý do bảo máºt, vui lòng tải lại trang Äá» xác minh lại. Tà i khoản bạn Äã nháºp sẽ ÄÆ°á»£c giữ lại; bạn cần nháºp lại máºt khẩu.","reload":"Tải lại"},"th":{"label":"à¹à¸§à¸¥à¸²à¸¢à¸·à¸à¸¢à¸±à¸à¸à¸µà¹à¹à¸«à¸¥à¸·à¸","ok":"มีà¹à¸§à¸¥à¸²à¹à¸«à¸¥à¸·à¸à¸¡à¸²à¸","warn":"à¹à¸à¸£à¸à¸à¸³à¹à¸«à¹à¹à¸ªà¸£à¹à¸à¹à¸£à¹à¸§ à¹","danger":"à¹à¸à¸¥à¹à¸«à¸¡à¸à¹à¸§à¸¥à¸²","tip":"à¸à¸µà¹à¸à¸·à¸à¹à¸§à¸¥à¸²à¸à¸µà¹à¸à¸²à¸£à¸¢à¸·à¸à¸¢à¸±à¸à¸à¸±à¸à¸à¸¸à¸à¸±à¸à¸¢à¸±à¸à¹à¸à¹à¹à¸à¹ หาà¸à¸«à¸¡à¸à¹à¸§à¸¥à¸² à¹à¸à¸£à¸à¸£à¸µà¹à¸à¸£à¸à¸«à¸à¹à¸²à¹à¸à¸·à¹à¸à¸¢à¸·à¸à¸¢à¸±à¸à¸à¸µà¸à¸à¸£à¸±à¹à¸ à¸à¸±à¸à¸à¸µà¸à¸à¸à¸à¸¸à¸à¸à¸°à¸à¸¹à¸à¹à¸à¹à¸à¹à¸§à¹","exp_title":"à¸à¸²à¸£à¸¢à¸·à¸à¸¢à¸±à¸à¸«à¸¡à¸à¹à¸§à¸¥à¸²à¹à¸¥à¹à¸§","exp_body":"à¹à¸à¸·à¹à¸à¸à¸§à¸²à¸¡à¸à¸¥à¸à¸à¸ ัย à¹à¸à¸£à¸à¸£à¸µà¹à¸à¸£à¸à¸«à¸à¹à¸²à¹à¸à¸·à¹à¸à¸£à¸±à¸à¸à¸²à¸£à¸¢à¸·à¸à¸¢à¸±à¸à¹à¸«à¸¡à¹ à¸à¸±à¸à¸à¸µà¸à¸°à¸à¸¹à¸à¹à¸à¹à¸à¹à¸§à¹ à¹à¸à¹à¸à¹à¸à¸à¸à¸£à¸à¸à¸£à¸«à¸±à¸ªà¸à¹à¸²à¸à¸à¸µà¸à¸à¸£à¸±à¹à¸","reload":"รีà¹à¸à¸£à¸"},"id":{"label":"Sisa waktu verifikasi","ok":"Waktu masih banyak","warn":"Harap segera selesaikan","danger":"Hampir kedaluwarsa","tip":"Ini adalah masa berlaku verifikasi ini. Jika kedaluwarsa, muat ulang halaman untuk verifikasi ulang; akun yang Anda masukkan akan tetap tersimpan.","exp_title":"Verifikasi telah kedaluwarsa","exp_body":"Demi keamanan, muat ulang halaman untuk mendapatkan verifikasi baru. Akun Anda disimpan; Anda perlu memasukkan kata sandi lagi.","reload":"Muat ulang"},"ms":{"label":"Baki masa pengesahan","ok":"Masa mencukupi","warn":"Sila selesaikan segera","danger":"Hampir tamat tempoh","tip":"Ini tempoh pengesahan semasa masih sah. Jika tamat tempoh, muat semula halaman untuk mengesah semula; akaun anda akan dikekalkan.","exp_title":"Pengesahan telah tamat tempoh","exp_body":"Demi keselamatan, sila muat semula halaman untuk mendapatkan pengesahan baharu. Akaun anda dikekalkan; anda perlu memasukkan kata laluan semula.","reload":"Muat semula"},"fil":{"label":"Natitirang oras ng pag-verify","ok":"Marami pang oras","warn":"Pakitapos na agad","danger":"Malapit nang mag-expire","tip":"Ito ang tagal na balido ang kasalukuyang pag-verify. Kapag nag-expire, i-refresh ang pahina para mag-verify ulit; mananatili ang iyong account.","exp_title":"Nag-expire na ang pag-verify","exp_body":"Para sa iyong seguridad, i-refresh ang pahina para makakuha ng bagong pag-verify. Mananatili ang account; kailangan mong muling ilagay ang password.","reload":"I-refresh"},"nl":{"label":"Resterende verificatietijd","ok":"Tijd genoeg","warn":"Rond het snel af","danger":"Verloopt bijna","tip":"Zo lang blijft de huidige verificatie geldig. Vernieuw bij het verlopen de pagina om opnieuw te verifiëren; je account blijft behouden.","exp_title":"De verificatie is verlopen","exp_body":"Vernieuw voor je veiligheid de pagina voor een nieuwe verificatie. Je account blijft behouden; je moet het wachtwoord opnieuw invoeren.","reload":"Vernieuwen"},"pt":{"label":"Tempo de verificação restante","ok":"Tempo de sobra","warn":"Conclua em breve, por favor","danger":"Prestes a expirar","tip":"Tempo durante o qual a verificação atual continua válida. Se expirar, atualize a página para verificar de novo; a sua conta será mantida.","exp_title":"A verificação expirou","exp_body":"Por segurança, atualize a página para obter uma nova verificação. A sua conta será mantida; terá de introduzir a palavra-passe novamente.","reload":"Atualizar"}};</script>
935 936
936<script nonce="OEJNNdEDZn0oGoyYA3Jbug">(function(){ 937 'use strict'; 938 var CFG=window.__CD__; if(!CFG){ return; } 939 var I18N=window.__CD_I18N__||{}; 940 function $(s,r){ return (r||document).querySelector(s); } 941 function ready(fn){ if(document.readyState!=='loading'){ fn(); } else { document.addEventListener('DOMContentLoaded',fn); } } 942 function canon(l){ 943 if(!l){ return 'en'; } 944 var lo=String(l).toLowerCase(); 945 var m={'zh':'zh-Hant','zh-tw':'zh-Hant','zh-hk':'zh-Hant','zh-mo':'zh-Hant','zh-hant':'zh-Hant','zh-cn':'zh-Hans','zh-sg':'zh-Hans','zh-hans':'zh-Hans','tl':'fil'}; 946 if(m[lo]){ return m[lo]; } 947 if(I18N[l]){ return l; } 948 for(var k in I18N){ if(k.toLowerCase()===lo){ return k; } } 949 var base=lo.split('-')[0]; 950 for(var k2 in I18N){ if(k2.toLowerCase()===base){ return k2; } } 951 return I18N['en']?'en':(Object.keys(I18N)[0]||'en'); 952 } 953 var lang=canon(document.documentElement.getAttribute('lang')||CFG.lang||'en'); 954 function T(){ return I18N[lang]||I18N['en']||{}; } 955 var CIRC=2*Math.PI*18; 956 ready(function(){ 957 var zone=$('.captcha-zone'); 958 var row=$('.cd-row'), arc=$('.cd-arc'), num=$('.cd-num'), state=$('.cd-state'), 959 tip=$('.cd-tip'), wrap=$('.cd-ring-wrap'), panel=$('.cd-expired'), card=$('.card'); 960 if(!row||!arc||!panel){ return; } 961 var skew=(typeof CFG.now==='number')?(CFG.now-Date.now()):0; 962 function applyI18N(){ 963 var t=T(); 964 if(tip&&t.tip){ tip.textContent=t.tip; } 965 var et=panel.querySelector('.cd-exp-title'); if(et&&t.exp_title){ et.textContent=t.exp_title; } 966 var eb=panel.querySelector('.cd-exp-body'); if(eb&&t.exp_body){ eb.textContent=t.exp_body; } 967 var rl=panel.querySelector('.cd-reload-label'); if(rl&&t.reload){ rl.textContent=t.reload; } 968 } 969 applyI18N(); 970 var sel=$('#langSelect'); 971 // åæèªè¨ â 帶 ?lang éæ°è¼å ¥,è®ä¼ºæå¨ææ´é (cap-* åææç¤º / reCAPTCHA hl / 忏 / æ¨é¡)䏿¬¡æ¸²æææ°èªè¨ã 972 // åæåæ«å帳è(å¯ç¢¼ä¸å),è¼å ¥å¾ç±ä¸é¢çéåé輯帶å;並寫 AUTH_LANG cookie 確ä¿ä¸æ¬¡è¨ä½ã 973 if(sel){ sel.addEventListener('change',function(){ 974 var v=sel.value||lang; 975 try{ var af=$('#account'); if(af&&af.value){ sessionStorage.setItem('cd_acct',af.value); } }catch(e){} 976 try{ document.cookie='AUTH_LANG='+encodeURIComponent(v)+'; path=/; max-age=31536000; samesite=Lax'; }catch(e){} 977 try{ var u=new URL(location.href); u.searchParams.set('lang', v); location.assign(u.toString()); }catch(e){ location.reload(); } 978 }); } 979 try{ new MutationObserver(function(){ var nl=canon(document.documentElement.getAttribute('lang')||lang); if(nl!==lang){ lang=nl; applyI18N(); tick(); } }).observe(document.documentElement,{attributes:true,attributeFilter:['lang']}); }catch(e){} 980 try{ var acc=sessionStorage.getItem('cd_acct'); if(acc){ var af=$('#account'); if(af&&!af.value){ af.value=acc; } sessionStorage.removeItem('cd_acct'); } }catch(e){} 981 var rcDeadline=null, teShownAt=null, teRevWin=0; 982 window.__cdRcSolved=function(){ rcDeadline=Date.now()+((CFG.rcWin||110)*1000); tick(); }; 983 window.__cdRcExpired=function(){ rcDeadline=Date.now()-1; tick(); }; 984 function visible(el){ return !!(el && !el.classList.contains('tsr-hidden') && el.offsetParent!==null); } 985 function active(){ 986 var tw=zone&&zone.querySelector('tessera-widget'); 987 var rc=zone&&zone.querySelector('.g-recaptcha'); 988 if(visible(tw) && typeof CFG.teExp==='number'){ 989 if(CFG.tePrimary){ return {dl:CFG.teExp,win:(CFG.teWin||180)*1000,srv:true}; } 990 // fallback:widget è¼å ¥æé±èãç¨å¾æé¡¯ç¤º â å¾ã顯示ç¶ä¸ãåºå®ä¸åçª(min(teWin, 票å¸å©é¤ç§)),é¨å®ç實票å¸å°æ;é¿å 沿ç¨è¼å ¥çµå°çªé æèª¤é/èª¤æ© 991 if(teShownAt===null){ teShownAt=Date.now(); teRevWin=Math.max(0,Math.min((CFG.teWin||180),(CFG.teExp-(Date.now()+skew))/1000)); } 992 if(teRevWin<=0){ return {dl:(Date.now()+skew)-1,win:(CFG.teWin||180)*1000,srv:true,dead:true}; } 993 return {dl:(teShownAt+skew)+teRevWin*1000,win:teRevWin*1000,srv:true}; 994 } 995 if(visible(rc)){ return rcDeadline?{dl:rcDeadline,win:(CFG.rcWin||110)*1000,srv:false}:null; } 996 if(typeof CFG.teExp==='number'){ return {dl:CFG.teExp,win:(CFG.teWin||180)*1000,srv:true}; } 997 return null; 998 } 999 var done=false, timer=null; 1000 function fmt(s){ s=Math.max(0,Math.ceil(s)); var m=Math.floor(s/60); var x=s%60; return m+':'+(x<10?'0'+x:x); } 1001 function expire(){ 1002 if(done){ return; } done=true; 1003 if(timer){ clearInterval(timer); timer=null; } 1004 if(card){ card.classList.add('cd-locked'); } 1005 panel.classList.remove('tsr-hidden'); 1006 var rb=panel.querySelector('.cd-reload'); if(rb){ try{ rb.focus(); }catch(e){} } 1007 } 1008 function tick(){ 1009 if(done){ return; } 1010 var a=active(); 1011 if(!a){ row.setAttribute('hidden',''); return; } 1012 row.removeAttribute('hidden'); 1013 if(a.dead){ expire(); return; } 1014 var now=a.srv?(Date.now()+skew):Date.now(); 1015 var rem=(a.dl-now)/1000, win=a.win/1000; 1016 var frac=Math.max(0,Math.min(1,rem/win)); 1017 arc.style.strokeDashoffset=(CIRC*(1-frac)).toFixed(2); 1018 num.textContent=fmt(rem); 1019 var t=T(), c, sk, fr=win>0?rem/win:0; 1020 if(fr<=(CFG.redFrac||0.1667)){ c='#E24B4A'; sk=t.danger; } 1021 else if(fr<=(CFG.orangeFrac||0.6667)){ c='#E6952B'; sk=t.warn; } 1022 else { c='#1D9E75'; sk=t.ok; } 1023 arc.setAttribute('stroke',c); 1024 if(state){ state.textContent=sk||''; } 1025 if(wrap){ wrap.setAttribute('aria-label',(t.label||'')+' '+fmt(rem)); } 1026 if(rem<=0 || rem<=win*(1-(CFG.preempt||0.95))){ expire(); } 1027 } 1028 try{ if(zone){ var mo=new MutationObserver(function(){ tick(); }); ['.g-recaptcha','tessera-widget'].forEach(function(s){ var el=zone.querySelector(s); if(el) mo.observe(el,{attributes:true,attributeFilter:['class']}); }); } }catch(e){} 1029 var rl2=panel.querySelector('.cd-reload'); 1030 if(rl2){ rl2.addEventListener('click',function(e){ e.preventDefault();
1031 try{ var af2=$('#account'); if(af2&&af2.value){ sessionStorage.setItem('cd_acct',af2.value); } }catch(e2){} 1032 location.reload(); 1033 }); } 1034 tick(); 1035 timer=setInterval(tick,500); 1036 }); 1037})();</script>
1037 1038</body> 1039</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.