diff --git "a/assets/main-CSyTzukZ.js" "b/assets/main-CSyTzukZ.js" new file mode 100644--- /dev/null +++ "b/assets/main-CSyTzukZ.js" @@ -0,0 +1,219 @@ +import"./modulepreload-polyfill-B5Qt9EMX.js";import{i as Jo,l as Qo,e as Xo,c as Yo,f as Zo,p as ea,g as ta,d as na,A as ra,K as Kr,h as oa,j as aa,D as Bn,b as dr,S as Sn,m as sa,k as hr,t as ia,a as ca,n as la,o as ua,r as da,_ as In}from"./preload-helper-DiAwoGSG.js";import{m as $n,D as Ln,P as fr,d as ha,b as fa,M as ma,p as pa,a as ga}from"./models-QsPq0tJ5.js";const ba="/assets/hero-DgsFBh_e.webp",Se=e=>``,re={paste:Se(''),trash:Se(''),copy:Se(''),download:Se(''),cancel:Se(''),retry:Se(''),cpu:Se(''),translate:Se(''),upload:Se(''),board:Se(''),flag:Se(''),person:Se(''),help:Se(''),pin:Se(''),file:Se(''),book:Se(''),gear:Se('')},ya=` + + +
+
+
中文0 ký tự
+ + +
+ + + + +
+
+
+
Tiếng Việt
+
+
+ + + + + +
+
+ +
+ +

Dán văn bản hoặc thả file .txt vào đây.

+ +
+ + + + +
+
+ + `,mr="'Songti SC','SimSun','Noto Serif CJK SC','Noto Serif TC',serif",va=` + + +
+
+
+ + + + + + +
+

Mặc Hi

+

Dịch truyện Trung – Việt · chạy trọn trong trình duyệt

+
+
+ + + +
+
+ +
+ +
+ + +
+ +

Chuẩn bị…

+
+
+
+

Lần đầu tải ~74 MB trọng số — + các lần sau mở nhanh nhờ bộ nhớ đệm của trình duyệt.

+
+ + + + +
+ +
+ + + + ${re.board} Bảng tốc độ + +
+ + + + + + +
+

+ +
+
+
+ +

Hướng dẫn

+

Dịch truyện Trung – Việt ngay trong trình duyệt: văn bản không rời khỏi + máy, tải model một lần rồi chạy được cả khi offline.

+
    +
  • Dịch — dán văn bản hoặc thả file .txt + (GBK / Big5 / UTF-8, tối đa 20 MB).
  • +
  • Quét tên — tìm nhân vật, địa danh, tổ chức trong văn bản; + thêm vào từ điển kèm gợi ý Hán-Việt hoặc tên Tây / Nhật.
  • +
  • Từ điển tên riêng — tên đã thêm luôn dịch đúng như bạn chọn.
  • +
  • Bộ nhớ & cài đặt — cụm đã dịch được nhớ theo từng model: + dịch lại file cũ gần như tức thì.
  • +
+

Cần trình duyệt có WebGPU (Chrome / Edge bản mới). + So tốc độ máy mình: bấm Gửi benchmark ở chân trang.

+
+ +
+
+ +

+

Không gửi nội dung văn bản — chỉ các thông số bên dưới.

+

+ + +
JSON đầy đủ sẽ gửi +
+

+
+ + +
+
+
`;function Sa(e){e.innerHTML=va;const t={};for(const n of e.querySelectorAll("[data-ref]"))t[n.dataset.ref]=n;return t}const Ye=new Map;function On(e){if(!e?.id)throw new Error("panel cần id");if(typeof e.mount!="function")throw new Error(`panel ${e.id} cần mount()`);return Ye.set(e.id,{prefers:"full",...e}),()=>{Ye.delete(e.id)}}function wa(e){return[...Ye.values()].filter(t=>t.available?!!t.available(e):!0)}const Ea=90;function ka(e,t,n){const r=()=>!matchMedia("(min-width: 900px)").matches;let a=0,o=0,s=!1;const i=()=>{s&&(s=!1,t.style.transform="",o>Ea&&n())};e.addEventListener("pointerdown",u=>{r()&&(s=!0,a=u.clientY,o=0,e.setPointerCapture?.(u.pointerId))}),e.addEventListener("pointermove",u=>{s&&(o=Math.max(0,u.clientY-a),t.style.transform=`translateY(${o}px)`)}),e.addEventListener("pointerup",i),e.addEventListener("pointercancel",i),e.addEventListener("click",()=>{const u=o;o=0,u<=4&&n()})}function Ca({tabs:e,overlay:t,rail:n=null,getState:r=()=>({})}){const a=new Map;let o=null,s=null,i=!1;const u=h=>n?.isOpen()&&h?.prefers==="side"?n:t;function l(h){let S=a.get(h.id);return S||(S=document.createElement("div"),S.className="panel-mount",a.set(h.id,S),h.mount(S)),S}function p(h){!h||!a.has(h)||(a.delete(h),Ye.get(h)?.destroy?.())}function f(h,S){const M=document.createElement("button");M.type="button",M.className=o===h.id?"ghost paneltab on":"ghost paneltab",h.icon&&M.insertAdjacentHTML("beforeend",h.icon),M.append(h.title);const C=h.badge?.(S);if(C!=null&&C!==""){const L=document.createElement("span");L.className="tabbadge",L.textContent=String(C),M.append(L)}return M.addEventListener("click",()=>{o===h.id&&u(h)===t?v():d(h.id)}),M}function m(h){e.replaceChildren(...wa(h).filter(S=>S.tab!==!1).map(S=>f(S,h)))}function d(h){const S=Ye.get(h);if(!S)return;if(o&&o!==h){const L=o,z=s;o=null,s=null,p(L),z?.body.replaceChildren()}const M=l(S),C=u(S);C.title.textContent=S.title,C.body.replaceChildren(M),C===t?t.modal.open||t.modal.showModal():t.modal.open&&(i=!0,t.modal.close(),i=!1),o=h,s=C,n?.onChange?.(C!==t),S.update?.(r()),m(r())}function v(){const h=o,S=s;o=null,s=null,p(h),S?.body.replaceChildren(),n?.onChange?.(!1),t.modal.open?t.modal.close():(n?.body.replaceChildren(),m(r()))}function y(){if(!o)return;const h=u(Ye.get(o));h!==s&&(h===t?v():d(o))}function g(){const h=r();m(h),o&&Ye.get(o)?.update?.(h)}return t.modal.addEventListener("close",()=>{if(i)return;const h=o;o=null,s=null,p(h),n?.onChange?.(!1),t.body.replaceChildren(),n?.body.replaceChildren(),m(r())}),t.modal.addEventListener("click",h=>{h.target===t.modal&&v()}),t.closeBtn.addEventListener("click",v),t.grip&&ka(t.grip,t.modal,v),{open:d,close:v,refresh:g,rehost:y,openId:()=>o}}const Ma="moxhi",xa=2,Ut="tm",jt="\0",Aa=15e4;function Vr({modelId:e,weightsTag:t,dtype:n,tokRev:r}={}){const a=[e??"unknown",t??"dev",n??"f16"];return r&&a.push(r),a.join("|")}function Na(e,t){return!!e&&!e.complete&&(e.done??0)>0&&e.file===t.file&&e.size===t.size&&e.encoding===t.encoding&&e.model===t.model}function Ta(){return new Promise((e,t)=>{const n=indexedDB.open(Ma,xa);n.onupgradeneeded=()=>{const r=n.result;r.objectStoreNames.contains(Ut)||r.createObjectStore(Ut).createIndex("ts","ts"),r.objectStoreNames.contains("partial")&&r.deleteObjectStore("partial")},n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)})}async function et(e,t){const n=await Ta();try{return await new Promise((r,a)=>{const o=n.transaction(Ut,e),s=t(o.objectStore(Ut));o.oncomplete=()=>r(typeof s=="function"?s():s),o.onerror=()=>a(o.error),o.onabort=()=>a(o.error??new Error("tx aborted"))})}finally{n.close()}}async function Pa(e,t){const n=new Array(t.length).fill(null);try{await et("readonly",r=>{t.forEach((a,o)=>{const s=r.get(e+jt+a);s.onsuccess=()=>{s.result&&(n[o]=s.result.t)}})})}catch{}return n}async function Ra(e,t){try{const n=Date.now();await et("readwrite",r=>{for(const[a,o]of t)r.put({t:o,ts:n},e+jt+a)})}catch{}}async function Ba(e=Aa){try{const t=await et("readonly",r=>{const a=r.count();return()=>a.result});if(t<=e)return;let n=t-Math.floor(e*.9);await et("readwrite",r=>{const a=r.index("ts").openCursor();a.onsuccess=()=>{const o=a.result;!o||n<=0||(o.delete(),n--,o.continue())}})}catch{}}async function Ia({sample:e=64}={}){try{const t=await et("readonly",n=>{const r=[],a=n.openKeyCursor();return a.onsuccess=()=>{const o=a.result;if(!o)return;const s=String(o.key),i=s.indexOf(jt);if(i<0)return;const u=s.slice(0,i);r.push(u),o.continue(u+"")},()=>r});return t.length?await et("readonly",n=>{const r=t.map(a=>({ns:a,rows:0,bytes:0}));return t.forEach((a,o)=>{const s=IDBKeyRange.bound(a+jt,a+"",!1,!0),i=n.count(s);i.onsuccess=()=>{r[o].rows=i.result};const u=n.getAllKeys(s,e),l=n.getAll(s,e);l.onsuccess=()=>{const p=l.result.length;if(!p)return;const f=(u.result??[]).reduce((m,d)=>m+String(d).length,0)+l.result.reduce((m,d)=>m+(d?.t?.length??0),0);r[o].bytes=Math.round(f/p*2*r[o].rows)}}),()=>r}):[]}catch{return[]}}async function $a(e){try{await et("readwrite",t=>{t.delete(IDBKeyRange.bound(e+"\0",e+"",!1,!0))})}catch{}}function La(e){const[t="",n="",r="",a=null]=String(e??"").split("|");return{model:t,weights:n,dtype:r,tokRev:a}}function Oa(e){const t=/^weights\.([0-9a-f]{6,})\./.exec(String(e??""));return t?t[1]:String(e??"")}function Fa(e){return e?e<1024?`${e} B`:e<1024*1024?`${Math.round(e/1024)} KB`:`${(e/1048576).toFixed(1)} MB`:"—"}const _a=5e3;function Da({getNamespace:e=()=>null,enabled:t=!0,onChange:n=()=>{},prefs:r=null}={}){let a=null,o=[],s=!1,i=!1,u=null,l=0;const p=()=>o.reduce((S,M)=>S+M.rows,0);async function f(){if(!s){s=!0,h();try{o=(await Ia()).sort((S,M)=>M.rows-S.rows)}catch{o=[]}i=!0,h(),n(),s=!1}}function m(){clearTimeout(l),u=null}function d(S){if(u!==S){u=S,clearTimeout(l),l=setTimeout(()=>{u=null,h()},_a),h();return}m(),$a(S).then(f)}function v(S,M="hint"){const C=document.createElement("p");return C.className=M,C.textContent=S,C}function y(S,M,C,L){const z=document.createElement("li");z.className="tmrow";const{model:G,weights:fe,dtype:me,tokRev:we}=La(S.ns),w=document.createElement("div");w.className="tmrow-main";const V=document.createElement("b");if(V.textContent=G||"(kh��ng rõ)",V.title=[Oa(fe),me,we&&`tok ${we}`].filter(Boolean).join(" · "),w.append(V),M){const J=document.createElement("span");J.className="tmcur",J.textContent="đang dùng",w.append(J)}const ge=document.createElement("span");ge.className="tmrow-meta",ge.textContent=`${S.rows.toLocaleString("vi-VN")} cụm`+(S.bytes?` · ≈ ${Fa(S.bytes)}`:"");const Ee=document.createElement("button");return Ee.type="button",Ee.className=L===S.ns?"ghost tmdanger":"ghost",Ee.textContent=L===S.ns?"Xóa thật?":"Xóa",Ee.addEventListener("click",()=>C(S.ns)),z.append(w,ge,Ee),z}function g(){const S=document.createElement("label");S.className="auto";const M=document.createElement("input");M.type="checkbox",M.id="auto-toggle",M.name="auto-toggle",M.checked=r.autoTranslate(),M.addEventListener("change",()=>r.setAutoTranslate(M.checked)),S.append(M," Tự dịch khi ngừng gõ");const C=document.createElement("hr");return C.className="panel-sep",[S,v("Chỉ với đoạn ngắn, không áp dụng khi mở file."),C]}function h(){if(!a)return;const S=e(),M=r?g():[];if(M.push(v("Cụm đã dịch được nhớ trong máy — dịch lại là có ngay.")),t||M.push(v("Phiên này đang chạy với ?tm=0 — không đọc cũng không ghi bộ nhớ.")),!i)M.push(v("đang đọc…"));else if(!o.length)M.push(v("Chưa có gì trong bộ nhớ dịch — dịch một file rồi quay lại."));else{const C=document.createElement("ul");C.className="tmlist",C.append(...o.map(L=>y(L,L.ns===S,d,u))),M.push(C),M.push(v((o.length>1?`Tổng ${p().toLocaleString("vi-VN")} cụm. `:"")+"Xóa chỉ bỏ bộ nhớ — bản dịch đang mở không mất."))}a.replaceChildren(...M)}return f(),{id:"memory",tab:!1,title:r?"Bộ nhớ & cài đặt":"Bộ nhớ dịch",prefers:"full",badge:()=>i&&p()?p().toLocaleString("vi-VN"):null,mount(S){a=S,h()},update(){m(),f()},destroy(){clearTimeout(l)}}}function Ga({store:e,onChange:t=()=>{}}={}){let n=null,r="",a=null;function o(f){const m=document.createElement("p");return m.className="hint",m.textContent=f,m}function s(){const f=document.createElement("form");f.className="glossform";const m=document.createElement("input");m.placeholder="名字 (tiếng Trung)",m.setAttribute("aria-label","Tên tiếng Trung");const d=document.createElement("input");d.placeholder="Dịch thành…",d.setAttribute("aria-label","Tên tiếng Việt");const v=document.createElement("button");return v.type="submit",v.className="ghost",v.textContent="Thêm",f.append(m,d,v),f.addEventListener("submit",y=>{y.preventDefault(),e.add({zh:m.value,vi:d.value})&&n.querySelector(".glossform input")?.focus()}),f}function i(f){const m=document.createElement("tr");f.enabled||(m.className="glossoff");const d=document.createElement("td");d.className="glosszh",d.textContent=f.zh;const v=document.createElement("td");v.textContent=f.vi;const y=document.createElement("td");y.className="num";const g=document.createElement("input");g.type="checkbox",g.checked=f.enabled,g.title=f.enabled?"Đang áp dụng — bỏ tick để tắt":"Đang tắt",g.addEventListener("change",()=>e.update(f.zh,{enabled:g.checked})),y.append(g);const h=document.createElement("td");h.className="num";const S=document.createElement("button");return S.type="button",S.className="ghost",S.textContent="Xóa",S.addEventListener("click",()=>e.remove(f.zh)),h.append(S),m.append(d,v,y,h),m}function u(f){const m=document.createElement("table");m.className="tmtable glosstable";const d=document.createElement("thead"),v=document.createElement("tr");for(const[g,h]of[["Tên gốc",""],["Dịch thành",""],["Áp","num"],["","num"]]){const S=document.createElement("th");S.className=h,S.textContent=g,v.append(S)}d.append(v);const y=document.createElement("tbody");return y.append(...f.map(i)),m.append(d,y),m}function l(){const f=document.createElement("div");f.className="glosstools";const m=document.createElement("input");m.type="file",m.accept=".json,application/json",m.hidden=!0;const d=document.createElement("button");d.type="button",d.className="ghost",d.textContent="Nhập JSON",d.addEventListener("click",()=>m.click()),m.addEventListener("change",()=>{const y=m.files[0];if(!y)return;const g=new FileReader;g.onload=()=>{try{const{added:h,updated:S}=e.importJson(String(g.result));r=`đã nhập ${h} tên mới, cập nhật ${S}`}catch(h){r=String(h?.message??h)}p()},g.readAsText(y)});const v=document.createElement("button");return v.type="button",v.className="ghost",v.textContent="Xuất JSON",v.addEventListener("click",()=>{const y=document.createElement("a");y.href=URL.createObjectURL(new Blob([e.exportJson()],{type:"application/json"})),y.download="tu-dien.json",y.click(),URL.revokeObjectURL(y.href)}),f.append(d,v,m),f}function p(){if(!n)return;const f=e.list(),m=[o("Tên trong bảng luôn được dịch đúng như bạn chọn.")];m.push(s()),f.length?m.push(u(f)):m.push(o("Chưa có tên nào — thêm ở trên, hoặc nhập từ file JSON.")),m.push(l()),r&&m.push(o(r)),n.replaceChildren(...m)}return{id:"glossary",title:"Từ điển tên riêng",icon:re.book,prefers:"full",badge:()=>e.count()||null,mount(f){n=f,a=e.subscribe(()=>{p(),t()}),p()},update(){p()},destroy(){a?.(),a=null}}}function Ua(e={}){let t={...e};const n=new Set;return{get:()=>t,set(r){const a=typeof r=="function"?r(t):{...t,...r};if(a===t)return t;t=a;for(const o of[...n])o(t);return t},subscribe(r){return n.add(r),()=>n.delete(r)}}}const ja={translate:new Set(["translate","analyze"]),analyze:new Set};function za({onStart:e,onIdle:t,onError:n}={}){const r=Ua({job:null});let a=null,o=null;const s=()=>r.get().job,i=l=>{const p=s();p&&r.set({job:{...p,...l}})};async function u(l){a=new AbortController,r.set({job:{kind:l.kind,label:l.label??"",phase:l.phase??"",done:0,total:l.total??0,cancellable:l.cancellable!==!1}}),e?.(s());try{return await l.exec({signal:a.signal,progress:i})}finally{a=null,r.set({job:null}),t?.();const p=o;o=null,p&&queueMicrotask(()=>{u(p).catch(f=>n?.(f))})}}return{run(l){const p=s();return p?ja[l.kind]?.has(p.kind)?(o=l,Promise.resolve("queued")):Promise.resolve("refused"):u(l).then(()=>"ran")},cancel(){a?.abort()},current:s,subscribe(l){return r.subscribe(()=>l(s()))}}}const Ha=/[\s:,;(\-–—…]/;function Fn(e){const t=[];let n="",r=!1;const a=o=>{n&&(t.push({text:n,q:o}),n="")};for(let o=0;oqr){e.textContent=t;return}const n=document.createDocumentFragment(),r=t.split(` +`);for(let a=0;a0&&n.appendChild(document.createTextNode(` +`));for(const o of Fn(r[a]))if(o.q){const s=document.createElement("span");s.className="dlg",s.textContent=o.text,n.appendChild(s)}else n.appendChild(document.createTextNode(o.text))}e.replaceChildren(n)}function Wa(e){const t=[],n=/[.!?…:;"”]\s+/g;let r=0;for(let a;a=n.exec(e);)t.push(e.slice(r,a.index+a[0].length)),r=a.index+a[0].length;return rFn(s).map(i=>({q:i.q,pieces:Wa(i.text)}))),a=r.reduce((s,i)=>s+i.reduce((u,l)=>u+l.pieces.length,0),0);if(n||a>Ka){Jr(e,t);return}e.replaceChildren();let o=0;for(let s=0;s0&&e.appendChild(document.createTextNode(` +`));for(const i of r[s])for(const u of i.pieces){if(!u)continue;const l=document.createElement("span");l.className=i.q?"ink-in dlg":"ink-in",l.style.animationDelay=`${Math.min(o*40,1200)}ms`,l.textContent=u,l.addEventListener("animationend",()=>{l.className=i.q?"dlg":"",l.style.animationDelay=""},{once:!0}),e.appendChild(l),o++}}}function qa(e){e&&e.addEventListener("click",t=>{const n=e.getBoundingClientRect(),r=document.createElement("span");r.className="ripple",r.style.left=`${t.clientX-n.left||n.width/2}px`,r.style.top=`${t.clientY-n.top||n.height/2}px`,e.appendChild(r),r.addEventListener("animationend",()=>r.remove())})}const Ja=[];function Qr(e,t={}){let n=e;for(const r of Ja)n=r(n,t);return n}function sn(e){return e?e.split(` +`):[]}function Qa(e){if(!e.length)return 0;let t=e.length-1;for(const n of e)t+=n.length;return t}function Xa(e){return e.length>qr?e:e.split(` +`).map(t=>Fn(t).map(n=>n.text).join("")).join(` +`)}function Ya(e,t,n={},{from:r=0,count:a=1/0,ink:o=!1,reduced:s=!1}={}){const i=Qr(t,n),u=r===0&&a===1/0?i:i.slice(r,r+a),l=u.join(` +`);return o?Va(e,l,{reduced:s}):Jr(e,l),{text:l,shown:u.length,total:i.length,chars:Qa(i)}}function _n(e,t={}){return Xa(Qr(e,t).join(` +`))}const Za=2e4;function _t(e=""){return{origin:"typed",text:e,name:null,bytes:null,encoding:null}}function Xr({name:e,bytes:t,text:n,encoding:r}){return{origin:"file",name:e,bytes:t,text:n,encoding:r}}function es(e){return e?.text?.length??0}function ts(){let e=null,t=0;return(n="")=>(n!==e&&(e=n,t+=1),t)}function ns(e){return es(e)>=Za?"long":"short"}function rs(e){return e?.origin==="file"||ns(e)==="long"}function os(e){const t=e?.origin==="file"?e.name:null;return t?`${t.replace(/\.txt$/i,"")}.vi.txt`:"mac-hi.txt"}const wn=e=>typeof e=="string"?e:"";function as({userAgent:e="",platform:t="",mobile:n,maxTouchPoints:r=0}={}){const a=wn(e),o=wn(t),s=Number.isFinite(Number(r))?Number(r):0,i=/\b(?:iPad|iPhone|iPod)\b/i.test(a)||/Mac/i.test(o)&&s>1,u=i||/Android/i.test(a)||(typeof n=="boolean"?n:/\b(?:Mobile|Mobi)\b/i.test(a));let l="unknown";return i&&/\b(?:CriOS|FxiOS|EdgiOS|OPiOS)\//i.test(a)?l="ios-other":/\bEdg(?:A|iOS)?\//i.test(a)?l="edge":/\b(?:Chrome|Chromium|CriOS)\//i.test(a)?l="chrome":/\b(?:Firefox|FxiOS)\//i.test(a)?l="firefox":/\bSafari\//i.test(a)&&/\bVersion\//i.test(a)&&(l="safari"),{browser:l,mobile:u,ios:i}}function ss(e){const t=wn(e?.message??e);return/no adapter/i.test(t)?"no-adapter":/WebGPU unavailable/i.test(t)?"missing-api":"unknown"}const ke=(e,t=null)=>({text:e,address:t});function is(e,t){const n=e==="chrome",r=n?"Chrome":"Edge",a=n?"chrome":"edge",o=`${a}://settings/system`,s=`${a}://gpu`,i=`${a}://flags/#enable-unsafe-webgpu`;return{steps:[ke(`Cập nhật ${r} lên bản mới nhất rồi mở lại trang này.`),ke(`Mở địa chỉ dưới đây, bật “Dùng tính năng tăng tốc đồ họa khi có thể”, rồi khởi động lại ${r}.`,o),ke("Sau khi khởi động lại, mở trang chẩn đoán dưới đây và kiểm tra WebGPU hiển thị “Hardware accelerated”.",s)],advanced:t==="no-adapter"?{text:`Chỉ khi ${s} báo WebGPU bị blocklist hoặc không được hỗ trợ, bạn có thể thử cờ dưới đây rồi khởi động lại ${r}. Đây là cờ thử nghiệm; hãy trả về Default nếu trình duyệt thiếu ổn định.`,address:i}:null}}function cs(e){const t=e==="edge"?"Edge":"Chrome";return{steps:[ke(`Cập nhật ${t} và Android lên phiên bản mới nhất.`),ke("Với Chrome, cấu hình phổ biến cần Chrome 121+ và Android 12+; WebGPU vẫn phụ thuộc GPU và driver được thiết bị hỗ trợ."),ke(`Đóng hẳn ${t}, mở lại trang này rồi bấm “Kiểm tra lại”.`),ke("Nếu vẫn không kết nối được GPU, hãy thử Chrome mới nhất hoặc một thiết bị WebGPU khác.")],advanced:null}}function ls(e){return{steps:[ke(`Cập nhật hệ điều hành trên ${e?"iPhone/iPad":"máy Mac"} để có Safari 26+.`),ke("Đóng hẳn Safari, mở lại trang này rồi bấm “Kiểm tra lại”."),ke("Nếu vẫn không kết nối được GPU, thiết bị hoặc phiên bản hệ điều hành hiện tại có thể chưa cung cấp adapter WebGPU phù hợp.")],advanced:null}}function us(){return{steps:[ke("Cập nhật iOS/iPadOS và Safari lên phiên bản mới nhất."),ke("Sao chép địa chỉ trang này và mở lại bằng Safari 26+."),ke("Trong Safari, bấm “Kiểm tra lại” để thử kết nối GPU.")],advanced:null}}function ds(e){return{steps:[ke("Cập nhật trình duyệt và hệ điều hành lên phiên bản mới nhất."),ke("Mở trang này bằng Chrome hoặc Edge mới nhất trên máy tính/Android, hoặc Safari 26+ trên thiết bị Apple."),ke(e==="firefox"?"Firefox chưa nằm trong cấu hình được ứng dụng kiểm thử; hãy thử một trình duyệt được liệt kê ở trên.":"Nếu trình duyệt hiện tại vẫn không có WebGPU, hãy thử một thiết bị hoặc trình duyệt được liệt kê ở trên.")],advanced:null}}function hs({userAgent:e="",platform:t="",mobile:n,maxTouchPoints:r=0,message:a=""}={}){const o=as({userAgent:e,platform:t,mobile:n,maxTouchPoints:r}),s=ss(a),i=s==="no-adapter"?"Trình duyệt có WebGPU nhưng chưa kết nối được với GPU phù hợp.":s==="missing-api"?"Trình duyệt chưa cung cấp WebGPU cho trang này.":"Trình duyệt chưa khởi tạo được WebGPU.";let u;return(o.browser==="chrome"||o.browser==="edge")&&o.mobile?u=cs(o.browser):o.browser==="chrome"||o.browser==="edge"?u=is(o.browser,s):o.browser==="safari"?u=ls(o.mobile):o.browser==="ios-other"?u=us():u=ds(o.browser),{...o,failureKind:s,summary:i,...u}}const pr=200,gr=/[。。.!!??;;…]/,fs=/[”’』」)〉》"')\]]/,ms=/[,、,]/;function ps(e){const t=[];let n=0;for(let a=0;a=0?n+1:pr,a=e.slice(0,r).trim(),o=e.slice(r).trim();return[...a?En(a):[],...o?En(o):[]]}function Yr(e){const t=[],n=[];for(const r of e.split(` +`)){let a=0;for(const o of ps(r))for(const s of En(o))t.push(s),a++;n.push(a)}return{sentences:t,paras:n}}function gs(e,t,n=200){const r=[],a=[];let o=0;for(const s of t){let i="",u=0;for(let l=0;ln&&(r.push(i),u++,i=""),i+=p}i&&(r.push(i),u++),o+=s,a.push(u)}return{rows:r,rowParas:a}}function bs(e,t){const n=[];let r=0;for(const a of e)n.push(t.slice(r,r+a).join(" ").trim()),r+=a;return n.join(` +`)}const ys={㑯:"㑔",㑳:"㑇",㑶:"㐹",㓨:"刾",㗲:"𠵾",㘚:"㘎",㜄:"㚯",㜏:"㛣",㜢:"𡞱",㠏:"㟆",㠣:"𫵷",㥮:"㤘",㩜:"㨫",㩳:"㧐",㩵:"擜",㺏:"𤠋",䁪:"𥇢",䁻:"䀥",䃮:"鿎",䊷:"䌶",䋙:"䌺",䋚:"䌻",䋹:"䌿",䋻:"䌾",䍦:"䍠",䎱:"䎬",䓣:"𬜯",䙡:"䙌",䜀:"䜧",䝼:"䞍",䡵:"𫟦",䥇:"䦂",䥑:"鿏",䥕:"𬭯",䥱:"䥾",䦛:"䦶",䦟:"䦷",䧢:"𨸟",䮄:"𫠊",䯀:"䯅",䰾:"鲃",䱷:"䲣",䱽:"䲝",䲁:"鳚",䲘:"鳤",䴉:"鹮",丟:"丢",並:"并",乾:"干",亂:"乱",亙:"亘",亞:"亚",佇:"伫",佈:"布",佔:"占",併:"并",來:"来",侖:"仑",侶:"侣",侷:"局",俁:"俣",係:"系",俔:"伣",俠:"侠",俥:"伡",俬:"私",倀:"伥",倆:"俩",倈:"俫",倉:"仓",個:"个",們:"们",倖:"幸",倫:"伦",倲:"㑈",偉:"伟",偑:"㐽",側:"侧",偵:"侦",偽:"伪",傌:"㐷",傑:"杰",傖:"伧",傘:"���",備:"备",傢:"家",傭:"佣",傯:"偬",傳:"传",傴:"伛",債:"债",傷:"伤",傾:"倾",僂:"偻",僅:"仅",僉:"佥",僑:"侨",僕:"仆",僞:"伪",僤:"𫢸",僥:"侥",僨:"偾",僱:"雇",價:"价",儀:"仪",儁:"俊",儂:"侬",億:"亿",儈:"侩",儉:"俭",儎:"傤",儐:"傧",儔:"俦",儕:"侪",儘:"尽",償:"偿",優:"优",儲:"储",儷:"俪",儸:"㑩",儺:"傩",儻:"傥",儼:"俨",兇:"凶",兌:"兑",兒:"儿",兗:"兖",內:"内",兩:"两",冊:"册",冑:"胄",冪:"幂",凈:"净",凍:"冻",凜:"凛",凱:"凯",別:"别",刪:"删",剄:"刭",則:"则",剋:"克",剎:"刹",剗:"刬",剛:"刚",剝:"剥",剮:"剐",剴:"剀",創:"创",剷:"铲",劃:"划",劄:"札",劇:"剧",劉:"刘",劊:"刽",劌:"刿",劍:"剑",劏:"㓥",劑:"剂",劚:"㔉",勁:"劲",動:"动",務:"务",勛:"勋",勝:"胜",勞:"劳",勢:"势",勣:"𪟝",勩:"勚",勱:"劢",勳:"勋",勵:"励",勸:"劝",勻:"匀",匭:"匦",匯:"汇",匱:"匮",區:"区",協:"协",卹:"恤",卻:"却",卽:"即",厙:"厍",厠:"厕",厤:"历",厭:"厌",厲:"厉",厴:"厣",參:"参",叄:"叁",叢:"丛",吒:"咤",吳:"吴",吶:"呐",呂:"吕",咼:"呙",員:"员",唄:"呗",唸:"念",問:"问",啓:"启",啞:"哑",啟:"启",啢:"唡",喎:"㖞",喚:"唤",喪:"丧",喫:"吃",喬:"乔",單:"单",喲:"哟",嗆:"呛",嗇:"啬",嗊:"唝",嗎:"吗",嗚:"呜",嗩:"唢",嗰:"𠮶",嗶:"哔",嘆:"叹",嘍:"喽",嘓:"啯",嘔:"呕",嘖:"啧",嘗:"尝",嘜:"唛",嘩:"哗",嘮:"唠",嘯:"啸",嘰:"叽",嘵:"哓",嘸:"呒",嘽:"啴",噁:"恶",噓:"嘘",噚:"㖊",噝:"咝",噠:"哒",噥:"哝",噦:"哕",噯:"嗳",噲:"哙",噴:"喷",噸:"吨",噹:"当",嚀:"咛",嚇:"吓",嚌:"哜",嚐:"尝",嚕:"噜",嚙:"啮",嚥:"咽",嚦:"呖",嚧:"𠰷",嚨:"咙",嚮:"向",嚲:"亸",嚳:"喾",嚴:"严",嚶:"嘤",囀:"啭",囁:"嗫",囂:"嚣",囅:"冁",囈:"呓",囉:"啰",囌:"苏",囑:"嘱",囪:"囱",圇:"囵",國:"国",圍:"围",園:"园",圓:"圆",圖:"图",團:"团",垻:"坝",埡:"垭",埨:"𫭢",埰:"采",執:"执",堅:"坚",堊:"垩",堖:"垴",堝:"埚",堯:"尧",報:"报",場:"场",塊:"块",塋:"茔",塏:"垲",塒:"埘",塗:"涂",塚:"冢",塢:"坞",塤:"埙",塵:"尘",塸:"𫭟",塹:"堑",塿:"𪣻",墊:"垫",墜:"坠",墠:"𫮃",墮:"堕",墰:"坛",墳:"坟",墶:"垯",墻:"墙",墾:"垦",壇:"坛",壋:"垱",壎:"埙",壓:"压",壗:"𡋤",壘:"垒",壙:"圹",壚:"垆",壜:"坛",壞:"坏",壟:"垄",壠:"垅",壢:"坜",壩:"坝",壪:"塆",壯:"壮",壺:"壶",壼:"壸",壽:"寿",夠:"够",夢:"梦",夥:"伙",夾:"夹",奐:"奂",奧:"奥",奩:"奁",奪:"夺",奬:"奖",奮:"奋",奼:"姹",妝:"妆",姍:"姗",姦:"奸",娙:"𫰛",娛:"娱",婁:"娄",婦:"妇",婭:"娅",媧:"娲",媯:"妫",媰:"㛀",媼:"媪",媽:"妈",嫋:"袅",嫗:"妪",嫵:"妩",嫺:"娴",嫻:"娴",嫿:"婳",嬀:"妫",嬃:"媭",嬈:"娆",嬋:"婵",嬌:"娇",嬙:"嫱",嬡:"嫒",嬤:"嬷",嬪:"嫔",嬰:"婴",嬸:"婶",孃:"娘",孋:"㛤",孌:"娈",孫:"孙",學:"学",孻:"𡥧",孿:"孪",宮:"宫",寀:"采",寢:"寝",實:"实",寧:"宁",審:"审",寫:"写",寬:"宽",寵:"宠",寶:"宝",將:"将",專:"专",尋:"寻",對:"对",導:"导",尷:"尴",屆:"届",屍:"尸",屓:"屃",屜:"屉",屢:"屡",層:"层",屨:"屦",屬:"属",岡:"冈",峯:"峰",峴:"岘",島:"岛",峽:"峡",崍:"崃",崑:"昆",崗:"岗",崙:"仑",崢:"峥",崬:"岽",嵐:"岚",嵗:"岁",嵽:"𫶇",嵾:"㟥",嶁:"嵝",嶄:"崭",嶇:"岖",嶔:"嵚",嶗:"崂",嶠:"峤",嶢:"峣",嶧:"峄",嶨:"峃",嶮:"崄",嶸:"嵘",嶺:"岭",嶼:"屿",嶽:"岳",巋:"岿",巒:"峦",巔:"巅",巖:"岩",巘:"𪩘",巰:"巯",巹:"卺",帥:"帅",師:"师",帳:"帐",帶:"带",幀:"帧",幃:"帏",幓:"㡎",幗:"帼",幘:"帻",幟:"帜",幣:"币",幫:"帮",幬:"帱",幷:"并",幹:"干",幾:"几",庫:"库",廁:"厕",廂:"厢",廄:"厩",廈:"厦",廎:"庼",廕:"荫",廚:"厨",廝:"厮",廞:"𫷷",廟:"庙",廠:"厂",廡:"庑",廢:"废",廣:"广",廩:"廪",廬:"庐",廳:"厅",弒:"弑",弔:"吊",弳:"弪",張:"张",強:"强",彄:"𫸩",彆:"别",彈:"弹",彌:"弥",彎:"弯",彔:"录",彙:"汇",彠:"彟",彥:"彦",彫:"雕",彲:"彨",彿:"佛",後:"后",徑:"径",從:"从",徠:"徕",復:"复",徵:"征",徹:"彻",恆:"恒",恥:"耻",悅:"悦",悞:"悮",悵:"怅",悶:"闷",悽:"凄",惡:"恶",惱:"恼",惲:"恽",惻:"恻",愛:"爱",愜:"惬",愨:"悫",愴:"怆",愷:"恺",愾:"忾",慄:"栗",態:"态",慍:"愠",慘:"惨",慚:"惭",慟:"恸",慣:"惯",慤:"悫",慪:"怄",慫:"怂",慮:"虑",慳:"悭",慶:"庆",慺:"㥪",慼:"戚",慾:"欲",憂:"忧",憊:"惫",憐:"怜",憑:"凭",憒:"愦",憖:"慭",憚:"惮",憤:"愤",憫:"悯",憮:"怃",憲:"宪",憶:"忆",懇:"恳",應:"应",懌:"怿",懍:"懔",懞:"蒙",懟:"怼",懣:"懑",懤:"㤽",懨:"恹",懲:"惩",懶:"懒",懷:"怀",懸:"悬",懺:"忏",懼:"惧",懾:"慑",戀:"恋",戇:"戆",戔:"戋",戧:"戗",戩:"戬",戰:"战",戱:"戯",戲:"戏",戶:"户",扞:"捍",拋:"抛",拚:"拼",挩:"捝",挱:"挲",挾:"挟",捨:"舍",捫:"扪",捱:"挨",捲:"卷",掃:"扫",掄:"抡",掆:"㧏",掗:"挜",掙:"挣",掛:"挂",採:"采",揀:"拣",揚:"扬",換:"换",揮:"挥",揯:"搄",損:"损",搖:"摇",搗:"捣",搧:"扇",搵:"揾",搶:"抢",摑:"掴",摜:"掼",摟:"搂",���:"挚",摳:"抠",摶:"抟",摺:"折",摻:"掺",撈:"捞",撏:"挦",撐:"撑",撓:"挠",撝:"㧑",撟:"挢",撣:"掸",撥:"拨",撫:"抚",撲:"扑",撳:"揿",撻:"挞",撾:"挝",撿:"捡",擁:"拥",擄:"掳",擇:"择",擊:"击",擋:"挡",擓:"㧟",擔:"担",據:"据",擠:"挤",擡:"抬",擣:"捣",擬:"拟",擯:"摈",擰:"拧",擱:"搁",擲:"掷",擴:"扩",擷:"撷",擺:"摆",擻:"擞",擼:"撸",擽:"㧰",擾:"扰",攄:"摅",攆:"撵",攏:"拢",攔:"拦",攖:"撄",攙:"搀",攛:"撺",攜:"携",攝:"摄",攢:"攒",攣:"挛",攤:"摊",攪:"搅",攬:"揽",敎:"教",敓:"敚",敗:"败",敘:"叙",敵:"敌",數:"数",斂:"敛",斃:"毙",斆:"敩",斕:"斓",斬:"斩",斷:"断",於:"于",旂:"旗",旣:"既",昇:"升",時:"时",晉:"晋",晛:"𬀪",晝:"昼",暈:"晕",暉:"晖",暐:"𬀩",暘:"旸",暢:"畅",暫:"暂",曄:"晔",曆:"历",曇:"昙",曉:"晓",曏:"向",曖:"暧",曠:"旷",曥:"𣆐",曨:"昽",曬:"晒",書:"书",會:"会",朥:"𦛨",朧:"胧",朮:"术",東:"东",枴:"拐",柵:"栅",柺:"拐",査:"查",桱:"𣐕",桿:"杆",梔:"栀",梘:"枧",梜:"𬂩",條:"条",梟:"枭",梲:"棁",棄:"弃",棊:"棋",棖:"枨",棗:"枣",棟:"栋",棡:"㭎",棧:"栈",棲:"栖",棶:"梾",椏:"桠",椲:"㭏",楊:"杨",楓:"枫",楨:"桢",業:"业",極:"极",榘:"矩",榦:"干",榪:"杩",榮:"荣",榲:"榅",榿:"桤",構:"构",槍:"枪",槓:"杠",槤:"梿",槧:"椠",槨:"椁",槮:"椮",槳:"桨",槶:"椢",槼:"椝",樁:"桩",樂:"乐",樅:"枞",樑:"梁",樓:"楼",標:"标",樞:"枢",樢:"㭤",樣:"样",樧:"榝",樫:"㭴",樳:"桪",樸:"朴",樹:"树",樺:"桦",樿:"椫",橈:"桡",橋:"桥",機:"机",橢:"椭",橫:"横",橯:"𣓿",檁:"檩",檉:"柽",檔:"档",檜:"桧",檟:"槚",檢:"检",檣:"樯",檮:"梼",檯:"台",檳:"槟",檸:"柠",檻:"槛",櫃:"柜",櫍:"𬃊",櫓:"橹",櫚:"榈",櫛:"栉",櫝:"椟",櫞:"橼",櫟:"栎",櫥:"橱",櫧:"槠",櫨:"栌",櫪:"枥",櫫:"橥",櫬:"榇",櫱:"蘖",櫳:"栊",櫸:"榉",櫻:"樱",欄:"栏",欅:"榉",權:"权",欏:"椤",欒:"栾",欓:"𣗋",欖:"榄",欞:"棂",欽:"钦",歎:"叹",歐:"欧",歟:"欤",歡:"欢",歲:"岁",歷:"历",歸:"归",歿:"殁",殘:"残",殞:"殒",殤:"殇",殨:"㱮",殫:"殚",殭:"僵",殮:"殓",殯:"殡",殰:"㱩",殲:"歼",殺:"杀",殻:"壳",殼:"壳",毀:"毁",毆:"殴",毿:"毵",氂:"牦",氈:"毡",氌:"氇",氣:"气",氫:"氢",氬:"氩",氳:"氲",氾:"泛",汎:"泛",汙:"污",決:"决",沒:"没",沖:"冲",況:"况",泝:"溯",洩:"泄",洶:"汹",浹:"浃",浿:"𬇙",涇:"泾",涗:"涚",涼:"凉",淒:"凄",淚:"泪",淥:"渌",淨:"净",淩:"凌",淪:"沦",淵:"渊",淶:"涞",淺:"浅",渙:"涣",減:"减",渢:"沨",渦:"涡",測:"测",渾:"浑",湊:"凑",湋:"𣲗",湞:"浈",湧:"涌",湯:"汤",溈:"沩",準:"准",溝:"沟",溫:"温",溮:"浉",溳:"涢",溼:"湿",滄:"沧",滅:"灭",滌:"涤",滎:"荥",滙:"汇",滬:"沪",滯:"滞",滲:"渗",滷:"卤",滸:"浒",滻:"浐",滾:"滚",滿:"满",漁:"渔",漊:"溇",漍:"𬇹",漚:"沤",漢:"汉",漣:"涟",漬:"渍",漲:"涨",漵:"溆",漸:"渐",漿:"浆",潁:"颍",潑:"泼",潔:"洁",潕:"𣲘",潙:"沩",潚:"㴋",潛:"潜",潤:"润",潯:"浔",潰:"溃",潷:"滗",潿:"涠",澀:"涩",澆:"浇",澇:"涝",澐:"沄",澗:"涧",澠:"渑",澤:"泽",澦:"滪",澩:"泶",澫:"𬇕",澮:"浍",澱:"淀",澾:"㳠",濁:"浊",濃:"浓",濄:"㳡",濆:"𣸣",濕:"湿",濘:"泞",濚:"溁",濛:"蒙",濜:"浕",濟:"济",濤:"涛",濧:"㳔",濫:"滥",濰:"潍",濱:"滨",濺:"溅",濼:"泺",濾:"滤",瀂:"澛",瀅:"滢",瀆:"渎",瀇:"㲿",瀉:"泻",瀋:"沈",瀏:"浏",瀕:"濒",瀘:"泸",瀝:"沥",瀟:"潇",瀠:"潆",瀦:"潴",瀧:"泷",瀨:"濑",瀰:"弥",瀲:"潋",瀾:"澜",灃:"沣",灄:"滠",灑:"洒",灒:"𪷽",灕:"漓",灘:"滩",灙:"𣺼",灝:"灏",灡:"㳕",灣:"湾",灤:"滦",灧:"滟",灩:"滟",災:"灾",為:"为",烏:"乌",烴:"烃",無:"无",煉:"炼",煒:"炜",煙:"烟",煢:"茕",煥:"焕",煩:"烦",煬:"炀",煱:"㶽",熅:"煴",熒:"荧",熗:"炝",熰:"𬉼",熱:"热",熲:"颎",熾:"炽",燀:"𬊤",燁:"烨",燈:"灯",燉:"炖",燒:"烧",燖:"𬊈",燙:"烫",燜:"焖",營:"营",燦:"灿",燬:"毁",燭:"烛",燴:"烩",燶:"㶶",燻:"熏",燼:"烬",燾:"焘",爍:"烁",爐:"炉",爛:"烂",爭:"争",爲:"为",爺:"爷",爾:"尔",牀:"床",牆:"墙",牘:"牍",牴:"抵",牽:"牵",犖:"荦",犛:"牦",犢:"犊",犧:"牺",狀:"状",狹:"狭",狽:"狈",猙:"狰",猶:"犹",猻:"狲",獁:"犸",獃:"呆",獄:"狱",獅:"狮",獎:"奖",獨:"独",獪:"狯",獫:"猃",獮:"狝",獰:"狞",獱:"㺍",獲:"获",獵:"猎",獷:"犷",獸:"兽",獺:"獭",獻:"献",獼:"猕",玀:"猡",現:"现",琱:"雕",琺:"珐",琿:"珲",瑋:"玮",瑒:"玚",瑣:"琐",瑤:"瑶",瑩:"莹",瑪:"玛",瑲:"玱",璉:"琏",璊:"𫞩",璕:"𬍤",璗:"𬍡",璡:"琎",璣:"玑",璦:"瑷",璫:"珰",璯:"㻅",環:"环",璵:"玙",璸:"瑸",璽:"玺",璿:"璇",瓅:"𬍛",瓊:"琼",瓏:"珑",瓔:"璎",瓚:"瓒",瓛:"𤩽",甌:"瓯",甕:"瓮",產:"产",産:"产",畝:"亩",畢:"毕",畫:"画",異:"异",畵:"画",當:"当",疇:"畴",疊:"叠",痙:"痉",痠:"酸",痾:"疴",瘂:"痖",瘋:"疯",瘍:"疡",瘓:"痪",瘞:"瘗",瘡:"疮",瘧:"疟",瘮:"瘆",瘲:"疭",瘺:"瘘",瘻:"瘘",療:"���",癆:"痨",癇:"痫",癉:"瘅",癒:"愈",癘:"疠",癟:"瘪",癡:"痴",癢:"痒",癤:"疖",癥:"症",癧:"疬",癩:"癞",癬:"癣",癭:"瘿",癮:"瘾",癰:"痈",癱:"瘫",癲:"癫",發:"发",皁:"皂",皚:"皑",皰:"疱",皸:"皲",皺:"皱",盃:"杯",盜:"盗",盞:"盏",盡:"尽",監:"监",盤:"盘",盧:"卢",盪:"荡",眞:"真",眥:"眦",眾:"众",睍:"𪾢",睏:"困",睜:"睁",睞:"睐",瞘:"眍",瞜:"䁖",瞞:"瞒",瞶:"瞆",瞼:"睑",矇:"蒙",矓:"眬",矚:"瞩",矯:"矫",硃:"朱",硜:"硁",硤:"硖",硨:"砗",硯:"砚",碕:"埼",碩:"硕",碭:"砀",碸:"砜",確:"确",碼:"码",碽:"䂵",磑:"硙",磚:"砖",磠:"硵",磣:"碜",磧:"碛",磯:"矶",磽:"硗",磾:"䃅",礄:"硚",礎:"础",礐:"𬒈",礙:"碍",礦:"矿",礪:"砺",礫:"砾",礬:"矾",礱:"砻",祕:"秘",祿:"禄",禍:"祸",禎:"祯",禕:"祎",禡:"祃",禦:"御",禪:"禅",禮:"礼",禰:"祢",禱:"祷",禿:"秃",秈:"籼",稅:"税",稈:"秆",稏:"䅉",稜:"棱",稟:"禀",種:"种",稱:"称",穀:"谷",穇:"䅟",穌:"稣",積:"积",穎:"颖",穠:"秾",穡:"穑",穢:"秽",穩:"稳",穫:"获",穭:"穞",窩:"窝",窪:"洼",窮:"穷",窯:"窑",窵:"窎",窶:"窭",窺:"窥",竄:"窜",竅:"窍",竇:"窦",竈:"灶",竊:"窃",竪:"竖",競:"竞",筆:"笔",筍:"笋",筧:"笕",筴:"䇲",箇:"个",箋:"笺",箏:"筝",箚:"札",節:"节",範:"范",築:"筑",篋:"箧",篔:"筼",篠:"筿",篢:"𬕂",篤:"笃",篩:"筛",篳:"筚",篸:"𥮾",簀:"箦",簍:"篓",簑:"蓑",簞:"箪",簡:"简",簣:"篑",簫:"箫",簹:"筜",簽:"签",簾:"帘",籃:"篮",籅:"𥫣",籌:"筹",籔:"䉤",籙:"箓",籛:"篯",籜:"箨",籟:"籁",籠:"笼",籤:"签",籩:"笾",籪:"簖",籬:"篱",籮:"箩",籲:"吁",粵:"粤",糉:"粽",糝:"糁",糞:"粪",糧:"粮",糰:"团",糲:"粝",糴:"籴",糶:"粜",糹:"纟",糾:"纠",紀:"纪",紂:"纣",紃:"𬘓",約:"约",紅:"红",紆:"纡",紇:"纥",紈:"纨",紉:"纫",紋:"纹",納:"纳",紐:"纽",紓:"纾",純:"纯",紕:"纰",紖:"纼",紗:"纱",紘:"纮",紙:"纸",級:"级",紛:"纷",紜:"纭",紝:"纴",紞:"𬘘",紡:"纺",紬:"䌷",紮:"扎",細:"细",紱:"绂",紲:"绁",紳:"绅",紵:"纻",紹:"绍",紺:"绀",紼:"绋",紿:"绐",絀:"绌",終:"终",絃:"弦",組:"组",絅:"䌹",絆:"绊",絎:"绗",結:"结",絕:"绝",絛:"绦",絝:"绔",絞:"绞",絡:"络",絢:"绚",給:"给",絨:"绒",絪:"𬘡",絰:"绖",統:"统",絲:"丝",絳:"绛",絶:"绝",絹:"绢",絺:"𫄨",綁:"绑",綃:"绡",綄:"𬘫",綆:"绠",綈:"绨",綉:"绣",綌:"绤",綎:"𬘩",綏:"绥",綐:"䌼",綑:"捆",經:"经",綖:"𫄧",綜:"综",綝:"𬘭",綞:"缍",綠:"绿",綡:"𫟅",綢:"绸",綣:"绻",綧:"𬘯",綪:"𬘬",綫:"线",綬:"绶",維:"维",綯:"绹",綰:"绾",綱:"纲",網:"网",綳:"绷",綴:"缀",綵:"彩",綸:"纶",綹:"绺",綺:"绮",綻:"绽",綽:"绰",綾:"绫",綿:"绵",緄:"绲",緇:"缁",緊:"紧",緋:"绯",緑:"绿",緒:"绪",緓:"绬",緔:"绱",緗:"缃",緘:"缄",緙:"缂",線:"线",緝:"缉",緞:"缎",締:"缔",緡:"缗",緣:"缘",緦:"缌",編:"编",緩:"缓",緬:"缅",緯:"纬",緱:"缑",緲:"缈",練:"练",緶:"缏",緹:"缇",緻:"致",緼:"缊",縈:"萦",縉:"缙",縊:"缢",縋:"缒",縐:"绉",縑:"缣",縕:"缊",縗:"缞",縛:"缚",縝:"缜",縞:"缟",縟:"缛",縣:"县",縧:"绦",縫:"缝",縭:"缡",縮:"缩",縯:"𬙂",縱:"纵",縲:"缧",縳:"䌸",縴:"纤",縵:"缦",縶:"絷",縷:"缕",縹:"缥",總:"总",績:"绩",繃:"绷",繅:"缫",繆:"缪",繒:"缯",織:"织",繕:"缮",繚:"缭",繞:"绕",繡:"绣",繢:"缋",繩:"绳",繪:"绘",繫:"系",繭:"茧",繮:"缰",繯:"缳",繰:"缲",繳:"缴",繶:"𫄷",繸:"䍁",繹:"绎",繻:"𦈡",繼:"继",繽:"缤",繾:"缱",繿:"䍀",纁:"𫄸",纆:"𬙊",纇:"颣",纈:"缬",纊:"纩",續:"续",纍:"累",纏:"缠",纓:"缨",纔:"才",纕:"𬙋",纖:"纤",纘:"缵",纜:"缆",缽:"钵",罃:"䓨",罈:"坛",罌:"罂",罎:"坛",罰:"罚",罵:"骂",罷:"罢",羅:"罗",羆:"罴",羈:"羁",羋:"芈",羣:"群",羥:"羟",羨:"羡",義:"义",羶:"膻",習:"习",翫:"玩",翬:"翚",翹:"翘",翽:"翙",耬:"耧",耮:"耢",聖:"圣",聞:"闻",聯:"联",聰:"聪",聲:"声",聳:"耸",聵:"聩",聶:"聂",職:"职",聹:"聍",聽:"听",聾:"聋",肅:"肃",脅:"胁",脈:"脉",脛:"胫",脣:"唇",脩:"修",脫:"脱",脹:"胀",腎:"肾",腖:"胨",腡:"脶",腦:"脑",腫:"肿",腳:"脚",腸:"肠",膃:"腽",膕:"腘",膚:"肤",膞:"䏝",膠:"胶",膢:"𦝼",膩:"腻",膽:"胆",膾:"脍",膿:"脓",臉:"脸",臍:"脐",臏:"膑",臘:"腊",臚:"胪",臟:"脏",臠:"脔",臢:"臜",臥:"卧",臨:"临",臺:"台",與:"与",興:"兴",舉:"举",舊:"旧",舖:"铺",舘:"馆",艙:"舱",艤:"舣",艦:"舰",艫:"舻",艱:"艰",艷:"艳",芻:"刍",苧:"苎",茲:"兹",荊:"荆",莊:"庄",莖:"茎",莢:"荚",莧:"苋",華:"华",菴:"庵",菸:"烟",萇:"苌",萊:"莱",萬:"万",萴:"荝",萵:"莴",葉:"叶",葒:"荭",葤:"荮",葦:"苇",葯:"药",葷:"荤",蒍:"𫇭",蒐:"搜",蒓:"莼",蒔:"莳",蒕:"蒀",蒞:"莅",蒼:"苍",蓀:"荪",蓆:"席",蓋:"盖",蓮:"莲",蓯:"苁",蓴:"莼",蓽:"荜",蔄:"𬜬",蔔:"卜",蔘:"参",蔞:"蒌",蔣:"蒋",蔥:"葱",蔦:"茑",蔭:"荫",蔯:"𫈟",蔿:"𫇭",蕁:"荨",蕆:"蒇",蕎:"荞",蕒:"荬",蕓:"芸",蕕:"莸",蕘:"荛",蕢:"蒉",蕩:"荡",蕪:"芜",蕭:"萧",蕷:"蓣",薀:"蕰",薈:"荟",薊:"蓟",薌:"芗",薑:"姜",薔:"蔷",薘:"荙",薟:"莶",薦:"荐",薩:"萨",薳:"䓕",薴:"苧",薵:"䓓",薹:"苔",薺:"荠",藍:"蓝",藎:"荩",藝:"艺",藥:"药",藪:"薮",藭:"䓖",藴:"蕴",藶:"苈",藹:"蔼",藺:"蔺",蘀:"萚",蘄:"蕲",蘆:"芦",蘇:"苏",蘊:"蕴",蘋:"苹",蘚:"藓",蘞:"蔹",蘟:"𦻕",蘢:"茏",蘭:"兰",蘺:"蓠",蘿:"萝",虆:"蔂",虉:"𬟁",處:"处",虛:"虚",虜:"虏",號:"号",虧:"亏",虯:"虬",蛺:"蛱",蛻:"蜕",蜆:"蚬",蝀:"𬟽",蝕:"蚀",蝟:"猬",蝦:"虾",蝨:"虱",蝸:"蜗",螄:"蛳",螞:"蚂",螢:"萤",螮:"䗖",螻:"蝼",螿:"螀",蟄:"蛰",蟈:"蝈",蟎:"螨",蟣:"虮",蟬:"蝉",蟯:"蛲",蟲:"虫",蟳:"𫊻",蟶:"蛏",蟻:"蚁",蠁:"蚃",蠅:"蝇",蠆:"虿",蠍:"蝎",蠐:"蛴",蠑:"蝾",蠔:"蚝",蠟:"蜡",蠣:"蛎",蠨:"蟏",蠱:"蛊",蠶:"蚕",蠻:"蛮",衆:"众",衊:"蔑",術:"术",衕:"同",衚:"胡",衛:"卫",衝:"冲",袞:"衮",袷:"夹",裊:"袅",裏:"里",補:"补",裝:"装",裡:"里",製:"制",複:"复",褌:"裈",褘:"袆",褲:"裤",褳:"裢",褸:"褛",褻:"亵",襀:"𫌀",襇:"裥",襉:"裥",襏:"袯",襖:"袄",襝:"裣",襠:"裆",襤:"褴",襪:"袜",襬:"摆",襯:"衬",襲:"袭",襴:"襕",覈:"核",見:"见",覎:"觃",規:"规",覓:"觅",視:"视",覘:"觇",覡:"觋",覥:"觍",覦:"觎",親:"亲",覬:"觊",覯:"觏",覲:"觐",覷:"觑",覺:"觉",覽:"览",覿:"觌",觀:"观",觴:"觞",觶:"觯",觸:"触",訁:"讠",訂:"订",訃:"讣",計:"计",訊:"讯",訌:"讧",討:"讨",訏:"𬣙",訐:"讦",訒:"讱",訓:"训",訕:"讪",訖:"讫",託:"托",記:"记",訛:"讹",訝:"讶",訟:"讼",訢:"䜣",訣:"诀",訥:"讷",訩:"讻",訪:"访",設:"设",許:"许",訴:"诉",訶:"诃",診:"诊",註:"注",証:"证",詀:"𧮪",詁:"诂",詆:"诋",詎:"讵",詐:"诈",詒:"诒",詔:"诏",評:"评",詖:"诐",詗:"诇",詘:"诎",詛:"诅",詝:"𬣞",詞:"词",詠:"咏",詡:"诩",詢:"询",詣:"诣",試:"试",詩:"诗",詪:"𬣳",詫:"诧",詬:"诟",詭:"诡",詮:"诠",詰:"诘",話:"话",該:"该",詳:"详",詵:"诜",詷:"𫍣",詼:"诙",詿:"诖",誄:"诔",誅:"诛",誆:"诓",誇:"夸",誌:"志",認:"认",誑:"诳",誒:"诶",誕:"诞",誘:"诱",誚:"诮",語:"语",誠:"诚",誡:"诫",誣:"诬",誤:"误",誥:"诰",誦:"诵",誨:"诲",說:"说",説:"说",誰:"谁",課:"课",誶:"谇",誹:"诽",誼:"谊",誾:"訚",調:"调",諂:"谄",諄:"谆",談:"谈",諉:"诿",請:"请",諍:"诤",諏:"诹",諑:"诼",諒:"谅",諓:"𬣡",論:"论",諗:"谂",諛:"谀",諜:"谍",諝:"谞",諞:"谝",諟:"𬤊",諡:"谥",諢:"诨",諤:"谔",諦:"谛",諧:"谐",諫:"谏",諭:"谕",諮:"咨",諱:"讳",諲:"𬤇",諳:"谙",諴:"𫍯",諶:"谌",諷:"讽",諸:"诸",諺:"谚",諼:"谖",諾:"诺",謀:"谋",謁:"谒",謂:"谓",謄:"誊",謅:"诌",謊:"谎",謎:"谜",謏:"𫍲",謐:"谧",謔:"谑",謖:"谡",謗:"谤",謙:"谦",謚:"谥",講:"讲",謝:"谢",謠:"谣",謡:"谣",謨:"谟",謫:"谪",謬:"谬",謭:"谫",謳:"讴",謹:"谨",謾:"谩",譁:"哗",證:"证",譎:"谲",譏:"讥",譓:"𬤝",譖:"谮",識:"识",譙:"谯",譚:"谭",譜:"谱",譞:"𫍽",譟:"噪",譫:"谵",譭:"毁",譯:"译",議:"议",譴:"谴",護:"护",譸:"诪",譽:"誉",譾:"谫",讀:"读",讅:"谉",變:"变",讋:"詟",讌:"䜩",讎:"雠",讒:"谗",讓:"让",讕:"谰",讖:"谶",讚:"赞",讜:"谠",讞:"谳",谿:"溪",豈:"岂",豎:"竖",豐:"丰",豔:"艳",豬:"猪",豶:"豮",貍:"狸",貓:"猫",貙:"䝙",貝:"贝",貞:"贞",貟:"贠",負:"负",財:"财",貢:"贡",貧:"贫",貨:"货",販:"贩",貪:"贪",貫:"贯",責:"责",貯:"贮",貰:"贳",貲:"赀",貳:"贰",貴:"贵",貶:"贬",買:"买",貸:"贷",貺:"贶",費:"费",貼:"贴",貽:"贻",貿:"贸",賀:"贺",賁:"贲",賂:"赂",賃:"赁",賄:"贿",賅:"赅",資:"资",賈:"贾",賊:"贼",賑:"赈",賒:"赊",賓:"宾",賕:"赇",賙:"赒",賚:"赉",賜:"赐",賞:"赏",賠:"赔",賡:"赓",賢:"贤",賣:"卖",賤:"贱",賦:"赋",賧:"赕",質:"质",賫:"赍",賬:"账",賭:"赌",賰:"䞐",賴:"赖",賵:"赗",賺:"赚",賻:"赙",購:"购",賽:"赛",賾:"赜",贄:"贽",贅:"赘",贇:"赟",贈:"赠",贊:"赞",贋:"赝",贍:"赡",贏:"赢",贐:"赆",贓:"赃",贔:"赑",贖:"赎",贗:"赝",贛:"赣",贜:"赃",赬:"赪",趕:"赶",趙:"赵",趨:"趋",趲:"趱",跡:"迹",踐:"践",踰:"逾",踴:"踊",蹌:"跄",蹕:"跸",蹟:"迹",蹠:"跖",蹣:"蹒",蹤:"踪",蹺:"跷",躂:"跶",躉:"趸",躊:"踌",躋:"跻",躍:"跃",躎:"䟢",躑:"踯",躒:"跞",躓:"踬",躕:"蹰",躚:"跹",躡:"蹑",躥:"蹿",躦:"躜",躪:"躏",軀:"躯",車:"车",軋:"轧",軌:"轨",軍:"军",軏:"𫐄",軑:"轪",軒:"轩",軔:"轫",軛:"轭",軝:"𬨂",軟:"软",軤:"轷",軫:"轸",軲:"轱",軸:"轴",軹:"轵",軺:"轺",軻:"轲",軼:"轶",軾:"轼",較:"较",輄:"𨐈",輅:"辂",輇:"辁",輈:"辀",載:"载",輊:"轾",輋:"𪨶",輒:"辄",輓:"挽",輔:"辅",輕:"轻",輗:"𫐐",輛:"辆",輜:"辎",輝:"辉",輞:"辋",輟:"辍",輥:"辊",輦:"辇",輩:"辈",輪:"轮",輬:"辌",輮:"𫐓",輯:"辑",輳:"辏",輶:"𬨎",輸:"输",輻:"辐",輼:"辒",輾:"辗",輿:"舆",轀:"辒",轂:"毂",轄:"辖",轅:"辕",轆:"辘",轉:"转",轍:"辙",轎:"轿",轔:"辚",轟:"轰",轡:"辔",轢:"轹",轤:"轳",辦:"办",辭:"辞",辮:"辫",辯:"辩",農:"农",迴:"回",逕:"径",這:"这",連:"连",週:"周",進:"进",遊:"游",運:"运",過:"过",達:"达",違:"违",遙:"遥",遜:"逊",遞:"递",遠:"远",遡:"溯",適:"适",遲:"迟",遶:"绕",遷:"迁",選:"选",遺:"遗",遼:"辽",邁:"迈",還:"还",邇:"迩",邊:"边",邏:"逻",邐:"逦",郟:"郏",郵:"邮",鄆:"郓",鄉:"乡",鄒:"邹",鄔:"邬",鄖:"郧",鄧:"邓",鄩:"𬩽",鄭:"郑",鄰:"邻",鄲:"郸",鄳:"𫑡",鄴:"邺",鄶:"郐",鄺:"邝",酇:"酂",酈:"郦",醃:"腌",醖:"酝",醜:"丑",醞:"酝",醟:"蒏",醣:"糖",醫:"医",醬:"酱",醱:"酦",醲:"𬪩",釀:"酿",釁:"衅",釃:"酾",釅:"酽",釋:"释",釐:"厘",釒:"钅",釓:"钆",釔:"钇",釕:"钌",釗:"钊",釘:"钉",釙:"钋",針:"针",釣:"钓",釤:"钐",釦:"扣",釧:"钏",釩:"钒",釴:"𬬩",釵:"钗",釷:"钍",釹:"钕",釺:"钎",釾:"䥺",釿:"𬬱",鈀:"钯",鈁:"钫",鈃:"钘",鈄:"钭",鈅:"钥",鈇:"𫓧",鈈:"钚",鈉:"钠",鈍:"钝",鈎:"钩",鈐:"钤",鈑:"钣",鈒:"钑",鈔:"钞",鈕:"钮",鈞:"钧",鈡:"钟",鈣:"钙",鈥:"钬",鈦:"钛",鈧:"钪",鈮:"铌",鈰:"铈",鈳:"钶",鈴:"铃",鈷:"钴",鈸:"钹",鈹:"铍",鈺:"钰",鈽:"钸",鈾:"铀",鈿:"钿",鉀:"钾",鉅:"巨",鉆:"钻",鉈:"铊",鉉:"铉",鉊:"𬬿",鉋:"铇",鉍:"铋",鉑:"铂",鉕:"钷",鉗:"钳",鉚:"铆",鉛:"铅",鉝:"𫟷",鉞:"钺",鉢:"钵",鉤:"钩",鉥:"𬬸",鉦:"钲",鉧:"𬭁",鉬:"钼",鉭:"钽",鉮:"𬬹",鉳:"锫",鉶:"铏",鉷:"𫟹",鉸:"铰",鉺:"铒",鉻:"铬",鉿:"铪",銀:"银",銃:"铳",銅:"铜",銈:"𫓯",銍:"铚",銑:"铣",銓:"铨",銖:"铢",銘:"铭",銚:"铫",銛:"铦",銜:"衔",銠:"铑",銣:"铷",銥:"铱",銦:"铟",銨:"铵",銩:"铥",銪:"铕",銫:"铯",銬:"铐",銱:"铞",銳:"锐",銶:"𨱇",銷:"销",銹:"锈",銻:"锑",銼:"锉",鋁:"铝",鋃:"锒",鋅:"锌",鋇:"钡",鋌:"铤",鋏:"铗",鋐:"𬭎",鋒:"锋",鋗:"𫓶",鋙:"铻",鋝:"锊",鋟:"锓",鋣:"铘",鋤:"锄",鋥:"锃",鋦:"锔",鋨:"锇",鋩:"铓",鋪:"铺",鋭:"锐",鋮:"铖",鋯:"锆",鋰:"锂",鋱:"铽",鋶:"锍",鋸:"锯",鋹:"𬬮",鋼:"钢",錀:"𬬭",錁:"锞",錄:"录",錆:"锖",錇:"锫",錈:"锩",錏:"铔",錐:"锥",錒:"锕",錕:"锟",錘:"锤",錙:"锱",錚:"铮",錛:"锛",錞:"𬭚",錟:"锬",錠:"锭",錡:"锜",錢:"钱",錤:"𫓹",錦:"锦",錨:"锚",錩:"锠",錫:"锡",錮:"锢",錯:"错",録:"录",錳:"锰",錶:"表",錸:"铼",錼:"镎",鍀:"锝",鍁:"锨",鍃:"锪",鍅:"钫",鍆:"钔",鍇:"锴",鍈:"锳",鍊:"炼",鍋:"锅",鍍:"镀",鍔:"锷",鍘:"铡",鍚:"钖",鍛:"锻",鍠:"锽",鍤:"锸",鍥:"锲",鍩:"锘",鍬:"锹",鍭:"𬭤",鍰:"锾",鍵:"键",鍶:"锶",鍺:"锗",鍼:"针",鍾:"钟",鎂:"镁",鎄:"锿",鎇:"镅",鎊:"镑",鎌:"镰",鎓:"𬭩",鎔:"镕",鎖:"锁",鎘:"镉",鎚:"锤",鎛:"镈",鎝:"𨱏",鎡:"镃",鎢:"钨",鎣:"蓥",鎦:"镏",鎧:"铠",鎩:"铩",鎪:"锼",鎬:"镐",鎭:"镇",鎮:"镇",鎰:"镒",鎲:"镋",鎳:"镍",鎵:"镓",鎶:"鿔",鎸:"镌",鎿:"镎",鏃:"镞",鏇:"旋",鏈:"链",鏌:"镆",鏍:"镙",鏏:"𬭬",鏐:"镠",鏑:"镝",鏗:"铿",鏘:"锵",鏜:"镗",鏝:"镘",鏞:"镛",鏟:"铲",鏡:"镜",鏢:"镖",鏤:"镂",鏨:"錾",鏰:"镚",鏵:"铧",鏷:"镤",鏹:"镪",鏺:"䥽",鏻:"𬭸",鏽:"锈",鐃:"铙",鐄:"𨱑",鐇:"𫔍",鐋:"铴",鐍:"𫔎",鐏:"𨱔",鐐:"镣",鐒:"铹",鐓:"镦",鐔:"镡",鐘:"钟",鐙:"镫",鐝:"镢",鐠:"镨",鐥:"䦅",鐦:"锎",鐧:"锏",鐨:"镄",鐩:"𬭼",鐫:"镌",鐮:"镰",鐯:"䦃",鐲:"镯",鐳:"镭",鐵:"铁",鐶:"镮",鐸:"铎",鐺:"铛",鐽:"𫟼",鐿:"镱",鑄:"铸",鑊:"镬",鑌:"镔",鑑:"鉴",鑒:"鉴",鑔:"镲",鑕:"锧",鑞:"镴",鑠:"铄",鑣:"镳",鑥:"镥",鑪:"𬬻",鑭:"镧",鑰:"钥",鑱:"镵",鑲:"镶",鑷:"镊",鑹:"镩",鑼:"锣",鑽:"钻",鑾:"銮",鑿:"凿",钁:"镢",钂:"镋",長:"长",門:"门",閂:"闩",閃:"闪",閆:"闫",閈:"闬",閉:"闭",開:"开",閌:"闶",閎:"闳",閏:"闰",閑:"闲",閒:"闲",間:"间",閔:"闵",閘:"闸",閡:"阂",閣:"阁",閤:"合",閥:"阀",閨:"闺",閩:"闽",閫:"阃",閬:"阆",閭:"闾",閱:"阅",閲:"阅",閶:"阊",閹:"阉",閻:"阎",閼:"阏",閽:"阍",閾:"阈",閿:"阌",闃:"阒",闆:"板",闇:"暗",闈:"闱",闉:"𬮱",闊:"阔",闋:"阕",闌:"阑",闍:"阇",闐:"阗",闑:"𫔶",闒:"阘",闓:"闿",闔:"阖",闕:"阙",闖:"闯",關:"关",闞:"阚",闠:"阓",闡:"阐",闢:"辟",闤:"阛",闥:"闼",陘:"陉",陝:"陕",陞:"升",陣:"阵",陰:"阴",陳:"陈",陸:"陆",陽:"阳",隉:"陧",隊:"队",階:"阶",隑:"𬮿",隕:"陨",際:"际",隤:"𬯎",隨:"随",險:"险",隮:"𬯀",隯:"陦",隱:"隐",隴:"陇",隸:"隶",隻:"只",雋:"隽",雖:"虽",雙:"双",雛:"雏",雜:"杂",雞:"鸡",離:"离",難:"难",雲:"云",電:"电",霑:"沾",霢:"霡",霧:"雾",霽:"霁",靂:"雳",靄:"霭",靆:"叇",靈:"灵",靉:"叆",靚:"靓",靜:"静",靝:"靔",靦:"腼",靨:"靥",鞏:"巩",鞝:"绱",鞦:"秋",鞽:"鞒",韁:"缰",韃:"鞑",韆:"千",韉:"鞯",韋:"韦",韌:"韧",韍:"韨",韓:"韩",韙:"韪",韜:"韬",韝:"鞲",韞:"韫",韻:"韵",響:"响",頁:"页",頂:"顶",頃:"顷",項:"项",順:"顺",頇:"顸",須:"须",頊:"顼",頌:"颂",頍:"��",頎:"颀",頏:"颃",預:"预",頑:"顽",頒:"颁",頓:"顿",頔:"𬱖",頗:"颇",領:"领",頜:"颌",頠:"𬱟",頡:"颉",頤:"颐",頦:"颏",頫:"𫖯",頭:"头",頮:"颒",頰:"颊",頲:"颋",頴:"颕",頵:"𫖳",頷:"颔",頸:"颈",頹:"颓",頻:"频",頽:"颓",顆:"颗",題:"题",額:"额",顎:"颚",顏:"颜",顒:"颙",顓:"颛",顔:"颜",顗:"𫖮",願:"愿",顙:"颡",顛:"颠",類:"类",顢:"颟",顥:"颢",顧:"顾",顫:"颤",顬:"颥",顯:"显",顰:"颦",顱:"颅",顳:"颞",顴:"颧",風:"风",颭:"飐",颮:"飑",颯:"飒",颱:"台",颳:"刮",颶:"飓",颸:"飔",颺:"飏",颻:"飖",颼:"飕",飀:"飗",飄:"飘",飆:"飙",飈:"飚",飛:"飞",飠:"饣",飢:"饥",飣:"饤",飥:"饦",飩:"饨",飪:"饪",飫:"饫",飭:"饬",飯:"饭",飱:"飧",飲:"饮",飴:"饴",飼:"饲",飽:"饱",飾:"饰",飿:"饳",餃:"饺",餄:"饸",餅:"饼",餈:"糍",餉:"饷",養:"养",餌:"饵",餎:"饹",餏:"饻",餑:"饽",餒:"馁",餓:"饿",餕:"馂",餖:"饾",餗:"𫗧",餘:"余",餚:"肴",餛:"馄",餜:"馃",餞:"饯",餡:"馅",館:"馆",餬:"糊",餱:"糇",餳:"饧",餵:"喂",餶:"馉",餷:"馇",餸:"𩠌",餺:"馎",餼:"饩",餾:"馏",餿:"馊",饁:"馌",饃:"馍",饅:"馒",饈:"馐",饉:"馑",饊:"馓",饋:"馈",饌:"馔",饑:"饥",饒:"饶",饗:"飨",饘:"𫗴",饜:"餍",饞:"馋",饢:"馕",馬:"马",馭:"驭",馮:"冯",馱:"驮",馳:"驰",馴:"驯",馹:"驲",馼:"𫘜",駁:"驳",駃:"𫘝",駉:"𬳶",駐:"驻",駑:"驽",駒:"驹",駓:"𬳵",駔:"驵",駕:"驾",駘:"骀",駙:"驸",駛:"驶",駝:"驼",駟:"驷",駡:"骂",駢:"骈",駪:"𬳽",駭:"骇",駰:"骃",駱:"骆",駸:"骎",駼:"𬳿",駿:"骏",騁:"骋",騂:"骍",騄:"𫘧",騅:"骓",騊:"𫘦",騌:"骔",騍:"骒",騎:"骑",騏:"骐",騑:"𬴂",騖:"骛",騙:"骗",騞:"𬴃",騠:"𫘨",騤:"骙",騧:"䯄",騫:"骞",騭:"骘",騮:"骝",騰:"腾",騱:"𫘬",騵:"𫘪",騶:"驺",騷:"骚",騸:"骟",騾:"骡",驀:"蓦",驁:"骜",驂:"骖",驃:"骠",驄:"骢",驅:"驱",驊:"骅",驌:"骕",驍:"骁",驎:"𬴊",驏:"骣",驕:"骄",驗:"验",驚:"惊",驛:"驿",驟:"骤",驢:"驴",驤:"骧",驥:"骥",驦:"骦",驪:"骊",驫:"骉",骯:"肮",髏:"髅",髒:"脏",體:"体",髕:"髌",髖:"髋",髮:"发",鬆:"松",鬍:"胡",鬚:"须",鬢:"鬓",鬥:"斗",鬧:"闹",鬨:"哄",鬩:"阋",鬮:"阄",鬱:"郁",鬹:"鬶",魎:"魉",魘:"魇",魚:"鱼",魛:"鱽",魟:"𫚉",魢:"鱾",魨:"鲀",魯:"鲁",魴:"鲂",魷:"鱿",魺:"鲄",鮀:"𬶍",鮁:"鲅",鮃:"鲆",鮆:"𫚖",鮈:"𬶋",鮊:"鲌",鮋:"鲉",鮍:"鲏",鮎:"鲇",鮐:"鲐",鮑:"鲍",鮒:"鲋",鮓:"鲊",鮚:"鲒",鮜:"鲘",鮝:"鲞",鮞:"鲕",鮟:"𩽾",鮠:"𬶏",鮡:"𬶐",鮣:"䲟",鮦:"鲖",鮪:"鲔",鮫:"鲛",鮭:"鲑",鮮:"鲜",鮳:"鲓",鮶:"鲪",鮸:"𩾃",鮺:"鲝",鯀:"鲧",鯁:"鲠",鯇:"鲩",鯉:"鲤",鯊:"鲨",鯒:"鲬",鯔:"鲻",鯕:"鲯",鯖:"鲭",鯗:"鲞",鯛:"鲷",鯝:"鲴",鯡:"鲱",鯢:"鲵",鯤:"鲲",鯧:"鲳",鯨:"鲸",鯪:"鲮",鯫:"鲰",鯰:"鲶",鯴:"鲺",鯷:"鳀",鯻:"𬶟",鯽:"鲫",鯿:"鳊",鰁:"鳈",鰂:"鲗",鰃:"鳂",鰆:"䲠",鰈:"鲽",鰉:"鳇",鰊:"𬶠",鰌:"䲡",鰍:"鳅",鰏:"鲾",鰐:"鳄",鰒:"鳆",鰓:"鳃",鰛:"鳁",鰜:"鳒",鰟:"鳑",鰠:"鳋",鰣:"鲥",鰤:"𫚕",鰥:"鳏",鰧:"䲢",鰨:"鳎",鰩:"鳐",鰭:"鳍",鰮:"鳁",鰱:"鲢",鰲:"鳌",鰳:"鳓",鰵:"鳘",鰶:"𬶭",鰷:"鲦",鰹:"鲣",鰺:"鲹",鰻:"鳗",鰼:"鳛",鰾:"鳔",鱀:"𬶨",鱂:"鳉",鱅:"鳙",鱇:"𩾌",鱈:"鳕",鱉:"鳖",鱒:"鳟",鱔:"鳝",鱖:"鳜",鱗:"鳞",鱘:"鲟",鱚:"𬶮",鱝:"鲼",鱟:"鲎",鱠:"鲙",鱣:"鳣",鱤:"鳡",鱧:"鳢",鱨:"鲿",鱭:"鲚",鱯:"鳠",鱲:"𫚭",鱷:"鳄",鱸:"鲈",鱺:"鲡",鳥:"鸟",鳧:"凫",鳩:"鸠",鳬:"凫",鳲:"鸤",鳳:"凤",鳴:"鸣",鳶:"鸢",鳾:"䴓",鴆:"鸩",鴇:"鸨",鴉:"鸦",鴒:"鸰",鴕:"鸵",鴛:"鸳",鴝:"鸲",鴞:"鸮",鴟:"鸱",鴣:"鸪",鴦:"鸯",鴨:"鸭",鴯:"鸸",鴰:"鸹",鴴:"鸻",鴷:"䴕",鴻:"鸿",鴿:"鸽",鵁:"䴔",鵂:"鸺",鵃:"鸼",鵏:"𬷕",鵐:"鹀",鵑:"鹃",鵒:"鹆",鵓:"鹁",鵜:"鹈",鵝:"鹅",鵟:"𫛭",鵠:"鹄",鵡:"鹉",鵪:"鹌",鵬:"鹏",鵮:"鹐",鵯:"鹎",鵰:"雕",鵲:"鹊",鵷:"鹓",鵾:"鹍",鶄:"䴖",鶇:"鸫",鶉:"鹑",鶊:"鹒",鶓:"鹋",鶖:"鹙",鶘:"鹕",鶚:"鹗",鶠:"𬸘",鶡:"鹖",鶥:"鹛",鶩:"鹜",鶪:"䴗",鶬:"鸧",鶯:"莺",鶱:"𬸣",鶲:"鹟",鶴:"鹤",鶹:"鹠",鶺:"鹡",鶻:"鹘",鶼:"鹣",鶿:"鹚",鷀:"鹚",鷁:"鹢",鷂:"鹞",鷄:"鸡",鷉:"䴘",鷊:"鹝",鷓:"鹧",鷖:"鹥",鷗:"鸥",鷙:"鸷",鷚:"鹨",鷟:"𬸦",鷥:"鸶",鷦:"鹪",鷫:"鹔",鷭:"𬸪",鷯:"鹩",鷲:"鹫",鷳:"鹇",鷴:"鹇",鷸:"鹬",鷹:"鹰",鷺:"鹭",鷽:"鸴",鸂:"㶉",鸇:"鹯",鸊:"䴙",鸌:"鹱",鸏:"鹲",鸑:"𬸚",鸕:"鸬",鸘:"鹴",鸚:"鹦",鸛:"鹳",鸝:"鹂",鸞:"鸾",鹵:"卤",鹹:"咸",鹺:"鹾",鹼:"碱",鹽:"盐",麗:"丽",麥:"麦",麩:"麸",麪:"面",麫:"面",麬:"𤿲",麯:"曲",麳:"𪎌",麴:"曲",麵:"面",麼:"么",麽:"么",黃:"黄",黌:"黉",點:"点",黨:"党",黲:"黪",黴:"霉",黶:"黡",黷:"黩",黽:"黾",黿:"鼋",鼂:"鼌",鼉:"鼍",鼕:"冬",鼴:"鼹",齊:"齐",齋:"斋",齎:"赍",齏:"齑",齒:"齿",齔:"龀",齕:"龁",齗:"龂",齘:"𬹼",齙:"龅",齜:"龇",齟:"龃",齠:"龆",齡:"龄",齣:"出",齦:"龈",齧:"啮",齪:"龊",齬:"龉",齮:"𬺈",齯:"𫠜",齲:"龋",齶:"腭",齷:"龌",齼:"𬺓",龍:"龙",龎:"厐",龐:"庞",龑:"䶮",龔:"龚",龕:"龛",龜:"龟","鿁":"䜤","鿓":"鿒","𠁞":"𠀾","𠗣":"㓆","𡃕":"𠴛","𡅏":"𠲥","𡑍":"𫭼","𡑭":"𡋗","𡓾":"𡋀","𡔖":"𡍣","𡞵":"㛟","𡠹":"㛿","𡢃":"㛠","𡮉":"𡭜","𡮣":"𡭬","𡳳":"𡳃","𡻕":"岁","𡾱":"㟜","𢣚":"𢘝","𢶫":"𢫞","𢹿":"𢬦","𣈶":"暅","𣙎":"㭣","𣞻":"𣘓","𣠩":"𣞎","𣠲":"𣑶","𣯶":"毶","𣾷":"㳢","𤁣":"𣺽","𤅶":"𣷷","𤓩":"𤊰","𤪺":"㻘","𤫩":"㻏","𤳸":"𤳄","𥊝":"𥅿","𥌃":"𥅘","𥕥":"𥐰","𥖅":"𥐯","𥗽":"𬒗","𥢢":"䅪","𥸠":"𥮋","𥼽":"𥹥","𦘧":"𡳒","𦣎":"𦟗","𦪙":"䑽","𧜗":"䘞","𧜵":"䙊","𧝞":"䘛","𧟀":"𧝧","𧩙":"䜥","𧵳":"䞌","𧶧":"䞎","𨊰":"䢀","𨊸":"䢁","𨋢":"䢂","𨤻":"𨤰","𨦫":"䦀","𨧀":"𬭊","𨧜":"䦁","𨨏":"𬭛","𨭆":"𬭶","𨭎":"𬭳","𨯅":"䥿","𩞯":"䭪","𩠴":"𩠠","𩣑":"䯃","𩶘":"䲞","𰻞":"𰻝","「":"“","」":"”","『":"‘","』":"’"},Zr={一坏:"一坯",一目瞭然:"一目了然",七逕:"七迳",上逕:"上迳",上鍊:"上链",不可貲計:"不可赀計",不瞭解:"不了解",么麼:"幺麽",么麽:"幺麽",九逕山:"九迳山",乾佑縣:"乾佑县",乾元:"乾元",乾卦:"乾卦",乾嘉:"乾嘉",乾圖:"乾图",乾坤:"乾坤",乾坤一擲:"乾坤一掷",乾坤再造:"乾坤再造",乾坤大挪移:"乾坤大挪移",乾宅:"乾宅",乾安縣:"乾安县",乾安鎮:"乾安镇",乾州:"乾州",乾斷:"乾断",乾旦:"乾旦",乾曜:"乾曜",乾清宮:"乾清宫",乾盛世:"乾盛世",乾紅:"乾红",乾綱:"乾纲",乾縣:"乾县",乾象:"乾象",乾造:"乾造",乾道:"乾道",乾闥婆:"乾闼婆",乾陵:"乾陵",乾隆:"乾隆",乾隆年間:"乾隆年间",乾隆皇帝:"乾隆皇帝",二噁英:"二𫫇英",以免藉口:"以免借口",傢俱:"家具",允祕:"允祕",八濛山:"八濛山",其陰多蒐:"其阴多蒐",凌藉:"凌借",函覆:"函复",剋架:"剋架",剋毒:"剋毒",千鍾粟:"千锺粟",南氾:"南氾",南逕:"南迳",反反覆覆:"反反复复",反覆:"反复",反覆思維:"反复思维",反覆思量:"反复思量",反覆性:"反复性",名覆金甌:"名复金瓯",吳祕:"吴祕",吳育昇:"吴育昇",哪吒:"哪吒",回覆:"回复",土坏:"土坯",坏土:"坯土",坏子:"坯子",坏布:"坯布",坏戶:"坯户",墨沈沈:"墨沉沉",壺裏乾坤:"壶里乾坤",大目乾連冥間救母變文:"大目乾连冥间救母变文",宫商角徵羽:"宫商角徵羽",尼乾子:"尼乾子",尼乾陀:"尼乾陀",年釐:"年釐",幺麼:"幺麽",幺麼小丑:"幺麽小丑",幺麼小醜:"幺麽小丑",康乾:"康乾",張昇:"张昇",張法乾:"张法乾",彷彿:"仿佛",徐胤昇:"徐胤昇",復甦:"复苏",徵弦:"徵弦",徵絃:"徵弦",徵羽摩柯:"徵羽摩柯",徵聲:"徵声",徵調:"徵调",徵音:"徵音",意志消沈:"意志消沉",憑藉:"凭借",憑藉着:"凭借着",懷釐:"怀釐",手鍊:"手链",打坏:"打坯",扞格:"扞格",扭轉乾坤:"扭转乾坤",批覆:"批复",找藉口:"找借口",折戟沈沙:"折戟沉沙",折戟沈河:"折戟沉河",拉坏:"拉坯",拉鍊:"拉链",拉鍊工程:"拉链工程",拜覆:"拜复",挨剋:"挨剋",捏坏:"捏坯",擊沈:"击沉",據瞭解:"据了解",於世成:"於世成",於乎:"於乎",於仲完:"於仲完",於倫:"於伦",於其一:"於其一",於則:"於则",於勇明:"於勇明",於呼哀哉:"於呼哀哉",於單:"於单",於坦:"於坦",於崇文:"於崇文",於忠祥:"於忠祥",於惟一:"於惟一",於戲:"於戏",於敖:"於敖",於梨華:"於梨华",於清言:"於清言",於潛:"於潜",於琳:"於琳",於穆:"於穆",於竹屋:"於竹屋",於菟:"於菟",於邑:"於邑",於陵子:"於陵子",旋乾轉坤:"旋乾转坤",旋轉乾坤:"旋转乾坤",旋轉乾坤之力:"旋转乾坤之力",明瞭:"明了",明覆:"明复",昏沈:"昏沉",春蒐:"春蒐",春釐:"春釐",暗沈沈:"暗沉沉",書中自有千鍾粟:"书中自有千锺粟",朝乾夕惕:"朝乾夕惕",木吒:"木吒",李乾德:"李乾德",李昇:"李昇",李昇勳:"李昇勋",李澤鉅:"李泽钜",李祕:"李祕",李鍊福:"李链福",李鍾郁:"李锺郁",束脩:"束脩",東氾:"东氾",梁昇卿:"梁昇卿",梁章鉅:"梁章钜",楊聯陞:"杨联陞",樊於期:"樊於期",死氣沈沈:"死气沉沉",段脩:"段脩",毛坏:"毛坯",水逕:"水迳",氾勝之:"氾胜之",氾南:"氾南",氾國:"氾国",氾水:"氾水",沈下:"沉下",沈不住氣:"沉不住气",沈住氣:"沉住气",沈冤:"沉冤",沈厚:"沉厚",沈吟:"沉吟",沈寂:"沉寂",沈得住氣:"沉得住气",沈思:"沉思",沈思往事:"沉思往事",沈悶:"沉闷",沈沒:"沉没",沈沒成本:"沉没成本",沈浮:"沉浮",沈浸:"沉浸",沈浸於:"沉浸于",沈淪:"沉沦",沈湎:"沉湎",沈湎酒色:"沉湎酒色",沈溺:"沉溺",沈滯:"沉滞",沈滯性:"沉滞性",沈澱:"沉淀",沈澱出來:"沉淀出来",沈澱劑:"沉淀剂",沈澱法:"沉淀法",沈澱物:"沉淀物",沈濁:"沉浊",沈甸甸:"沉甸甸",沈痛:"沉痛",沈痼:"沉痼",沈痾:"���疴",沈睡:"沉睡",沈睡不醒:"沉睡不醒",沈砂池:"沉砂池",沈積:"沉积",沈積岩:"沉积岩",沈積石:"沉积石",沈筒:"沉筒",沈船:"沉船",沈落:"沉落",沈迷:"沉迷",沈迷不醒:"沉迷不醒",沈醉:"沉醉",沈重:"沉重",沈降:"沉降",沈陷:"沉陷",沈靜:"沉静",沈靜下來:"沉静下来",沈香:"沉香",沈鬱:"沉郁",沈魚落雁:"沉鱼落雁",沈默:"沉默",沈默不語:"沉默不语",沈默寡言:"沉默寡言",沙逕:"沙迳",河逕:"河迳",流徵:"流徵",浪蕩乾坤:"浪荡乾坤",浮沈:"浮沉",海哩:"海里",深沈:"深沉",深沈不露:"深沉不露",溫昇豪:"温昇豪",滑藉:"滑借",烏昇:"乌昇",烏沈沈:"乌沉沉",烏逕:"乌迳",狐藉虎威:"狐借虎威",王彥昇:"王彦昇",珍珠項鍊:"珍珠项链",甚鉅:"甚钜",甦生:"苏生",甦醒:"苏醒",申昇勳:"申昇勋",申覆:"申复",畢昇:"毕昇",盧象昇:"卢象昇",目劄:"目劄",瞭如:"了如",瞭如指掌:"了如指掌",瞭然:"了然",瞭然於心:"了然于心",瞭若指掌:"了若指掌",瞭解:"了解",瞭解到:"了解到",破釜沈舟:"破釜沉舟",磚坏:"砖坯",示覆:"示复",社逕:"社迳",祕丕笈:"祕丕笈",祕彭祖:"祕彭祖",祕瓊:"祕琼",祝釐:"祝釐",稟覆:"禀复",竺乾:"竺乾",答覆:"答复",篤麼:"笃麽",簡單明瞭:"简单明了",籌畫:"筹划",素藉:"素借",耳沈:"耳沉",肉脩:"肉脩",肘手鍊足:"肘手链足",胤祕:"胤祕",脩敬:"脩敬",脩炳:"脩炳",脩脡:"脩脡",脩脯:"脩脯",脩金:"脩金",脫坏:"脱坯",腶脩:"腶脩",英哩:"英里",茅蒐:"茅蒐",茵藉:"茵借",萬鍾:"万锺",落雁沈魚:"落雁沉鱼",蒐于紅:"蒐于红",蒐於紅:"蒐于红",蒐狩:"蒐狩",蒐獮:"蒐狝",蒐獵:"蒐猎",蒐田:"蒐田",蒐畋:"蒐畋",蒐苗:"蒐苗",蒜薹:"蒜薹",蔣昇:"蒋昇",蕓薹:"芸薹",蕭乾:"萧乾",藉代:"借代",藉以:"借以",藉助:"借助",藉助於:"借助于",藉卉:"借卉",藉口:"借口",藉喻:"借喻",藉寇兵:"借寇兵",藉寇兵齎盜糧:"借寇兵赍盗粮",藉手:"借手",藉據:"借据",藉故:"借故",藉故推辭:"借故推辞",藉方:"借方",藉條:"借条",藉槁:"借槁",藉機:"借机",藉此:"借此",藉此機會:"借此机会",藉甚:"借甚",藉由:"借由",藉着:"借着",藉端:"借端",藉端生事:"借端生事",藉箸代籌:"借箸代筹",藉草枕塊:"借草枕块",藉詞:"借词",藉讀:"借读",藉資:"借资",衹得:"只得",衹見樹木:"只见树木",衹見樹木不見森林:"只见树木不见森林",袁祕:"袁祕",袖裏乾坤:"袖里乾坤",袷袢:"袷袢",製坏:"制坯",覆信:"复信",覆呈:"复呈",覆命:"复命",覆墓:"复墓",覆帳:"复帐",覆按:"复按",覆文:"复文",覆校:"复校",覆電:"复电",見覆:"见复",角徵:"角徵",角徵羽:"角徵羽",計畫:"计划",變徵:"变徵",變徵之聲:"变徵之声",變徵之音:"变徵之音",谿工:"谿工",赤石逕:"赤石迳",踅門瞭戶:"踅门了户",躪藉:"躏借",載沈載浮:"载沉载浮",載浮載沈:"载浮载沉",辛祕:"辛祕",逆釐:"逆釐",逕口:"迳口",逕聯:"迳联",逕頭:"迳头",郭子乾:"郭子乾",酒逢知己千鍾少:"酒逢知己千锺少",醞藉:"酝借",重覆:"重复",金吒:"金吒",金昇玟:"金昇玟",金鍊:"金链",鈞覆:"钧复",鉅子:"钜子",鉅萬:"钜万",鉅防:"钜防",鉸鍊:"铰链",銀鍊:"银链",鋼坏:"钢坯",錢鍾書:"钱锺书",鍊墜:"链坠",鍊子:"链子",鍊形:"链形",鍊條:"链条",鍊錘:"链锤",鍊鎖:"链锁",鍛鍾:"锻锺",鍾繇:"锺繇",鍾萬梅:"锺万梅",鍾重發:"锺重发",鍾鍛:"锺锻",鍾馗:"锺馗",鎖鍊:"锁链",鐵鍊:"铁链",鑽石項鍊:"钻石项链",鑿坏:"凿坯",閻鶴昇:"阎鹤昇",陰沈:"阴沉",陰沈沈:"阴沉沉",陰陰沈沈:"阴阴沉沉",陳志昇:"陈志昇",陳昇:"陈昇",陶坏:"陶坯",雁杳魚沈:"雁杳鱼沉",電覆:"电复",韓昇延:"韩昇延",項鍊:"项链",頸鍊:"颈链",顛乾倒坤:"颠乾倒坤",顛倒乾坤:"颠倒乾坤",顧藉:"顾借",魏徵:"魏徵",魚沈雁杳:"鱼沉雁杳",麪坏兒:"面坯儿",麼些族:"麽些族",黃鍾公:"黄锺公",黑沈沈:"黑沉沉",龔昇:"龚昇"};let kn=null,ft=null;function vs(){kn=new Map(Object.entries(ys)),ft=new Map;for(const e of Object.keys(Zr)){const t=e[0];let n=ft.get(t);n||ft.set(t,n=[]),n.push(e)}for(const e of ft.values())e.sort((t,n)=>n.length-t.length)}function Dn(e){kn||vs();let t="",n=0,r=0;const a=e.length;for(;r=3?a.slice(1,-1).join(", "):a[a.length-1]}const r=t.match(/^Vulkan[\s\d.]+\((.+)\)$/i);return r&&(t=r[1]),t=t.replace(/ANGLE Metal Renderer:\s*/i,"").replace(/\(0x[0-9A-Fa-f]+\)/g,"").replace(/\b(Direct3D\d+|vs_\d+_\d+|ps_\d+_\d+|OpenGL(?: ES)?[\d. ]*)\b/g,"").replace(/\((TM|R|C)\)/gi,"").replace(/\s{2,}/g," ").trim().replace(/[,;·]+$/,"").replace(/\s+GPU$/i,"").trim().replace(/^(\S+)( \1)+(?= |$)/i,"$1"),t||null}const ws={nvidia:["nvidia","geforce"],amd:["amd","radeon","ati"],intel:["intel"],apple:["apple"],qualcomm:["qualcomm","adreno"],arm:["arm","mali"],samsung:["samsung","xclipse"]};function eo(e,t,n){const r=String(e??"").toLowerCase().trim();if(!r)return!1;const a=`${t??""} ${n??""}`.toLowerCase();return(ws[r]??[r]).some(o=>a.includes(o))}function Es(e,t){return t&&/\d/.test(t)?t:e}function ks(e){if(typeof e!="string"||!e.trim())return e;const t=o=>/\S\s+\S/.test(o);let n=e.trim();const r=n.replace(/^(NVIDIA\s+(GeForce\s+)?|AMD\s+|Qualcomm\s+)/i,"");t(r)&&(n=r);const a=n.replace(/\s+(Graphics|GPU)$/i,"");return t(a)&&(n=a),n}function Cs(e){const t=String(e??"");return/\b[ab]\d{3}\b/i.test(t)||/hpg/i.test(t)?!1:/\b(intel|iris|uhd|xe)\b/i.test(t)?!0:/\bradeon\b/i.test(t)&&(/\b\d{3}m\b/i.test(t)||/\bradeon(\s*\(tm\))?\s+graphics$/i.test(t))}function to(){try{const e=document.createElement("canvas"),t=e.getContext("webgl2",{powerPreference:"high-performance"})??e.getContext("webgl",{powerPreference:"high-performance"});if(!t)return null;const n=t.getExtension("WEBGL_debug_renderer_info"),r=n?{vendor:String(t.getParameter(n.UNMASKED_VENDOR_WEBGL)??""),renderer:String(t.getParameter(n.UNMASKED_RENDERER_WEBGL)??"")}:null;return t.getExtension("WEBGL_lose_context")?.loseContext(),r}catch{return null}}function Ms(e,t,n=to()){return!n||!eo(e?.vendor,n.vendor,n.renderer)?t:Es(t,Ss(n.renderer))}function zt(e){let t;try{t=window[`${e}Storage`];const n="moxhi.storage.probe";t.setItem(n,"1"),t.removeItem(n)}catch{const n=new Map;return{persistent:!1,getItem:r=>n.get(r)??null,setItem:(r,a)=>{n.set(r,String(a))},removeItem:r=>{n.delete(r)}}}return{persistent:!0,getItem:n=>{try{return t.getItem(n)}catch{return null}},setItem:(n,r)=>{try{t.setItem(n,r)}catch{}},removeItem:n=>{try{t.removeItem(n)}catch{}}}}const xs=1,Dt=1e3,cn="moxhi.scheduleAuto.seed.v1",As=new Set(["off","shadow","apply","auto"]),Ns=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;if(!Number.isInteger(Dt)||Dt<0||Dt>1e4)throw new Error("schedule auto rollout basis points must be an integer from 0 to 10000");function br(e){return typeof e!="string"||!Ns.test(e)?null:Number.parseInt(e.slice(0,8),16)%1e4}function Pe(e,t,n,r){return{mode:e,source:t,reason:n,revision:xs,rolloutBps:r}}function Ts({enabled:e=!1,explicitMode:t=null,rolloutBps:n=Dt,getStorage:r=()=>null,createSeed:a=()=>null}={}){if(t!==null){const u=As.has(t)?t:"off";return Pe(u,"explicit",u===t?"explicit":"explicit-invalid",n)}if(e!==!0)return Pe("off","default","caller-disabled",n);if(!Number.isInteger(n)||n<0||n>1e4)return Pe("off","default","rollout-invalid",0);if(n===0)return Pe("off","default","rollout-disabled",0);let o;try{o=r()}catch{return Pe("off","default","storage-error",n)}if(o?.persistent!==!0)return Pe("off","default","storage-unavailable",n);let s;try{s=o.getItem(cn)}catch{return Pe("off","default","storage-error",n)}if(s===null){try{s=a()}catch{return Pe("off","default","seed-generation-failed",n)}if(br(s)===null)return Pe("off","default","seed-generation-failed",n);try{if(o.setItem(cn,s),o.getItem(cn)!==s)return Pe("off","default","seed-write-failed",n)}catch{return Pe("off","default","seed-write-failed",n)}}const i=br(s);return i===null?Pe("off","default","seed-invalid",n):in)throw new Error(`${t} must be a non-empty string of at most ${n} chars`);return e}function bt(e,t){return Ge(e,t),e===0?0:2**Math.ceil(Math.log2(e))}function yt(e){if(!Array.isArray(e)||e.length===0)return null;const t=[...e].sort((r,a)=>r-a),n=t.length>>1;return t.length%2?t[n]:(t[n-1]+t[n])/2}function vr(e,t){if(!Array.isArray(e)||!Array.isArray(t)||e.length===0||e.length!==t.length)return null;let n=0,r=0;for(let a=0;a0?n/r:null}function Cn(e,t){if(!Array.isArray(e)||e.length===0)return null;const n=[...e].sort((s,i)=>s-i),r=(n.length-1)*t,a=Math.floor(r),o=Math.ceil(r);return a===o?n[a]:n[a]+(n[o]-n[a])*(r-a)}function Mn(e){if(Array.isArray(e))return e.map(Mn);if(e&&typeof e=="object"){const t={};for(const n of Object.keys(e).sort())t[n]=Mn(e[n]);return t}return e}function zn(e){return JSON.stringify(Mn(e))}function Ks(e){return!!e&&pt.some(t=>e.inFlight===t.inFlight&&e.groupSteps===t.groupSteps)}function Vs(e){return Ce(e,"groupSteps")}function qs(e,t=null){const n=Ce(e,"groupSteps");return t==null?n:Math.min(n,Ce(t,"carry groupSteps"))}function Js(e,t){const n=Ce(e,"carry groupSteps"),r=Ce(t,"groupStepsFinal");return Math.min(n,r)}function Qs(e){return e===1/0?"inf":bt(e,"policy.tokenBudget")}function Sr(e,t,n){return t.map(r=>bt(Cn(e,r),n))}function Xs(e){const t=new Map;for(const n of e){const r=Ce(n,"plannedSourceBuckets value");t.set(r,(t.get(r)??0)+1)}return[...t.entries()].sort((n,r)=>n[0]-r[0]).map(([n,r])=>[n,bt(r,"bucket count")])}function Ys({batchSizes:e,plannedSourceBuckets:t,sourceTokenLengths:n,modelId:r,weightsId:a,dtype:o,policy:s}={}){if(!Array.isArray(e)||e.length===0)throw new Error("batchSizes must be a non-empty array");const i=e.map(p=>Ce(p,"batchSizes value"));if(!Array.isArray(t)||t.length!==i.length)throw new Error("plannedSourceBuckets must align with batchSizes");if(!Array.isArray(n))throw new Error("sourceTokenLengths must be an array");const u=i.reduce((p,f)=>p+f,0);if(n.length!==u)throw new Error("sourceTokenLengths must contain one value per planned row");const l=n.map(p=>Ce(p,"sourceTokenLengths value"));if(!s||typeof s!="object")throw new Error("policy must be an object");return{protocolRev:We,rowCountBand:bt(u,"rowCount"),batchCountBand:bt(i.length,"batchCount"),plannedSourceBucketHistogram:Xs(t),batchSizeQuantiles:Sr(i,[.25,.5,.75],"batchSize quantile"),sourceTokenQuantiles:Sr(l,[.25,.5,.75,.9],"sourceToken quantile"),model:[ce(r,"modelId"),ce(a,"weightsId"),ce(o,"dtype",32)],policy:{pack:s.pack===!0,kvPlanner:ce(s.kvPlanner,"policy.kvPlanner"),tokenBudgetBand:Qs(s.tokenBudget),immediates:ce(s.immediates,"policy.immediates",32),uniformPool:s.uniformPool===!0}}}function Zs(e){if(!e||typeof e!="object")throw new Error("signature must be an object");return zn(e)}function ei(e,t=Gn,n=null){if(!Array.isArray(e)||e.length===0)throw new Error("batch cost list must be non-empty");const r=e.map(f=>Z(f,"batch cost"));if(!Array.isArray(t)||t.length===0||t.some(f=>!Number.isFinite(f)||f<=0||f>=1))throw new Error("sample quantiles must be finite values between zero and one");let a=null;if(n!=null){if(!Array.isArray(n)||n.length!==r.length)throw new Error("batch regions must align with batch costs");a=n.map((f,m)=>{if(Number.isInteger(f)&&f>0||typeof f=="string"&&f.length>0&&f.length<=64)return f;throw new Error(`batch region at index ${m} is invalid`)})}if(r.length<=t.length)return r.map((f,m)=>m);const o=r.reduce((f,m)=>f+m,0);let s=0;const i=r.map(f=>{const m=(s+f/2)/o;return s+=f,m}),u=new Set,l=new Set,p=a?Math.min(t.length,new Set(a.map(String)).size):0;for(const f of t){let m=null;const d=a&&l.sizef-m)}function Kt(e){return`${typeof e}:${String(e)}`}function ti(e,t){return typeof e=="number"&&typeof t=="number"?e-t:typeof e=="number"?-1:typeof t=="number"?1:String(e).localeCompare(String(t))}function ln(e,t,n){return e.filter(({index:r})=>!n.has(r)).map(r=>({...r,distance:Math.abs(r.center-t)})).sort((r,a)=>r.distance-a.distance||r.index-a.index)[0]??null}function wr(e,t){const n=e.entries.filter(({index:o})=>t.has(o));if(n.length===0)return null;const r=n.reduce((o,s)=>o+s.cost,0);return n.reduce((o,s)=>o+s.center*s.cost,0)/r<.5?.75:.25}function un(e){return[...e].sort((t,n)=>n.mass-t.mass||ti(t.region,n.region)||t.entries[0].index-n.entries[0].index)}function ni(e,t,n=null){if(!Array.isArray(e)||e.length===0)throw new Error("batch cost list must be non-empty");const r=e.map(C=>Z(C,"batch cost"));if(!Array.isArray(t)||t.length===0)throw new Error("sample batch indices must be a non-empty array");const a=t.map(C=>{if(!Number.isInteger(C)||C<0||C>=r.length)throw new Error("sample batch index is out of range");return C});if(new Set(a).size!==a.length)throw new Error("sample batch indices contain a duplicate");if(r.length-a.length<2)throw new Error("confirmation planning requires two unused batches");let o;if(n==null)o=new Array(r.length).fill("all");else{if(!Array.isArray(n)||n.length!==r.length)throw new Error("batch regions must align with batch costs");o=n.map((C,L)=>{if(Number.isInteger(C)&&C>0||typeof C=="string"&&C.length>0&&C.length<=64)return C;throw new Error(`batch region at index ${L} is invalid`)})}const s=new Map;for(let C=0;CKt(o[C]))),f=C=>C.entries.some(({index:L})=>!l.has(L)),d=un(i.filter(C=>p.has(C.key)&&f(C)))[0];if(!d)throw new Error("confirmation planning requires an unused stability batch");const v=wr(d,u),y=ln(d.entries,v,l);if(!y)throw new Error("confirmation planning could not select a stability batch");l.add(y.index);let h=un(i.filter(C=>!p.has(C.key)&&f(C)))[0]??null,S=.5;h||(h=un(i.filter(L=>p.has(L.key)&&L.key!==d.key&&f(L)))[0]??null,h&&(S=wr(h,u)));let M;if(h)M=ln(h.entries,S,l);else{let C=0;const L=r.reduce((G,fe)=>G+fe,0),z=r.map((G,fe)=>{const me={index:fe,cost:G,center:(C+G/2)/L};return C+=G,me});M=ln(z,.5,l)}if(!M)throw new Error("confirmation planning could not select a coverage batch");return Object.freeze([Object.freeze({role:"stability",batchIndex:y.index,region:o[y.index]}),Object.freeze({role:"coverage",batchIndex:M.index,region:o[M.index]})])}function ri(e,t){if(!Array.isArray(e)||e.length===0)throw new Error("batch cost list must be non-empty");const n=e.map(l=>Z(l,"batch cost"));if(!Array.isArray(t)||t.length===0)throw new Error("sample batch indices must be a non-empty array");const r=t.map(l=>{if(!Number.isInteger(l)||l<0||l>=n.length)throw new Error("sample batch indices must address the batch cost list");return l});if(new Set(r).size!==r.length)throw new Error("sample batch indices must not contain duplicates");r.sort((l,p)=>l-p);const a=n.reduce((l,p)=>l+p,0);let o=0;const s=n.map(l=>{const p=(o+l/2)/a;return o+=l,p}),i=r.map(l=>s[l]),u=new Array(r.length).fill(0);for(let l=0;lMath.abs(s[l]-d)),f=Math.min(...p),m=p.map((d,v)=>({distance:d,owner:v})).filter(({distance:d})=>Math.abs(d-f)<=Number.EPSILON*8);for(const{owner:d}of m)u[d]+=n[l]/m.length}return u.map(l=>l/a)}function oi({fileMode:e=!1,pack:t=!1,isMobile:n=!1,uncachedRows:r=0,plannedBatches:a=0,kernelTuneSource:o=null,manualOverrides:s={},memorySafe:i=!1}={}){if(!e)return{eligible:!1,reason:"typed-text"};if(!t)return{eligible:!1,reason:"packing-disabled"};if(n)return{eligible:!1,reason:"mobile-v1-skip"};for(const u of Fs){const l=s?.[u];if(l!=null)return{eligible:!1,reason:`manual-override:${u}`}}return o==="partial"?{eligible:!1,reason:"kernel-autotune-partial"}:o!=="measured"&&o!=="cache"?{eligible:!1,reason:"kernel-autotune-untrusted"}:i?!Number.isInteger(r)||r0||typeof e?.region=="number"&&Number.isFinite(e.region))&&Number.isFinite(e?.baselineWallMs)&&e.baselineWallMs>0&&Number.isFinite(e?.candidateWallMs)&&e.candidateWallMs>0&&Number.isFinite(e?.baselineDecodeMs)&&e.baselineDecodeMs>0&&Number.isFinite(e?.candidateDecodeMs)&&e.candidateDecodeMs>0}function vt(e){return Number.isInteger(e)&&e>=0}function xn(e){if(!Array.isArray(e)||e.length===0)return{pairCount:0,wallGain:null,decodeGain:null,medianWallGain:null,medianDecodeGain:null,weightedWallGain:null,weightedDecodeGain:null,favorableRegions:0,complete:!1,exact:!1,shrinkFree:!1};const t=e.some(g=>g?.weight!==void 0),r=(!t||e.every(g=>Number.isFinite(g?.weight)&&g.weight>0))&&e.every(io),a=r&&e.every(g=>g.complete===!0),o=e.every(g=>g.exact===!0),i=e.every(g=>vt(g.baselineSubmitShrinks)&&vt(g.candidateSubmitShrinks))&&e.every(g=>g.baselineSubmitShrinks===0&&g.candidateSubmitShrinks===0),u=r?e.map(g=>Vt(g.baselineWallMs,g.candidateWallMs)):[],l=r?e.map(g=>Vt(g.baselineDecodeMs,g.candidateDecodeMs)):[],p=t&&r?e.map(g=>g.weight):[],f=yt(u),m=yt(l),d=t?vr(u,p):null,v=t?vr(l,p):null,y=new Set;return r&&e.forEach((g,h)=>{u[h]>0&&y.add(String(g.region))}),{pairCount:e.length,wallGain:d===null?f:Math.min(f,d),decodeGain:v===null?m:Math.min(m,v),medianWallGain:f,medianDecodeGain:m,weightedWallGain:d,weightedDecodeGain:v,favorableRegions:y.size,complete:a,exact:o,shrinkFree:i}}function ai(e,t="base"){if(!Array.isArray(e)||e.length===0)throw new Error("screen results must be a non-empty array");const n=e.find(a=>a?.id===t);if(!n)throw new Error(`screen results are missing baseline ${t}`);const r=e.filter(a=>a?.id!==t&&a?.exact===!0&&a?.submitShrinks===0&&Number.isFinite(a?.score)&&a.score>0).sort((a,o)=>a.score-o.score||String(a.id).localeCompare(String(o.id)))[0]??null;return{base:n,candidate:r}}function Er({screenPairs:e,confirmationPairs:t=[]}={}){const n=xn(e),r=Array.isArray(t)?t:[],a=xn(r),o=Array.isArray(t)&&r.length<=Ze.length&&r.every((h,S)=>h?.role===Ze[S]),s=r.every(io),i=s?r.map(h=>Vt(h.baselineWallMs,h.candidateWallMs)):[],u=s?r.map(h=>Vt(h.baselineDecodeMs,h.candidateDecodeMs)):[],l=i.length>0?Math.min(...i):null,p=Number.isFinite(n.wallGain)?Math.min(n.wallGain,...i):n.wallGain,f=Number.isFinite(n.decodeGain)?Math.min(n.decodeGain,...u):n.decodeGain,m=[...Array.isArray(e)?e:[],...r],d=m.every(h=>vt(h?.baselineSubmitShrinks)&&vt(h?.candidateSubmitShrinks)&&h.baselineSubmitShrinks===0&&h.candidateSubmitShrinks===0),v=m.every(h=>h?.exact===!0),y={promote:!1,reason:null,wallGain:p,screenWallGain:n.wallGain,confirmationMinWallGain:l,decodeGain:f,favorableRegions:n.favorableRegions,confirmationCount:Array.isArray(t)?r.filter(h=>h?.complete===!0).length:0,requiredConfirmations:Ze.length,completedRoles:r.filter(h=>h?.complete===!0).map(h=>h.role)};return!n.complete||!o||r.length>0&&!a.complete?{...y,reason:"incomplete"}:d?v?n.favorableRegions=Bs?n.decodeGain>=0?i.some(h=>h<=0)||u.some(h=>h<0)?{...y,reason:"confirmation-regression"}:i.some(h=>hZ(u,"run cost"));Z(r,"safetyFactor");const i=s.reduce((u,l)=>u+a*(l/o),0);return{rawGpuMs:i,projectedMs:i*r,runCount:s.length}}function si({kernelReferenceMs:e,kernelReferenceCost:t,sampleCosts:n,armCount:r=De.length,confirmationRounds:a=2,pretokenizeMs:o=0,safetyFactor:s=Qt}={}){const i=Z(e,"kernelReferenceMs"),u=Z(t,"kernelReferenceCost");if(!Array.isArray(n)||n.length===0)throw new Error("sampleCosts must be a non-empty array");const l=n.map(d=>Z(d,"sample cost"));if(Ce(r,"armCount"),!Number.isInteger(a)||a<0)throw new Error("confirmationRounds must be a non-negative integer");Ge(o,"pretokenizeMs"),Z(s,"safetyFactor");const p=l.flatMap(d=>Array(r).fill(d)),f=a*2;p.push(...Array(f).fill(yt(l)));const m=An({referenceMs:i,referenceCost:u,runCosts:p,safetyFactor:s});return{rawGpuMs:m.rawGpuMs,rawProjectedMs:o+m.rawGpuMs,projectedMs:o+m.projectedMs,screenRuns:l.length*r,confirmationRuns:f,completeRuns:p.length,runCosts:p}}function ii(e,t=Jt,n=Un){const r=e?.projectedMs,a=e?.rawProjectedMs;if(!Number.isFinite(r)||r<0||!Number.isFinite(t)||t<=0||!Number.isFinite(n)||n<0||n>=t)return{admit:!1,reason:"invalid-projection",projectedMs:Number.isFinite(r)?r:null,rawProjectedMs:Number.isFinite(a)?a:null,budgetMs:Number.isFinite(t-n)?t-n:null,admission:null};const o=t-n,s=r<=o,i=!s&&Number.isFinite(a)&&a>=0&&a<=o,u=s||i;return{admit:u,reason:u?null:"projected-over-budget",projectedMs:r,rawProjectedMs:Number.isFinite(a)?a:null,budgetMs:o,admission:s?"full":i?"pilot":null}}function ci({elapsedMs:e,projectedRunMs:t,deadlineMs:n=Jt,marginMs:r=Un,safetyFactor:a=Qt}={}){if(!(Number.isFinite(e)&&e>=0&&Number.isFinite(t)&&t>0&&Number.isFinite(n)&&n>0&&Number.isFinite(r)&&r>=0&&Number.isFinite(a)&&a>0))return{admit:!1,reason:"invalid-projection",projectedEndMs:null,remainingMs:Number.isFinite(n-e)?n-e:null};const s=e+t*a+r;return{admit:s<=n,reason:s<=n?null:"projected-over-budget",projectedEndMs:s,remainingMs:n-e}}function dn({elapsedMs:e,deadlineMs:t=Jt}={}){Ge(e,"elapsedMs"),Z(t,"deadlineMs");const n=Math.max(0,e-t);return{elapsedMs:e,deadlineMs:t,deadlineExceeded:n>0,overrunMs:n}}function co({adapterKey:e,modelId:t,weightsId:n,dtype:r,browserMajor:a,kernelTuneId:o,modes:s,signature:i}={}){if(!Number.isInteger(a)||a<0)throw new Error(`browserMajor must be a non-negative integer, got ${a}`);if(!s||typeof s!="object"||Array.isArray(s))throw new Error("modes must be an object");if(!i||typeof i!="object")throw new Error("signature must be an object");const u={};for(const[l,p]of Object.entries(s)){if(!Us.has(l))throw new Error(`modes contains unknown key ${l}`);if(js.has(l)){if(typeof p!="boolean")throw new Error(`modes.${l} must be boolean`);u[l]=p}else l==="tokenBudget"?u[l]=p===1/0?"inf":Z(p,"modes.tokenBudget"):u[l]=ce(p,`modes.${l}`)}return zn({protocolRev:We,adapterKey:ce(e,"adapterKey"),modelId:ce(t,"modelId"),weightsId:ce(n,"weightsId"),dtype:ce(r,"dtype",32),browserMajor:a,kernelTuneId:ce(o,"kernelTuneId"),modes:u,signature:i})}function li(e={}){const t=zn({amortizationRev:Et,scheduleIdentity:co(e)});return ce(t,"observation identity",Qe)}function lo(e){let t=2166136261;for(let n=0;n>>0).toString(16).padStart(8,"0")}function ui(e){return ce(e,"cache identity",Qe),`moxhi.schedule.v${We}.${lo(e)}`}function di(e){return ce(e,"observation scope identity",Qe),`moxhi.schedule-observation.v${Et}.${lo(e)}`}function Nn(e,t="observedShape"){if(e!=null){if(!e||typeof e!="object")throw new Error(`${t} must be an object`);if(Z(e.targetTokenP50,`${t}.targetTokenP50`),Z(e.targetTokenP90,`${t}.targetTokenP90`),e.targetTokenP901)throw new Error(`${t}.compactionRate must be between zero and one`)}}function St(e){if(!e||typeof e!="object"||Array.isArray(e))throw new Error("cache entry must be an object");if(!Number.isInteger(e.protocolRev)||e.protocolRev<=0)throw new Error("cache entry protocolRev must be a positive integer");if(ce(e.identity,"cache entry identity",Qe),ce(e.scopeKey,"cache entry scopeKey",512),ce(e.kernelTuneId,"cache entry kernelTuneId",512),ce(e.signatureKey,"cache entry signatureKey",Qe),Ge(e.createdAt,"cache entry createdAt"),Ge(e.lastUsedAt,"cache entry lastUsedAt"),!_s.has(e.ttlClass))throw new Error(`cache entry ttlClass is invalid: ${e.ttlClass}`);if(!Ds.has(e.verdict))throw new Error(`cache entry verdict is invalid: ${e.verdict}`);if(!Ks(e.schedule))throw new Error("cache entry schedule is not a version-1 arm");if(!Number.isInteger(e.screenSubmitShrinks)||e.screenSubmitShrinks<0)throw new Error("cache entry screenSubmitShrinks must be a non-negative integer");const t=e.schedule.inFlight===Le.inFlight&&e.schedule.groupSteps===Le.groupSteps,n=Gs.has(e.verdict);if(n&&e.ttlClass!=="negative"||!n&&e.ttlClass!=="normal")throw new Error("cache entry ttlClass does not match its verdict");if(e.verdict==="selected"){if(t)throw new Error("selected cache verdict must use a non-default schedule");if(e.screenSubmitShrinks!==0)throw new Error("selected cache verdict requires zero-shrink proof")}else if(!t)throw new Error("non-selected cache verdict must use the default schedule");if(e.verdict==="keep-default"&&e.screenSubmitShrinks!==0)throw new Error("keep-default cache verdict requires zero-shrink proof");if(e.verdict==="safety-fallback"&&e.screenSubmitShrinks===0)throw new Error("safety-fallback cache verdict requires a submit shrink");if(n&&e.screenSubmitShrinks!==0)throw new Error("negative cache verdict cannot contain completed shrink evidence");if(Nn(e.observedShape),e.invalidatedReason!==void 0&&(typeof e.invalidatedReason!="string"||e.invalidatedReason.length===0||e.invalidatedReason.length>128))throw new Error("cache entry invalidatedReason is invalid");if(!e.evidence||typeof e.evidence!="object"||Array.isArray(e.evidence))throw new Error("cache entry evidence must be an object");for(const[a,o]of Object.entries(e.evidence)){if(!zs.has(a))throw new Error(`cache entry evidence contains unknown key ${a}`);if(Hs.has(a)){if(!Number.isInteger(o)||o<0)throw new Error(`cache entry evidence.${a} must be a non-negative integer`)}else if(Ws.has(a))Ge(o,`cache entry evidence.${a}`);else if(a==="exact"){if(typeof o!="boolean")throw new Error("cache entry evidence.exact must be boolean")}else if(!Number.isFinite(o))throw new Error(`cache entry evidence.${a} must be finite`)}if(e.verdict==="selected"&&e.evidence.confirmationCount!==Ze.length)throw new Error("selected cache verdict requires both confirmation roles");let r;try{r=JSON.stringify(e.evidence??null).length}catch{throw new Error("cache entry evidence is not serializable")}if(r>Os)throw new Error("cache entry evidence exceeds the bounded payload limit");return e}function uo(e){e.forEach(St);const t=new Map;for(const n of e){const r=(t.get(n.scopeKey)??0)+1;if(r>jn)throw new Error("cache entries exceed the per-scope LRU bound");t.set(n.scopeKey,r)}}function hi({identity:e,scopeKey:t,kernelTuneId:n,signatureKey:r,createdAt:a,lastUsedAt:o=a,ttlClass:s,verdict:i,schedule:u,observedShape:l=null,screenSubmitShrinks:p=0,evidence:f={}}={}){const m={protocolRev:We,identity:e,scopeKey:t,kernelTuneId:n,signatureKey:r,createdAt:a,lastUsedAt:o,ttlClass:s,verdict:i,schedule:u&&{inFlight:u.inFlight,groupSteps:u.groupSteps},observedShape:l?{...l}:null,screenSubmitShrinks:p,evidence:{...f}};return St(m),m}function fi(e){if(!Array.isArray(e)||e.length>Ht)throw new Error(`cache entries must be an array of at most ${Ht}`);return uo(e),JSON.stringify({schema:ao,entries:e})}function mi(e){if(e==null||e==="")return{status:"miss",entries:[]};try{const t=JSON.parse(e);return t?.schema!==ao||!Array.isArray(t.entries)||t.entries.length>Ht?{status:"corrupt",entries:[]}:(uo(t.entries),{status:null,entries:t.entries})}catch{return{status:"corrupt",entries:[]}}}function kr(e,t){return Math.max(e,t)/Math.min(e,t)}function ho(e,t){try{Nn(e,"storedShape"),Nn(t,"currentShape")}catch{return!0}return!e||!t?!1:kr(e.targetTokenP50,t.targetTokenP50)>yr||kr(e.targetTokenP90,t.targetTokenP90)>yr}function pi(e,{now:t=Date.now(),identity:n,kernelTuneId:r,signatureKey:a,observedShape:o=null}={}){try{St(e)}catch{return{status:"corrupt-entry",entry:null}}if(e.protocolRev!==We)return{status:"protocol-mismatch",entry:null};if(e.invalidatedReason)return{status:e.invalidatedReason,entry:null};if(e.identity!==n)return{status:"identity-mismatch",entry:null};if(e.kernelTuneId!==r)return{status:"kernel-tune-mismatch",entry:null};if(e.signatureKey!==a)return{status:"signature-mismatch",entry:null};const s=e.ttlClass==="negative"?$s:ro,i=t-e.createdAt;return!Number.isFinite(t)||i<0||i>=s?{status:"expired",entry:null}:o&&e.observedShape&&ho(e.observedShape,o)?{status:"shape-drift",entry:null}:{status:null,entry:e}}function Cr(e,t,n=jn){if(!Array.isArray(e))throw new Error("cache entries must be an array");St(t),Ce(n,"maxPerScope");const r=e.map(s=>St(s)).filter(s=>s.identity!==t.identity);r.push(t);const a=new Map;for(const s of r){const i=a.get(s.scopeKey)??[];i.push(s),a.set(s.scopeKey,i)}const o=[];for(const s of a.values())s.sort((i,u)=>u.lastUsedAt-i.lastUsedAt||u.createdAt-i.createdAt||i.identity.localeCompare(u.identity)),o.push(...s.slice(0,n));return o.sort((s,i)=>i.lastUsedAt-s.lastUsedAt||i.createdAt-s.createdAt||s.identity.localeCompare(i.identity)).slice(0,Ht)}function hn(e,t){if(!Array.isArray(e))throw new Error("cache entries must be an array");return ce(t,"cache identity",Qe),e.filter(n=>n?.identity!==t)}const gi=new Set(["amortizationRev","protocolRev","identity","scopeKey","kernelTuneId","signatureKey","createdAt","lastUsedAt","schedule","profiledWallMs","profiledDecodeMs","rowCount","batchCount","tokenCount","submitShrinks"]);function lt(e){if(!e||typeof e!="object"||Array.isArray(e))throw new Error("observation entry must be an object");for(const t of Object.keys(e))if(!gi.has(t))throw new Error(`observation entry contains unknown key ${t}`);if(!Number.isInteger(e.amortizationRev)||e.amortizationRev<=0)throw new Error("observation entry amortizationRev must be a positive integer");if(!Number.isInteger(e.protocolRev)||e.protocolRev<=0)throw new Error("observation entry protocolRev must be a positive integer");if(ce(e.identity,"observation entry identity",Qe),ce(e.scopeKey,"observation entry scopeKey",512),ce(e.kernelTuneId,"observation entry kernelTuneId",512),ce(e.signatureKey,"observation entry signatureKey",Qe),Ge(e.createdAt,"observation entry createdAt"),Ge(e.lastUsedAt,"observation entry lastUsedAt"),e.lastUsedAtoo)throw new Error("observations exceed the per-scope LRU bound");t.set(n.scopeKey,r)}}function bi({amortizationRev:e,protocolRev:t,identity:n,scopeKey:r,kernelTuneId:a,signatureKey:o,createdAt:s,lastUsedAt:i=s,schedule:u=Le,profiledWallMs:l,profiledDecodeMs:p,rowCount:f,batchCount:m,tokenCount:d,submitShrinks:v=0,...y}={}){const g=Object.keys(y)[0];if(g)throw new Error(`observation entry contains unknown key ${g}`);const h={amortizationRev:Et,protocolRev:We,identity:n,scopeKey:r,kernelTuneId:a,signatureKey:o,createdAt:s,lastUsedAt:i,schedule:u&&{inFlight:u.inFlight,groupSteps:u.groupSteps},profiledWallMs:l,profiledDecodeMs:p,rowCount:f,batchCount:m,tokenCount:d,submitShrinks:v};return lt(h),h}function yi(e){if(!Array.isArray(e)||e.length>Wt)throw new Error(`observations must be an array of at most ${Wt}`);return fo(e),JSON.stringify({schema:so,entries:e})}function Mr(e){if(e==null||e==="")return{status:"miss",entries:[]};try{const t=JSON.parse(e);return t?.schema!==so||!Array.isArray(t.entries)||t.entries.length>Wt||Object.keys(t).some(n=>!["schema","entries"].includes(n))?{status:"corrupt",entries:[]}:(fo(t.entries),{status:null,entries:t.entries})}catch{return{status:"corrupt",entries:[]}}}function vi(e,{now:t=Date.now(),identity:n,kernelTuneId:r,signatureKey:a}={}){try{lt(e)}catch{return{status:"corrupt-entry",entry:null}}return e.amortizationRev!==Et?{status:"amortization-mismatch",entry:null}:e.protocolRev!==We?{status:"protocol-mismatch",entry:null}:e.identity!==n?{status:"identity-mismatch",entry:null}:e.kernelTuneId!==r?{status:"kernel-tune-mismatch",entry:null}:e.signatureKey!==a?{status:"signature-mismatch",entry:null}:!Number.isFinite(t)||t=Ls?{status:"expired",entry:null}:{status:null,entry:e}}function xr(e,t,n=oo){if(!Array.isArray(e))throw new Error("observations must be an array");lt(t),Ce(n,"maxPerScope");const r=e.map(s=>lt(s)).filter(s=>s.identity!==t.identity);r.push(t);const a=new Map;for(const s of r){const i=a.get(s.scopeKey)??[];i.push(s),a.set(s.scopeKey,i)}const o=[];for(const s of a.values())s.sort((i,u)=>u.lastUsedAt-i.lastUsedAt||u.createdAt-i.createdAt||i.identity.localeCompare(u.identity)),o.push(...s.slice(0,n));return o.sort((s,i)=>i.lastUsedAt-s.lastUsedAt||i.createdAt-s.createdAt||s.identity.localeCompare(i.identity)).slice(0,Wt)}function fn(e){return{status:"needs-baseline-observation",reason:e,admit:!1,observedProfiledWallMs:null,minimumExpectedSavingMs:null,projectedWorstCaseScreenMs:null,paybackRatio:null}}function Si({observation:e=null,projection:t=null,promotionGain:n=no}={}){if(!e)return fn("missing-observation");try{lt(e)}catch{return fn("invalid-observation")}const r=t?.projectedMs;if(!(Number.isFinite(r)&&r>0&&Number.isFinite(n)&&n>0&&n<=1))return fn("invalid-projection");const a=e.profiledWallMs,o=a*n,s=o/r,i=o>=r;return{status:i?"admitted":"unamortized",reason:i?null:"insufficient-payback",admit:i,observedProfiledWallMs:a,minimumExpectedSavingMs:o,projectedWorstCaseScreenMs:r,paybackRatio:s}}function wi(e,t,{required:n=!1,max:r=1/0}={}){if(!Array.isArray(e)||n&&e.length===0)throw new Error(`${t} must be ${n?"a non-empty":"an"} array`);if(e.length>r)throw new Error(`${t} exceeds its bounded size`);const a=e.map(o=>{if(!Number.isInteger(o)||o<0)throw new Error(`${t} must contain non-negative integers`);return o});if(new Set(a).size!==a.length)throw new Error(`${t} must not contain duplicates`);return[...a].sort((o,s)=>o-s)}function Ei(e){if(!Array.isArray(e))throw new Error("confirmationPlan must be an array");if(e.length>Ze.length)throw new Error("confirmationPlan exceeds its bounded size");const t=e.map((n,r)=>{if(!n||typeof n!="object"||Array.isArray(n))throw new Error(`confirmationPlan[${r}] must be an object`);if(Object.keys(n).some(i=>!["role","batchIndex","region"].includes(i)))throw new Error(`confirmationPlan[${r}] contains an unknown key`);const o=Ze[r];if(n.role!==o)throw new Error(`confirmationPlan[${r}] must have role ${o}`);if(!Number.isInteger(n.batchIndex)||n.batchIndex<0)throw new Error(`confirmationPlan[${r}].batchIndex must be non-negative`);if(!(Number.isInteger(n.region)&&n.region>0||typeof n.region=="string"&&n.region.length>0&&n.region.length<=64))throw new Error(`confirmationPlan[${r}].region is invalid`);return{role:n.role,batchIndex:n.batchIndex,region:n.region}});if(new Set(t.map(({batchIndex:n})=>n)).size!==t.length)throw new Error("confirmationPlan batch indices must not contain duplicates");return t}function ki(e,t){const n=t%e.length;return[...e.slice(n),...e.slice(0,n)]}function Ar(e,t=e.groupSteps){return{inFlight:e.inFlight,groupSteps:qs(e.groupSteps,t)}}function Ci(e,t){return`${e}:${t}`}function Mi(e){if(!Array.isArray(e)||e.length===0)throw new Error("runBatch rows must be a non-empty array");const t=e.map((n,r)=>{if(!n||typeof n!="object"||!Array.isArray(n.ids)||n.ids.length<2||n.ids.some(a=>!Number.isInteger(a)||a<0)||typeof n.forcedEos!="boolean")throw new Error(`runBatch rows[${r}] is invalid`);return[n.ids,n.forcedEos]});return{fingerprint:JSON.stringify(t),targetTokenLengths:e.map(n=>n.ids.length-1)}}function xi(e,t){if(!e||typeof e!="object"||Array.isArray(e))throw new Error("runBatch result must be an object");if(e.cleanupComplete!==!0)throw new Error("runBatch cleanupComplete evidence must be true");const n=Ce(e.groupStepsStart,"runBatch groupStepsStart"),r=Ce(e.groupStepsFinal,"runBatch groupStepsFinal");if(n!==t.groupSteps)throw new Error("runBatch groupStepsStart does not match the admitted schedule");if(r>n)throw new Error("runBatch groupStepsFinal must not grow");if(!vt(e.submitShrinks))throw new Error("runBatch submitShrinks must be a non-negative integer");if(e.submitShrinks===0&&r!==n||e.submitShrinks>0&&r>=n)throw new Error("runBatch submitShrinks and groupStepsFinal are inconsistent");if(!Number.isInteger(e.compactions)||e.compactions<0)throw new Error("runBatch compactions must be a non-negative integer");return{...Mi(e.rows),groupStepsStart:n,groupStepsFinal:r,submitShrinks:e.submitShrinks,wallMs:Z(e.wallMs,"runBatch wallMs"),decodeMs:Z(e.decodeMs,"runBatch decodeMs"),compactions:e.compactions}}function Ai(e){return De.map(t=>{const n=e.get(t.id),r=yt(n.records.map(s=>s.wallMs)),a=yt(n.records.map(s=>s.decodeMs)),o={id:t.id,status:n.status==="pending"&&n.records.length>0?"partial":n.status,completedRuns:n.records.length,submitShrinks:n.records.reduce((s,i)=>s+i.submitShrinks,0)};return r!==null&&(o.medianWallMs=r),a!==null&&(o.medianDecodeMs=a),o})}function Ni(e){if(!e||e.records.length===0)return null;const t=e.records.filter(r=>r.phase==="screen"),n=t.flatMap(r=>r.targetTokenLengths);return n.length===0?null:{targetTokenP50:Cn(n,.5),targetTokenP90:Cn(n,.9),compactionRate:t.filter(r=>r.compactions>0).length/t.length}}function Ti(e){if(!e||typeof e!="object"||Array.isArray(e))throw new Error("safetyOptions must be an object");if(Z(e.submitBudgetMs,"safetyOptions.submitBudgetMs"),typeof e.encSplitSubmits!="boolean")throw new Error("safetyOptions.encSplitSubmits must be boolean");return Object.freeze({...e})}function Nr(e){const t=e();if(!Number.isFinite(t))throw new Error("schedule tuner clock must be finite");return t}function Tr({decision:e=null,sampleCount:t=0,confirmationCount:n=0,tuneMs:r,projectedMs:a,actualMs:o,overrunMs:s,exact:i=!1,includePerformance:u=!0}){const l={sampleCount:t,confirmationCount:n,tuneMs:r,projectedMs:a,actualMs:o,overrunMs:s,exact:i};return u&&(l.favorableRegions=e?.favorableRegions??0,Number.isFinite(e?.wallGain)&&(l.wallGain=e.wallGain),Number.isFinite(e?.screenWallGain)&&(l.screenWallGain=e.screenWallGain),Number.isFinite(e?.confirmationMinWallGain)&&(l.confirmationMinWallGain=e.confirmationMinWallGain),Number.isFinite(e?.decodeGain)&&(l.decodeGain=e.decodeGain)),l}async function mo({sampleBatchIndices:e,confirmationPlan:t=[],workloadBatchCosts:n,batchRegions:r=null,kernelReferenceMs:a,kernelReferenceCost:o,safetyOptions:s,pretokenize:i,estimateBatch:u,runBatch:l,now:p=Date.now,isCancelled:f=()=>!1,isDeviceHealthy:m=()=>!1,deadlineMs:d=Jt,marginMs:v=Un,safetyFactor:y=Qt,pretokenizeEstimateMs:g=0}={}){const h=wi(e,"sampleBatchIndices",{required:!0,max:Gn.length}),S=Ei(t);if(S.some(({batchIndex:E})=>h.includes(E)))throw new Error("confirmationPlan batches must be unused by the screen");const M=ri(n,h),C=new Map(h.map((E,A)=>[E,M[A]]));let L=null;if(r!=null){if(!Array.isArray(r)||r.length===0)throw new Error("batchRegions must be a non-empty array");if(L=r.map((A,F)=>{if(Number.isInteger(A)&&A>0||typeof A=="string"&&A.length>0&&A.length<=64)return A;throw new Error(`batchRegions[${F}] is invalid`)}),Math.max(...h,...S.map(({batchIndex:A})=>A))>=L.length)throw new Error("batchRegions must cover every screen and confirmation batch");for(const A of S)if(Kt(A.region)!==Kt(L[A.batchIndex]))throw new Error(`confirmationPlan ${A.role} region does not match batchRegions`)}for(const[E,A]of[[i,"pretokenize"],[u,"estimateBatch"],[l,"runBatch"],[p,"now"],[f,"isCancelled"],[m,"isDeviceHealthy"]])if(typeof E!="function")throw new Error(`${A} must be a function`);if(Z(a,"kernelReferenceMs"),Z(o,"kernelReferenceCost"),Z(d,"deadlineMs"),Ge(v,"marginMs"),v>=d)throw new Error("marginMs must be below deadlineMs");Z(y,"safetyFactor"),Ge(g,"pretokenizeEstimateMs");const z=Ti(s),G=new Map(De.map(E=>[E.id,{arm:E,carry:Vs(E.groupSteps),status:"pending",records:[]}])),fe=h.flatMap((E,A)=>ki(De,A).map(F=>({phase:"screen",batchIndex:E,samplePosition:A,region:L?.[E]??`sample-${A+1}`,arm:F}))),me=new Map,we=async(E,A)=>{const F=Ci(E,A.id);if(me.has(F))return me.get(F);const O=Z(await u(E,Ar(A)),`estimateBatch(${E}, ${A.id})`);return me.set(F,O),O};let w=null,V=null,ge=0,Ee=null,J=0,k=!1,B=[];const _=[],I=()=>{if(Ee===null)return 0;const E=Nr(p)-Ee;if(!Number.isFinite(E)||E<0)throw new Error("schedule tuner clock must be monotonic");return E},N=({verdict:E,reason:A=E,schedule:F=Le,source:O="default",cacheable:te,ttlClass:Q,decision:W=null,exact:be=!1,includeCandidateEvidence:ye=!0,includeObservedShape:Ke=!0})=>{const ae=I(),Ie=dn({elapsedMs:ae,deadlineMs:d}),tt=Tr({decision:W,sampleCount:k?h.length:B.length,confirmationCount:_.length,tuneMs:ae,projectedMs:ge,actualMs:ae,overrunMs:Ie.overrunMs,exact:be,includePerformance:!0}),nt=te?Tr({decision:W,sampleCount:k?h.length:B.length,confirmationCount:_.length,tuneMs:ae,projectedMs:ge,actualMs:ae,overrunMs:Ie.overrunMs,exact:be,includePerformance:Q!=="negative"}):{};return{protocolRev:We,verdict:E,reason:A,schedule:{inFlight:F.inFlight,groupSteps:F.groupSteps},source:O,screenSubmitShrinks:J,scheduleTuneMs:ae,evidence:tt,confirmationPlan:S.map(kt=>({...kt})),completedConfirmationRoles:W?.completedRoles?[...W.completedRoles]:[],candidateEvidence:ye?Ai(G):[],observedShape:Ke?Ni(G.get("base")):null,projection:{preGate:w?{rawGpuMs:w.rawGpuMs,rawProjectedMs:w.rawProjectedMs,projectedMs:w.projectedMs,runCount:w.runCount,budgetMs:w.budgetMs,admission:w.admission}:null,postPilot:V?{...V}:null},deadline:Ie,cache:{cacheable:te,ttlClass:Q,evidence:nt}}},T=()=>N({verdict:"cancelled",cacheable:!1,ttlClass:null,includeCandidateEvidence:!1,includeObservedShape:!1}),j=E=>N({verdict:E,cacheable:!0,ttlClass:"negative",includeCandidateEvidence:!1,includeObservedShape:!1});if(f())return T();const $=[];for(const E of fe){if(f())return T();$.push(await we(E.batchIndex,E.arm))}const ee=An({referenceMs:a,referenceCost:o,runCosts:$,safetyFactor:y});w={...ee,rawProjectedMs:g+ee.rawGpuMs,projectedMs:g+ee.projectedMs},ge=w.projectedMs;const pe=ii(w,d,v);if(w.budgetMs=pe.budgetMs,w.admission=pe.admission,!pe.admit)return j("projected-over-budget");Ee=Nr(p);const Me=[...new Set([...h,...S.map(({batchIndex:E})=>E)])].sort((E,A)=>E-A);for(const E of Me)if(f()||(await i(E),f()))return T();if(I()>=d)return j("timeout");let oe={ms:a,cost:o};const K=async E=>{if(f())return{terminal:T()};const A=I();if(A>=d)return{terminal:j("timeout")};const F=G.get(E.arm.id),O=Ar(E.arm,F.carry),te=await we(E.batchIndex,E.arm),Q=oe.ms*(te/oe.cost),W=ci({elapsedMs:A,projectedRunMs:Q,deadlineMs:d,marginMs:v,safetyFactor:y});if(!W.admit)return Number.isFinite(W.projectedEndMs)&&(ge=W.projectedEndMs),{terminal:j("projected-over-budget")};let be;try{be=await l(E.batchIndex,O,z)}catch(ae){if(f())return{terminal:T()};if(E.arm.id==="base"||!await m(ae))throw ae;return F.status="error",dn({elapsedMs:I(),deadlineMs:d}).deadlineExceeded?{terminal:j("admission-overrun")}:{candidateError:!0}}const ye=xi(be,O);if(f())return{terminal:T()};if(ye.submitShrinks>0){J+=ye.submitShrinks;const ae={...ye};return delete ae.fingerprint,F.status="submit-shrink",F.records.push({phase:E.phase,batchIndex:E.batchIndex,region:E.region,...ae}),{terminal:N({verdict:"safety-fallback",reason:"submit-shrink",source:"measured",cacheable:!0,ttlClass:"normal",exact:!1})}}return F.carry=Js(F.carry,ye.groupStepsFinal),dn({elapsedMs:I(),deadlineMs:d}).deadlineExceeded?{terminal:j("admission-overrun")}:{trial:{...ye,cost:te}}},P=new Map,Re=(E,A)=>{const F=G.get(E.arm.id),{fingerprint:O,...te}=A,Q={phase:"screen",batchIndex:E.batchIndex,region:E.region,...te};F.records.push(Q);const W=P.get(E.batchIndex)??new Map;if(W.set(E.arm.id,O),P.set(E.batchIndex,W),E.arm.id==="base")for(const be of De.slice(1)){const ye=W.get(be.id);ye!==void 0&&ye!==O&&(G.get(be.id).status="output-mismatch")}else{const be=W.get("base");be!==void 0&&be!==O&&(F.status="output-mismatch")}},x=fe[0],le=await K(x);if(le.terminal)return le.terminal;Re(x,le.trial),oe={ms:le.trial.wallMs,cost:le.trial.cost};const ue=$.slice(1);if(ue.length>0){const E=An({referenceMs:oe.ms,referenceCost:oe.cost,runCosts:ue,safetyFactor:y}),A=I(),F=A+E.rawGpuMs+v,O=A+E.projectedMs+v,te=O<=d,Q=!te&&F<=d;if(V={rawGpuMs:E.rawGpuMs,projectedMs:E.projectedMs,runCount:E.runCount,rawProjectedEndMs:F,projectedEndMs:O,admission:te?"full":Q?"per-run":null},ge=V.projectedEndMs,!te&&!Q)return j("projected-over-budget")}let H=x.batchIndex;for(const E of fe.slice(1)){E.batchIndex!==H&&(P.delete(H),H=E.batchIndex);const A=G.get(E.arm.id);if(E.arm.id!=="base"&&A.status!=="pending")continue;const F=await K(E);if(F.terminal)return F.terminal;F.candidateError||Re(E,F.trial)}P.clear(),k=!0,G.get("base").status="complete";for(const E of De.slice(1)){const A=G.get(E.id),F=A.records.filter(O=>O.phase==="screen");A.status==="pending"&&(A.status=F.length===h.length?"complete":"incomplete")}const xe=new Map,he=E=>{const A=G.get(E.id);return h.map(F=>{const O=G.get("base").records.find(Q=>Q.phase==="screen"&&Q.batchIndex===F),te=A.records.find(Q=>Q.phase==="screen"&&Q.batchIndex===F);return{region:O.region,weight:C.get(F),baselineWallMs:O.wallMs,candidateWallMs:te.wallMs,baselineDecodeMs:O.decodeMs,candidateDecodeMs:te.decodeMs,complete:!0,exact:!0,baselineSubmitShrinks:O.submitShrinks,candidateSubmitShrinks:te.submitShrinks}})},Ae=De.map(E=>{const A=G.get(E.id),F=A.records.filter(Q=>Q.phase==="screen"),O=E.id==="base"||A.status==="complete";let te=1;if(E.id!=="base"&&O){const Q=he(E);xe.set(E.id,Q);const W=xn(Q);te=1-(W.weightedWallGain??W.wallGain)}return{id:E.id,score:te,exact:O,submitShrinks:F.reduce((Q,W)=>Q+W.submitShrinks,0)}}),{candidate:X}=ai(Ae);if(!X)return N({verdict:"keep-default",reason:"no-exact-candidate",source:"measured",cacheable:!0,ttlClass:"normal",exact:!1});const Y=G.get(X.id).arm,Ne=G.get(X.id);B=xe.get(X.id);let q=Er({screenPairs:B});if(q.reason!=="needs-confirmation")return N({verdict:"keep-default",reason:q.reason,source:"measured",cacheable:!0,ttlClass:"normal",decision:q,exact:!0});for(let E=0;En.inFlight===e.inFlight&&n.groupSteps===e.groupSteps);if(!t)throw new Error("decodeScheduleOverride must be a version-1 schedule arm");return{inFlight:t.inFlight,groupSteps:t.groupSteps}}function Pr(e=null){return e==="shadow"?"shadow":e==="1"||e==="apply"?"apply":e==="auto"?"auto":"off"}function $i(e,t,n,r={}){const a=e??{},o=["dModel","heads","headDim","ffn","encLayers","decLayers","vocab","maxPos","srcCap","decodeCap"].map(l=>t[l]??"").join("x"),s=`${r.subgroupMinSize??0}-${r.subgroupMaxSize??0}`,i=r.immediates==="on"?"on":"off",u=r.uniformPool===!0||r.uniformPool==="on"||r.uniformPool==="b64"?"b64":"off";return[`moxhi.autotune.v${Kr}`,a.vendor??"",a.architecture??"",a.device??"",`sg${s}`,o,n,`imm${i}`,`pool${u}`,r.browserMajor??"unknown"].join("|")}const Li=720*3600*1e3;function Oi(e){if(e==null)return{parsed:null,status:"miss"};try{const t=JSON.parse(e);return!t||typeof t!="object"||Array.isArray(t)?{parsed:null,status:"corrupt"}:{parsed:t,status:null}}catch{return{parsed:null,status:"corrupt"}}}function Fi(e,t,n=Date.now(),r=Li){const a=Date.parse(e?.date??""),o=n-a;return!Number.isFinite(a)||o<0||o>=r?{status:"expired",measuredAt:null}:oa(e?.tuned,t)?{status:null,measuredAt:a}:{status:"safety-rejected",measuredAt:null}}function _i(e,t){return aa(e,t)?"accepted":"mismatch"}const Di=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Gi=e=>typeof e=="string"&&Di.test(e)?e:null,ht=(e,{priorTuneId:t=null,cachedUs:n=null,currentUs:r=null,error:a=null}={})=>({status:e,priorTuneId:t,cachedUs:n,currentUs:r,error:a});function Ui(e){return e.map((t,n)=>n).sort((t,n)=>e[t]-e[n])}function ji(e,t=192,n=576){return Math.max(t,Math.min(n,Math.floor(t*224/e)))}function Wn({ua:e="",maxTouchPoints:t=0}={}){const n=typeof e=="string"?e:"";return/iPhone|iPad|iPod|Android/.test(n)||/Macintosh/.test(n)&&t>1}function zi({ua:e=""}={}){return/Android/.test(typeof e=="string"?e:"")}function po({ua:e="",maxTouchPoints:t=0,capParam:n=null}={}){const r=Math.floor(Number(n));return Number.isFinite(r)&&r>=1?Math.min(r,2048):Wn({ua:e,maxTouchPoints:t})?192:576}function go({ua:e="",maxTouchPoints:t=0,budgetParam:n=null}={}){if(typeof n=="string"&&n.trim()==="0")return 1/0;const r=Math.floor(Number(n));return n!==""&&n!==null&&n!==void 0&&Number.isFinite(r)&&r>=1?Math.min(r,1024*1024):Wn({ua:e,maxTouchPoints:t})?16*1024:1/0}const Rr="moxhi-mobile-kv-v2";function bo(e=null){if(e==null||String(e).trim()==="")return{mode:"auto",capacity:null};const t=String(e).trim();if(t==="0")return{mode:"legacy",capacity:null};if(!/^\d+$/.test(t))return{mode:"legacy",capacity:null};const n=Number(t);return!Number.isInteger(n)||n<1||n>Bn?{mode:"legacy",capacity:null}:{mode:"forced",capacity:n}}function Hi(e,{modelId:t="",mobile:n=!1,plannerParam:r=null,kvcapParam:a=null,tokenBudget:o=1/0}={}){if(!Number.isInteger(e)||e<1)throw new Error(`file KV policy: bad S=${e}`);const s=bo(a),i=r==="1"&&n&&t==="moxhi"&&s.mode!=="legacy",u=s.mode==="forced"?s.capacity:null;if(!i)return{rowCap:null,tokenBudget:o,kvCapacity:u,label:u?`forced-kv${u}`:"legacy-full-kv",autoRows:!1};let l=192,p=Bn,f=o;return e<=32?(l=384,p=64,f=1/0):e<=64?(l=192,p=112,f=1/0):e<=96&&(l=192,p=128,f=1/0),{rowCap:l,tokenBudget:f,kvCapacity:u??p,label:u?`${Rr}+forced-kv${u}`:Rr,autoRows:!0}}function Wi({modelId:e="",ua:t="",maxTouchPoints:n=0,plannerParam:r=null,kvcapParam:a=null,capParam:o=null,budgetParam:s=null}={}){const i=Wn({ua:t,maxTouchPoints:n}),u=bo(a),l=r==="1"&&i&&e==="moxhi"&&u.mode!=="legacy",p=go({ua:t,maxTouchPoints:n,budgetParam:s}),f=po({ua:t,maxTouchPoints:n,capParam:o}),m=o!=null&&String(o).trim()!==""&&Number.isFinite(Number(o))&&Math.floor(Number(o))>=1,d=l&&!m?576:f,v=g=>Hi(g,{modelId:e,mobile:i,plannerParam:r,kvcapParam:a,tokenBudget:p}),y=v(32);return{mobile:i,autoRows:l,absCap:d,tokenBudget:p,forcedCapacity:u.mode==="forced"?u.capacity:null,policyLabel:y.label,policyForS:v,kvCapacityForS:g=>v(g).kvCapacity}}function Ki({param:e=null}={}){return e==="1"}function Br(){return po({ua:navigator.userAgent??"",maxTouchPoints:navigator.maxTouchPoints??0,capParam:new URLSearchParams(location.search).get("cap")})}function Vi(){return go({ua:navigator.userAgent??"",maxTouchPoints:navigator.maxTouchPoints??0,budgetParam:new URLSearchParams(location.search).get("tokenbudget")})}function yo(e,t,n,r=192,a=576,o=1/0,s=null){const i=[],u=[];for(let l=0;lC)break;f=v,m=y,p++}i.push([l,p]),u.push(m),l=p}return{ranges:i,buckets:u}}function qi(e,t,n,r=192,a=576,o=1/0,s=null){return yo(e,t,n,r,a,o,s).ranges}function Ji(){return Ki({param:new URLSearchParams(location.search).get("inplacecompact")})}const Be=e=>Math.round(e*10)/10,mn=e=>Math.round(e*100)/100;async function Qi(e,t=globalThis.crypto){if(!t?.subtle?.digest)throw new Error("SHA-256 unavailable");const n=new TextEncoder().encode(String(e));return[...new Uint8Array(await t.subtle.digest("SHA-256",n))].map(a=>a.toString(16).padStart(2,"0")).join("")}function Xi(e,t=null){if(!Array.isArray(e))throw new Error("aggregateBatchProfile needs an array");const n=e.reduce((o,s)=>o+(Number(s.ms)||0),0),r=e.reduce((o,s)=>o+(Number(s.decodeMs)||0),0),a={};for(const o of e){if(!Number.isInteger(o.S)||o.S<1)throw new Error(`aggregateBatchProfile: bad S=${o.S}`);const s=a[o.S]??={batches:0,rows:0,tokens:0,compactions:0,kvGrows:0,kvGrowsWithPending:0,kvGrowBindGroupsPurged:0,ms:0,encoderMs:0,decodeMs:0,maxB:0,maxCap:0,maxSteps:0,maxSourceTokenArea:0,minInitialKvCapacity:1/0,maxInitialKvCapacity:0,maxFinalKvCapacity:0,logicalArenaPeakMB:0,submittedArenaPeakMB:0};s.batches++,s.rows+=Number(o.B)||0,s.tokens+=Number(o.tokens)||0,s.compactions+=Number(o.compactions)||0,s.kvGrows+=Number(o.kvGrows)||0,s.kvGrowsWithPending+=Number(o.kvGrowsWithPending)||0,s.kvGrowBindGroupsPurged+=Number(o.kvGrowBindGroupsPurged)||0,s.ms+=Number(o.ms)||0,s.encoderMs+=Number(o.encoderMs)||0,s.decodeMs+=Number(o.decodeMs)||0,s.maxB=Math.max(s.maxB,Number(o.B)||0),s.maxCap=Math.max(s.maxCap,Number(o.cap)||0),s.maxSteps=Math.max(s.maxSteps,Number(o.steps)||0);const i=Number(o.initialKvCapacity)||0;i>0&&(s.minInitialKvCapacity=Math.min(s.minInitialKvCapacity,i)),s.maxInitialKvCapacity=Math.max(s.maxInitialKvCapacity,i),s.maxFinalKvCapacity=Math.max(s.maxFinalKvCapacity,Number(o.finalKvCapacity)||0),s.maxSourceTokenArea=Math.max(s.maxSourceTokenArea,(Number(o.B)||0)*o.S),s.logicalArenaPeakMB=Math.max(s.logicalArenaPeakMB,Number(o.logicalArenaPeakMB)||0),s.submittedArenaPeakMB=Math.max(s.submittedArenaPeakMB,Number(o.submittedArenaPeakMB)||0)}for(const o of Object.values(a))Number.isFinite(o.minInitialKvCapacity)||(o.minInitialKvCapacity=0),o.ms=Be(o.ms),o.encoderMs=Be(o.encoderMs),o.decodeMs=Be(o.decodeMs),o.batchWallPct=n>0?mn(o.ms/n*100):0,o.decodeSharePct=r>0?mn(o.decodeMs/r*100):0,o.fileWallPct=Number.isFinite(t)&&t>0?mn(o.ms/t*100):null;return{profiledMs:Be(n),profiledDecodeMs:Be(r),sBuckets:a}}const Tn=64,Yi=Tn;function Gt(e,t="unknown"){return(String(e??"").trim()||t).slice(0,96)}function Zi(e={},{subgroupMinSize:t=0,subgroupMaxSize:n=0}={}){return[Gt(e.vendor),Gt(e.architecture),Gt(e.device),`sg${Number(t)||0}-${Number(n)||0}`].join("|")}function ec({batchSize:e,plannedS:t,maxChars:n}={}){if(!Number.isInteger(e)||e<1)throw new Error(`schedule batchSize must be positive, got ${e}`);if(!Number.isInteger(t)||t<1)throw new Error(`schedule plannedS must be positive, got ${t}`);if(!Number.isFinite(n)||n<0)throw new Error(`schedule maxChars must be non-negative, got ${n}`);const r=ua(n),a=Math.sqrt(e/Tn),o=Math.max(1,t/96);return Tn*a*r*o}function Ir(e,t){const n=[...e].sort((s,i)=>s-i),r=(n.length-1)*t,a=Math.floor(r),o=Math.ceil(r);return a===o?n[a]:n[a]+(n[o]-n[a])*(r-a)}function tc(e,t,n){return e.length===0||n<1?null:{targetTokenP50:Ir(e,.5),targetTokenP90:Ir(e,.9),compactionRate:t/n}}function pn(e,t){if(!e?.getItem)return null;try{return e.getItem(t)}catch{return null}}function ct(e,t,n){if(e)try{n.length===0?e.removeItem?.(t):e.setItem?.(t,fi(n))}catch{}}function $t(e,t,n){if(!e)return!1;try{if(n.length===0){if(typeof e.removeItem!="function")return!1;e.removeItem(t)}else{if(typeof e.setItem!="function")return!1;e.setItem(t,yi(n))}return!0}catch{return!1}}function Lt({selectedSchedule:e,telemetry:t,cacheHit:n=!1,cachedObservedShape:r=null,driftBatchIndices:a=[],invalidate:o=()=>{},recordBaselineObservation:s=()=>!1}){return{selectedSchedule:{inFlight:e.inFlight,groupSteps:e.groupSteps},telemetry:t,cacheHit:n,cachedObservedShape:r,driftBatchIndices:[...a],invalidate:o,recordBaselineObservation:s}}async function nc({enabled:e=!1,amortizationPolicy:t="bypass",configuredSchedule:n=Le,eligibilityInput:r={},buildWorkload:a,adapterKey:o,modelId:s,weightsId:i,dtype:u,browserMajor:l,kernelTuneId:p,modes:f,scopeKey:m,kernelReferenceMs:d,kernelReferenceCost:v=Yi,safetyOptions:y,storage:g=null,runner:h=mo,pretokenize:S,estimateBatch:M,runBatch:C,isCancelled:L=()=>!1,isDeviceHealthy:z=()=>!1,clock:G=()=>performance.now(),cacheNow:fe=()=>Date.now()}={}){const me={inFlight:n.inFlight,groupSteps:n.groupSteps},we=t==="automatic",w={protocolRev:We,enabled:e===!0,eligible:!1,source:"default",reason:e===!0?null:"disabled",configuredSchedule:{...me},selectedSchedule:{...me},effectiveSchedule:{...me},workload:null,evidence:null,candidateEvidence:[],observedShape:null,projection:null,deadline:null,screenSubmitShrinks:0,selectedGain:null,screenGain:null,confirmationMinGain:null,sampleCount:0,confirmationCount:0,confirmationPlan:[],completedConfirmationRoles:[],scheduleTuneMs:0,invalidatedReason:null,cache:{status:"not-checked",write:null,verdict:null,persistent:g?.persistent!==!1},amortization:{revision:Et,status:e&&!we?"bypass":"not-checked",reason:null,observationCacheState:"not-checked",observationAgeMs:null,observedProfiledWallMs:null,minimumExpectedSavingMs:null,projectedWorstCaseScreenMs:null,paybackRatio:null,write:null,persistent:g?.persistent!==!1}},V=()=>Lt({selectedSchedule:me,telemetry:w});if(!e)return V();const ge=oi(r);if(w.eligible=ge.eligible,w.reason=ge.reason,!ge.eligible)return V();if(!(Number.isFinite(d)&&d>0))return w.reason="kernel-reference-missing",V();if(typeof a!="function"||typeof h!="function")return w.reason="integration-unavailable",V();if(L())return w.reason="cancelled",V();const Ee=G(),J=()=>{const x=G()-Ee;w.scheduleTuneMs=Number.isFinite(x)&&x>0?x:0};let k,B,_,I,N,T,j,$=[],ee,pe;try{if(k=await a(),!k||!Array.isArray(k.batchCosts)||k.batchCosts.length===0)throw new Error("schedule workload is missing batch costs");const x=k.batchRegions??k.signatureInput?.plannedSourceBuckets??null;ee=ei(k.batchCosts,Gn,x),pe=ni(k.batchCosts,ee,x),B=Ys(k.signatureInput),_=Zs(B);const le={adapterKey:o,modelId:s,weightsId:i,dtype:u,browserMajor:l,kernelTuneId:p,modes:f,signature:B};I=co(le),N=ui(m),we&&(T=li(le),j=di(m))}catch(x){return w.reason="workload-preparation-error",w.error=String(x?.message??x).slice(0,160),J(),V()}w.workload=B;const Me=mi(pn(g,N));$=Me.entries,w.cache.status=Me.status??"miss",Me.status==="corrupt"&&ct(g,N,[]);const oe=fe();let K=$.find(x=>x.identity===I)??null;if(K){const x=pi(K,{now:oe,identity:I,kernelTuneId:p,signatureKey:_});if(x.entry){K={...x.entry,lastUsedAt:oe},$=Cr($,K),ct(g,N,$),w.source="cache",w.reason=K.verdict,w.selectedSchedule={...K.schedule},w.effectiveSchedule={...K.schedule},w.evidence={...K.evidence},w.observedShape=K.observedShape?{...K.observedShape}:null,w.screenSubmitShrinks=K.screenSubmitShrinks,w.selectedGain=K.evidence.wallGain??null,w.screenGain=K.evidence.screenWallGain??null,w.confirmationMinGain=K.evidence.confirmationMinWallGain??null,w.sampleCount=K.evidence.sampleCount??0,w.confirmationCount=K.evidence.confirmationCount??0,w.cache.status="hit",w.cache.verdict=K.verdict,we&&(w.amortization.status="cache-hit",w.amortization.reason=null),J();const le=ue=>{$=hn($,I),ct(g,N,$),K=null,w.invalidatedReason=ue,w.cache.status=ue};return Lt({selectedSchedule:K.schedule,telemetry:w,cacheHit:!0,cachedObservedShape:K.observedShape,driftBatchIndices:ee,invalidate:le})}$=hn($,I),ct(g,N,$),w.cache.status=x.status,K=null}if(L())return w.reason="cancelled",J(),V();if(we){const x=Mr(pn(g,j));let le=x.entries;w.amortization.observationCacheState=x.status??"miss",x.status==="corrupt"&&$t(g,j,[]);let ue=le.find(he=>he.identity===T)??null;if(ue){const he=vi(ue,{now:oe,identity:T,kernelTuneId:p,signatureKey:_});he.entry?(ue={...he.entry,lastUsedAt:oe},le=xr(le,ue),$t(g,j,le),w.amortization.observationCacheState="hit",w.amortization.observationAgeMs=oe-ue.createdAt):(le=le.filter(Ae=>Ae.identity!==T),$t(g,j,le),w.amortization.observationCacheState=he.status,ue=null)}let H=null;if(ue)try{H=si({kernelReferenceMs:d,kernelReferenceCost:v,sampleCosts:ee.map(he=>k.batchCosts[he]),armCount:De.length,confirmationRounds:2,pretokenizeMs:0})}catch{H=null}const xe=Si({observation:ue,projection:H});if(Object.assign(w.amortization,xe),!xe.admit){w.reason=xe.status;let he=!1;const Ae=(X={})=>{if(he)return w.amortization.write="duplicate",!1;he=!0;const Y=q=>q?.inFlight===Le.inFlight&&q?.groupSteps===Le.groupSteps;if(!(X.complete===!0&&X.cancelled===!1&&X.deviceHealthy===!0&&Y(X.configuredSchedule)&&Y(X.effectiveSchedule)&&X.rowCount===r.uncachedRows&&X.batchCount===k.batchCosts.length&&X.submitShrinks===0))return w.amortization.write="rejected",!1;try{const q=fe(),E=bi({identity:T,scopeKey:m,kernelTuneId:p,signatureKey:_,createdAt:q,schedule:Le,profiledWallMs:X.profiledWallMs,profiledDecodeMs:X.profiledDecodeMs,rowCount:X.rowCount,batchCount:X.batchCount,tokenCount:X.tokenCount,submitShrinks:X.submitShrinks}),A=Mr(pn(g,j)),F=xr(A.status===null?A.entries:[],E),O=$t(g,j,F);return w.amortization.write=O?"stored":"unavailable",O}catch{return w.amortization.write="rejected",!1}};return J(),Lt({selectedSchedule:me,telemetry:w,recordBaselineObservation:Ae})}}const P=await h({sampleBatchIndices:ee,confirmationPlan:pe,workloadBatchCosts:[...k.batchCosts],batchRegions:k.batchRegions??k.signatureInput?.plannedSourceBuckets??null,kernelReferenceMs:d,kernelReferenceCost:v,safetyOptions:y,pretokenize:S,estimateBatch:M,runBatch:C,now:G,isCancelled:L,isDeviceHealthy:z});if(J(),L())return w.source="default",w.reason="cancelled",w.cache.write="not-cacheable",V();w.source=P.source,w.reason=P.reason,w.selectedSchedule={...P.schedule},w.effectiveSchedule={...P.schedule},w.evidence=P.evidence?{...P.evidence}:null,w.candidateEvidence=Array.isArray(P.candidateEvidence)?P.candidateEvidence.map(x=>({...x})):[],w.observedShape=P.observedShape?{...P.observedShape}:null,w.projection=P.projection?{...P.projection}:null,w.deadline=P.deadline?{...P.deadline}:null,w.screenSubmitShrinks=P.screenSubmitShrinks??0,w.selectedGain=P.evidence?.wallGain??null,w.screenGain=P.evidence?.screenWallGain??null,w.confirmationMinGain=P.evidence?.confirmationMinWallGain??null,w.sampleCount=P.evidence?.sampleCount??0,w.confirmationCount=P.evidence?.confirmationCount??0,w.confirmationPlan=Array.isArray(P.confirmationPlan)?P.confirmationPlan.map(x=>({...x})):pe.map(x=>({...x})),w.completedConfirmationRoles=Array.isArray(P.completedConfirmationRoles)?[...P.completedConfirmationRoles]:[],w.cache.verdict=P.verdict,P.cache?.cacheable?(K=hi({identity:I,scopeKey:m,kernelTuneId:p,signatureKey:_,createdAt:oe,ttlClass:P.cache.ttlClass,verdict:P.verdict,schedule:P.schedule,observedShape:P.observedShape,screenSubmitShrinks:P.screenSubmitShrinks,evidence:P.cache.evidence}),$=Cr($,K),ct(g,N,$),w.cache.write="stored"):w.cache.write="not-cacheable";const Re=x=>{K&&($=hn($,I),ct(g,N,$),K=null),w.invalidatedReason=x,w.cache.status=x};return Lt({selectedSchedule:P.schedule,telemetry:w,invalidate:Re})}async function rc({model:e=$n(Ln),onPhase:t,onProgress:n,onDeviceLost:r,scheduleAutotuneRunner:a=mo,scheduleCacheStorage:o=null,scheduleDefaultEnabled:s=!1,scheduleDefaultSeedFactory:i=()=>globalThis.crypto?.randomUUID?.()}={}){t?.("gpu");const u=await Jo(),l=u.hasF16?"f16":"f32";let p=null;u.device.lost.then(x=>{x?.reason!=="destroyed"&&(p={reason:x?.reason??"unknown",message:x?.message??""},console.error(`WebGPU device lost (${p.reason}): ${p.message}`),r?.(p))}),t?.("tokenizer");const f=await Qo(e.tokenizerId,e.tokRev),m=new URLSearchParams(location.search);let d=o;const y=["shortlist","directq8","immediates","uniformpool","kvplanner","kvcap","cap","tokenbudget","tm","inplacecompact","submitbudget","encsplit","inflight","groupsteps","scheduletune"].filter(x=>m.get(x)!==null).map(x=>`${x}=${String(m.get(x)).slice(0,24)}`),g=m.has("scheduletune")?Pr(m.get("scheduletune")):null,h=Ts({enabled:s===!0,explicitMode:g,getStorage:()=>d??=zt("local"),createSeed:i}),S=h.mode,M=m.get("shortlist")!=="0",C=m.get("directq8")!=="0",L=m.get("immediates")==="0"?"off":"auto",z=L==="auto"&&u.hasImmediates?"on":"off",G=Ri(z,m.get("uniformpool")),fe=m.get("submitbudget"),me=fe===null?void 0:Number(fe)>0?Number(fe):null,we=Ji(),w=Bi({inFlightParam:m.get("inflight"),groupStepsParam:m.get("groupsteps")}),V=Wi({modelId:e.id,ua:navigator.userAgent??"",maxTouchPoints:navigator.maxTouchPoints??0,plannerParam:m.get("kvplanner"),kvcapParam:m.get("kvcap"),capParam:m.get("cap"),budgetParam:m.get("tokenbudget")}),ge=m.get("encsplit"),Ee=ge===null?zi({ua:navigator.userAgent??""}):ge==="1",J=l==="f16"&&M?Xo(f.idToToken):null;t?.("weights");const k=await Yo(u.device,e.weightsUrl,{targetDtype:l,lmHeadQ8:l==="f16",ffnWT:l==="f16",projWT:l==="f16",directQ8:C,...J?{lmHeadIds:J}:{},onProgress:n});t?.("autotune");let B=null,_=null,I=null,N="default",T=null,j=null,$=null;try{const x=$i(u.adapterInfo,Zo(),l,{subgroupMinSize:u.subgroupMinSize,subgroupMaxSize:u.subgroupMaxSize,immediates:z,uniformPool:G,browserMajor:Hn(navigator.userAgent??"")}),le=localStorage.getItem(x),ue=Oi(le),H=ue.parsed;if(ue.status==="corrupt")try{localStorage.removeItem(x)}catch{}ue.status&&($=ht(ue.status));const xe=await ea({...u,dtype:l});B=xe;let he=!1;const Ae=H?Fi(H,xe):null,X=Gi(H?.tuneId);if(Ae?.status&&($=ht(Ae.status,{priorTuneId:X})),H&&!Ae?.status){const Y=H.timings?.b64?.def?.medianUs;try{const Ne=await ta({...u,dtype:l},k,{immediates:L,uniformPool:G});if(he=_i(Y,Ne.medianUs)==="accepted",he){let q=X,E="accepted";if(!q){q=crypto.randomUUID(),E="legacy-upgraded";try{localStorage.setItem(x,JSON.stringify({...H,tuneId:q}))}catch{}}I=H.tuned,N="cache",_=H.timings??null,T=q,j=Ae.measuredAt,$=ht(E,{priorTuneId:X,cachedUs:Number.isFinite(Y)?Y:null,currentUs:Ne.medianUs})}else $=ht("mismatch",{priorTuneId:X,cachedUs:Number.isFinite(Y)?Y:null,currentUs:Ne.medianUs}),console.info(`autotune cache power-state mismatch (${Y??"missing"}us -> ${Ne.medianUs}us); remeasuring`)}catch(Ne){$=ht("canary-error",{priorTuneId:X,cachedUs:Number.isFinite(Y)?Y:null,error:String(Ne?.message??Ne).slice(0,128)}),console.warn("autotune cache canary failed; remeasuring:",Ne)}}if(!he){const Y=await na({...u,dtype:l},k,{reductionSafety:xe,immediates:L,uniformPool:G,maxB:Br()});if(I=Y.tuned,_=Y.timings??null,T=crypto.randomUUID(),j=Date.now(),N=Y.partial?"partial":"measured",!Y.partial)try{localStorage.setItem(x,JSON.stringify({tuned:I,timings:Y.timings,tuneId:T,date:new Date(j).toISOString()}))}catch{}}}catch(x){if(x?.code==="WEBMT_NO_SAFE_REDUCTION")throw x;console.warn("autotune unavailable, falling back to auto routing:",x)}t?.("ready");const ee=u.adapterInfo,pe=ee.description||[ee.vendor,ee.architecture].filter(Boolean).join(" ")||"GPU",Me=to(),oe=Ms(ee,pe,Me),K=[oe!==pe?pe:null,ee.subgroupMinSize&&ee.subgroupMaxSize?`subgroup ${ee.subgroupMinSize}–${ee.subgroupMaxSize}`:null,navigator.deviceMemory?`RAM ${navigator.deviceMemory>=32?"≥":"~"}${navigator.deviceMemory}GB`:null,navigator.hardwareConcurrency?`~${navigator.hardwareConcurrency} luồng CPU`:null].filter(Boolean).join(" · "),P=l==="f16"?2:4;async function Re(x,{onBatch:le,shouldStop:ue,pack:H=!1,resume:xe=null,tm:he=null,glossary:Ae=null,scheduleTuneMode:X=S,decodeScheduleOverride:Y=null,onScheduleTune:Ne=null}={}){const q=Ii(Y)??{...w},E=performance.now(),A=Dn(x);x=A.text;const F=Yr(x);let O=F.sentences,te=F.paras;if(H){const D=gs(O,te);O=D.rows,te=D.rowParas}if(O.length===0)return{text:"",cancelled:!1,stats:{sentences:0,tokens:0,ms:0,tokPerSec:0}};const Q=Array.isArray(xe)&&xe.length===O.length,W=Q?[...xe]:new Array(O.length).fill(""),be=Q?W.reduce((D,se)=>D+(se?1:0),0):0;let ye=0,Ke=0;if(H&&he?.get){const D=performance.now();try{const se=await he.get(O);for(let ie=0;ieW[se]?null:Ae.protect(D)):null,Ie=ae?ae.filter(Boolean).length:0,tt=[],nt=(H?Ui(O.map(D=>D.length)):O.map((D,se)=>se)).filter(D=>!W[D]),kt=H?V.absCap:Br(),Xt=Math.min(192,kt),zo=H?V.tokenBudget:Vi(),Ct=nt.map(D=>O[D].length),Mt=H?yo(Ct,u,P,Xt,kt,zo,V.policyForS):{ranges:qi(Ct,u,P,Xt,Xt),buckets:[]},{ranges:_e}=Mt,Yt=D=>{const[se,ie]=_e[D],de=nt.slice(se,ie),$e=H?Mt.buckets[D]:null;return{start:se,end:ie,idx:de,plannedS:$e,sources:de.map(Te=>ae?.[Te]?.text??O[Te]),initialKvCapacity:H?V.kvCapacityForS($e):V.forcedCapacity}},Yn=async(D,se,{primeNext:ie=!1,safetyOptions:de=null}={})=>{if(p)throw new Error(`GPU device lost (${p.reason}): ${p.message}`);const $e=Yt(D),Te=de?de.submitBudgetMs:me,U=de?de.encSplitSubmits:Ee;da();const rn=performance.now(),{rows:Rt,metrics:st}=await ia({...u,dtype:l},k,f,$e.sources,{...ca(I,$e.end-$e.start),immediates:L,uniformPool:G,...se,...Te!==void 0?{submitBudgetMs:Te}:{},encSplitSubmits:U,inPlaceCompact:H&&we,kvCapacity:$e.initialKvCapacity,...H?{maxNewTokens:Bn}:{},onPrimed:ie&&D+1<_e.length?()=>{const It=Yt(D+1);It.idx.every(it=>W[it])||hr(f,It.sources).catch(()=>{})}:null}),Bt=performance.now();return{plan:$e,rows:Rt,metrics:st,wallMs:Bt-rn,endedAt:Bt,arenaStats:la()}};let xt=0,At=0,Nt=0,Tt=!1;const Ve={timingMode:"overlapping-gpu-windows",gpuWindowsOverlap:!0,prepMs:0,tmMs:Ke,scheduleTuneMs:0,tokenizeMs:0,encoderMs:0,decodeMs:0,detokMs:0,gapMs:0},rt=[],Zn=performance.now();Ve.prepMs=Zn-E-Ke;const je=Y===null&&H?Pr(X):"off",er=Zi(u.adapterInfo,{subgroupMinSize:u.subgroupMinSize,subgroupMaxSize:u.subgroupMaxSize}),Zt=Gt(k.weightsTag??e.weightsUrl,"dev"),Ho=[er,e.id,Zt,l].join("|").slice(0,512);let en=null;const tr=D=>{if(typeof Ne=="function")try{Ne({active:D,mode:je})}catch{}},Wo=typeof a=="function"?async D=>{tr(!0);try{return await a(D)}finally{tr(!1)}}:null,ne=await nc({enabled:je!=="off",amortizationPolicy:je==="auto"?"automatic":"bypass",configuredSchedule:q,eligibilityInput:{fileMode:H,pack:H,isMobile:V.mobile,uncachedRows:nt.length,plannedBatches:_e.length,kernelTuneSource:N,manualOverrides:{inflight:Y===null?m.get("inflight"):String(q.inFlight),groupsteps:Y===null?m.get("groupsteps"):String(q.groupSteps),submitbudget:m.get("submitbudget"),encsplit:m.get("encsplit")},memorySafe:H&&_e.length>0},buildWorkload:async()=>{const D=Ct.map(ie=>Math.max(1,Math.min(Sn,ie+1)));return en={batchCosts:_e.map(([ie,de],$e)=>{let Te=0;for(let U=ie;Ude-ie),plannedSourceBuckets:[...Mt.buckets],sourceTokenLengths:D,modelId:e.id,weightsId:Zt,dtype:l,policy:{pack:H,kvPlanner:V.policyLabel,tokenBudget:V.tokenBudget,immediates:z,uniformPool:G}}},en},adapterKey:er,modelId:e.id,weightsId:Zt,dtype:l,browserMajor:Pi(navigator.userAgent??""),kernelTuneId:T??"untrusted",modes:{pack:H,kvPlanner:V.policyLabel,kvPolicy:V.policyLabel,tokenBudget:V.tokenBudget,immediates:z,uniformPool:G,inPlaceCompact:H&&we,compact:!0,parameterMode:z},scopeKey:Ho,kernelReferenceMs:Number(_?.b64?.def?.medianUs)/1e3,safetyOptions:{submitBudgetMs:me===void 0?1e3:me,encSplitSubmits:Ee},storage:je!=="off"?d??=zt("local"):d,runner:Wo,pretokenize:async D=>{const se=Yt(D);await hr(f,se.sources)},estimateBatch:async D=>en.batchCosts[D],runBatch:async(D,se,ie)=>{const de=await Yn(D,se,{safetyOptions:ie});return{rows:de.rows,groupStepsStart:de.metrics.groupStepsStart,groupStepsFinal:de.metrics.groupStepsFinal,submitShrinks:de.metrics.submitShrinks,wallMs:de.wallMs,decodeMs:de.metrics.decodeMs,compactions:de.metrics.compactions,cleanupComplete:!0}},isCancelled:()=>ue?.()===!0,isDeviceHealthy:()=>!p,clock:()=>performance.now()});Ve.scheduleTuneMs=ne.telemetry.scheduleTuneMs;const nr={...ne.selectedSchedule},ot=je==="apply"||je==="auto"?{...nr}:{...q};ne.telemetry.mode=je,ne.telemetry.requestedSchedule={...q},ne.telemetry.predictedSchedule={...nr},ne.telemetry.configuredSchedule={...ot};const Ko=je==="auto"&&["admitted","cache-hit"].includes(ne.telemetry.amortization?.status);ne.telemetry.canonicalUsesTunerVerdict=ne.telemetry.eligible&&(je==="apply"||Ko);let Xe={...ot},at=Xe.groupSteps;ne.telemetry.effectiveSchedule={...Xe};const rr=[];let or=0,tn=0;const ar=new Set(ne.driftBatchIndices);let nn=performance.now();for(let D=0;D<_e.length;D++){if(ue?.()){Tt=!0;break}const se=performance.now();Ve.gapMs+=se-nn;const ie={inFlight:Xe.inFlight,groupSteps:Math.min(Xe.groupSteps,at)},de=await Yn(D,ie,{primeNext:!0}),{plan:$e,rows:Te,metrics:U,endedAt:rn,arenaStats:Rt}=de,{idx:st,plannedS:Bt}=$e;Ve.tokenizeMs+=U.tokenizeMs,Ve.encoderMs+=U.encoderMs,Ve.decodeMs+=U.decodeMs,Ve.detokMs+=U.detokMs,U.groupStepsFinal&&(at=Math.min(at,U.groupStepsFinal)),nn=rn;const It=nn-se;rt.push({B:U.B,S:U.S,cap:U.cap,steps:U.steps,submits:U.submits,compactions:U.compactions,compactMode:U.compactMode,inFlight:ie.inFlight,configuredInFlight:ot.inFlight,configuredGroupSteps:ot.groupSteps,groupSteps:U.groupStepsStart,awaitMs:Be(U.awaitMs),cpuEncodeMs:Be(U.cpuEncodeMs),groupStepsFinal:U.groupStepsFinal,submitShrinks:U.submitShrinks,maxGroupAwaitMs:Be(U.maxGroupAwaitMs),plannedS:Bt,initialKvCapacity:U.initialKvCapacity,finalKvCapacity:U.finalKvCapacity,kvGrows:U.kvGrows,kvGrowsWithPending:U.kvGrowsWithPending,kvCapacitySequence:U.kvCapacitySequence,kvGrowBindGroupsPurged:U.kvGrowBindGroupsPurged,sourceTokenArea:U.B*U.S,tokens:U.tokensGenerated,ms:Be(It),encoderMs:Be(U.encoderMs),decodeMs:Be(U.decodeMs),logicalArenaPeakMB:Be(Rt.highWaterBytes/1048576),submittedArenaPeakMB:Be(Rt.submittedHighWaterBytes/1048576)});let it=null;if(ne.telemetry.enabled&&ne.telemetry.eligible&&!ne.telemetry.invalidatedReason&&U.submitShrinks>0)it="submit-shrink";else if(ne.cacheHit&&!ne.telemetry.invalidatedReason&&ne.cachedObservedShape&&ar.has(D)){for(const Oe of Te)rr.push(Math.max(1,(Oe.ids?.length??1)-1));if(U.compactions>0&&or++,tn++,tn===ar.size){const Oe=tc(rr,or,tn);ne.telemetry.canonicalObservedShape=Oe,ho(ne.cachedObservedShape,Oe)&&(it="shape-drift")}}it&&(ne.invalidate(it),Xe={...Le},at=Math.min(at,Le.groupSteps)),ne.telemetry.effectiveSchedule={inFlight:Xe.inFlight,groupSteps:Math.min(Xe.groupSteps,at)};const cr=new Set;if(Te.forEach((Oe,on)=>{const qe=st[on];let an=Oe.text.normalize("NFC");const lr=ae?.[qe];if(lr){const ur=Ae.restore(an,lr.marks);an=ur.text,ur.ok||(tt.push(qe),cr.add(qe))}W[qe]=an,Oe.forcedEos&&At++}),Nt+=Te.length,xt+=U.tokensGenerated,H&&he?.put){const Oe=[];if(Te.forEach((on,qe)=>{!on.forcedEos&&!cr.has(st[qe])&&Oe.push([O[st[qe]],W[st[qe]]])}),Oe.length)try{he.put(Oe)}catch{}}le?.(D+1,_e.length,W)}const Pt=performance.now()-Zn;At>0&&console.warn(`translateText: ${At}/${O.length} rows hit the token cap (tail may be cut)`);const{profiledMs:sr,profiledDecodeMs:ir,sBuckets:Vo}=Xi(rt,Pt),qo=rt.reduce((D,se)=>D+(se.submitShrinks??0),0);return ne.recordBaselineObservation({complete:!Tt&&Nt===nt.length&&rt.length===_e.length,cancelled:Tt,deviceHealthy:!p,configuredSchedule:ot,effectiveSchedule:ne.telemetry.effectiveSchedule,profiledWallMs:sr,profiledDecodeMs:ir,rowCount:Nt,batchCount:rt.length,tokenCount:xt,submitShrinks:qo}),{text:bs(te,W),rowTexts:W,cancelled:Tt,stats:{sentences:O.length,tokens:xt,ms:Pt,forcedEos:At,t2s:A.changed,glossaryRows:Ie,glossaryFailed:tt,batches:_e.length,stages:Ve,resumeHits:be,tmHits:ye,decodedRows:Nt,batchStats:rt,decodeSchedule:{...ot},requestedDecodeSchedule:{...q},effectiveDecodeSchedule:{...ne.telemetry.effectiveSchedule},scheduleAutotune:ne.telemetry,profiledMs:sr,profiledDecodeMs:ir,sBuckets:Vo,tokPerSec:Pt>0?xt/Pt*1e3:0}}}return{info:{gpuName:oe,gpuTitle:K,dtype:l,lmHeadQ8:l==="f16",lmShortN:J?.length??0,directQ8:k.q8Stats.directTensors>0,immediates:z,uniformPool:G?"b64":"off",inPlaceCompact:we?"explicit":"off",decodeSchedule:{...w},scheduleTuneMode:S,scheduleDefault:{source:h.source,reason:h.reason,revision:h.revision,rolloutBps:h.rolloutBps},kvPolicy:V.policyLabel,kvPlannerOverride:m.get("kvplanner"),kvCapacityOverride:m.get("kvcap"),q8Stats:k.q8Stats,tunedFrom:N,modelId:e.id,modelName:e.name,weightsTag:k.weightsTag??"dev",tokRev:e.tokRev??null,bench:{adapterInfo:{...u.adapterInfo},subgroupMinSize:u.subgroupMinSize,subgroupMaxSize:u.subgroupMaxSize,hasF16:u.hasF16,limits:{...u.limits},kernelRev:Kr,safety:B?{...B.verdicts,forceSg:B.forceSg}:null,tuned:I,tunedFrom:N,timings:_,protocolRev:ra,tuneId:T,measuredAt:j,cacheCheck:$,flags:y,gpuName:oe,gpuWebgl:Me?.renderer??null,webglSameGpu:!!(Me&&eo(ee.vendor,Me.vendor,Me.renderer)),adapterLimits:{...u.adapterLimits},features:[...u.features??[]],wgslFeatures:(()=>{try{return[...navigator.gpu?.wgslLanguageFeatures??[]]}catch{return[]}})()}},translateText:Re,isLost:()=>p,destroy:()=>{try{k.buffer.destroy()}catch{}try{u.device.destroy()}catch{}}}}const oc=["auto","utf-8","gb18030","big5","utf-16le","utf-16be"],ac=new Set("的一是不了人我在有他这为之大来以个中上们到说国和地也子时道出而要于就下得可你年生自会那后能对着事其里所去行过家十用发天如然作方成者多日都三小军二无同么经法当起与好看学进种将还分此心前面又定见只主没公从知世什两次使身被高已亲话常活正感明问力理尔点文几本特做外孩相西果走月实向声车全信重机工物气每并别真打太新比才便夫再书部水像眼等体却加电主界门利海受听表德少克代员许先口由死安写性马光白或住难望教命花结乐色更拉东神记处让母父应直字场平报友关放至张认接���入笑内英军候民岁往何度山觉路带万男边风解叫任金快原吃妈变通师立象数四失满战远格士音轻目条呢病始达深完今提求清王化空业思切怎非找片罗钱吗语元喜曾离飞科言干流欢约各即指合反题必该论交终林请医晚制球决传画保读运及则房早院量苦火布品近坐产答星精视五连司巴這為來個們說國時過還進裡著見兩麼開關門問間東車書興學實現點戰處條讓報馬場話認遠飛樂氣師難聽當義務長員島洋歐陽於億敵獨隊淚類燈爾談請諸講謝證識護賽選遺醫錢鐵閒陳陰險陸雙雞離電靈頭頗題顧風餘體高鬥魚鳥龍發夢舊聲應轉醒覺對藥雲會後".split("")).add(",").add("。").add("、"),gn=(e,...t)=>t.every((n,r)=>e[r]===n);function $r(e){let t=0,n=0,r=0;for(const a of e){const o=a.codePointAt(0);if(o===65533){r++;continue}(o>=19968&&o<=40959||o>=12288&&o<=12351||o>=65280&&o<=65374)&&(t++,ac.has(a)&&n++)}return t+r===0?-1:(n-4*r)/(t+r)}function sc(e){if(e.length>=3&&gn(e,239,187,191))return"utf-8";if(e.length>=2&&gn(e,255,254))return"utf-16le";if(e.length>=2&&gn(e,254,255))return"utf-16be";try{return new TextDecoder("utf-8",{fatal:!0}).decode(e),"utf-8"}catch{}const t=e.subarray(0,65536),n=new TextDecoder("gb18030").decode(t),r=new TextDecoder("big5").decode(t),a=$r(n),o=$r(r);return o>a*1.05&&o>0?"big5":"gb18030"}function vo(e,t="auto"){const n=t==="auto"?sc(e):t;return{text:new TextDecoder(n).decode(e),encoding:n}}const ic=["QX7","KX7","RX7","ZX9","ZQ1","VX1"];function cc(e){let t=2166136261;for(let n=0;n>>0).toString(16).padStart(8,"0")}function lc(e){const t=(e??[]).filter(n=>n?.enabled!==!1&&n?.zh&&n?.vi).map(n=>({zh:Dn(n.zh).text,vi:n.vi})).filter((n,r,a)=>a.findIndex(o=>o.zh===n.zh)===r).sort((n,r)=>r.zh.length-n.zh.length);return t.length?{terms:t}:null}function So(e,t){const n=[];for(const r of t.terms){let a=0;for(;(a=e.indexOf(r.zh,a))!==-1;){const o=a+r.zh.length;n.some(s=>as.start)||n.push({start:a,end:o,term:r}),a=o}}return n.sort((r,a)=>r.start-a.start)}function uc(e,t){if(!t)return null;const n=So(e,t);if(!n.length)return null;const r=ic.filter(i=>!e.includes(i)),a=new Map,o=[];for(const i of n){let u=a.get(i.term.zh);if(!u){if(!r.length)continue;u={marker:r.shift(),vi:i.term.vi,count:0},a.set(i.term.zh,u)}u.count++,o.push({start:i.start,end:i.end,marker:u.marker})}if(!o.length)return null;let s=e;for(let i=o.length-1;i>=0;i--){const u=o[i];s=s.slice(0,u.start)+u.marker+s.slice(u.end)}return{text:s,marks:[...a.values()]}}function dc(e,t){let n=!0,r=e;for(const a of t){const o=r.split(a.marker).length-1;o!==a.count&&(n=!1),o&&(r=r.split(a.marker).join(a.vi))}return{text:r,ok:n}}function hc(e,t){if(!t)return null;const n=So(e,t);if(!n.length)return null;const r=[...new Set(n.map(a=>`${a.term.zh}${a.term.vi}`))].sort();return cc(r.join(""))}const Lr="moxhi.glossary",fc="file không đúng định dạng";function Or(e){return e?.version!==1||!Array.isArray(e.terms)?null:e.terms.filter(t=>t&&typeof t.zh=="string"&&typeof t.vi=="string").map(t=>({zh:t.zh.trim(),vi:t.vi.trim(),enabled:t.enabled!==!1})).filter(t=>t.zh&&t.vi)}function mc({storage:e=zt("local")}={}){let t;try{t=Or(JSON.parse(e.getItem(Lr)??"null"))??[]}catch{t=[]}const n=new Set;function r(){e.setItem(Lr,JSON.stringify({version:1,terms:t}));for(const o of n)o()}function a({zh:o,vi:s}){if(o=String(o??"").trim(),s=String(s??"").trim(),!o||!s)return!1;const i=t.find(u=>u.zh===o);return i?(i.vi=s,i.enabled=!0):t.push({zh:o,vi:s,enabled:!0}),r(),!0}return{list:()=>t.map(o=>({...o})),count:()=>t.filter(o=>o.enabled).length,add:a,update(o,s){const i=t.find(u=>u.zh===o);i&&(typeof s?.vi=="string"&&s.vi.trim()&&(i.vi=s.vi.trim()),typeof s?.enabled=="boolean"&&(i.enabled=s.enabled),r())},remove(o){const s=t.length;t=t.filter(i=>i.zh!==o),t.length!==s&&r()},importJson(o){let s;try{s=Or(JSON.parse(o))}catch{s=null}if(!s)throw new Error(fc);let i=0,u=0;for(const l of s){const p=t.find(f=>f.zh===l.zh);p?(p.vi=l.vi,p.enabled=l.enabled,u++):(t.push(l),i++)}return r(),{added:i,updated:u}},exportJson:()=>JSON.stringify({version:1,terms:t},null,2),subscribe(o){return n.add(o),()=>n.delete(o)}}}function pc({assetBase:e="/model-d8",loadEngine:t=()=>In(()=>import("./index-DOgWbOaH.js"),[])}={}){let n=null,r=null;return{id:"lert-small-d8",label:"LERT small D8",downloadMB:28.8,async load({onProgress:a}={}){n||(r??=(async()=>{const{createD8Ner:o}=await t();try{n=await o({assetBase:e,onProgress:a})}catch(s){if(r=null,/shader-f16/i.test(String(s?.message??s))){const i=new Error("GPU này không có shader-f16 — không chạy được mô hình phân tích.");throw i.code="unsupported",i}throw s}})(),await r)},async run(a,{onProgress:o,signal:s}={}){if(!n)throw new Error("provider chưa load()");const i=await n.analyze(a,{signal:s,onProgress:o}),u=[];return i.forEach((l,p)=>{for(const f of l.entities)u.push({text:f.text,type:f.type,row:p,start:f.startCodepoint,end:f.endCodepoint,confidence:f.confidence})}),{entities:u}},release(){try{n?.releaseWorkspaces()}catch{}try{n?.destroy()}catch{}n=null,r=null}}}function gc(e){const t=new Map;for(const n of e){const r=`${n.text}\0${n.type}`,a=t.get(r);a?(a.count+=1,(n.rowr.count-n.count||n.text.localeCompare(r.text,"zh"))}function bc(e){const t={all:e.length,Nh:0,Ns:0,Ni:0};for(const n of e)n.type in t&&(t[n.type]+=1);return t}let Fr=null;function _r(){return Fr??=In(()=>import("./hanviet_data-DivPLpiI.js"),[]).then(e=>e.default),Fr}function Dr(e,t){return Array.from(e??"").map(n=>{const r=t[n];return r?r.charAt(0).toLocaleUpperCase("vi")+r.slice(1):n}).join(" ").replace(/\s+/g," ").trim()}let Gr=null;function Ur(){return Gr??=In(()=>import("./names_data-nngCF4q7.js"),[]).then(e=>e.default),Gr}function jr(e,t){const n=String(e??"");return t.latin[n]??t.latin[Dn(n).text]??null}function yc(e,t){const n=Array.from(String(e??""));return n.length<3?!1:n.every(r=>t.translit.includes(r))}const gt={Nh:"Người",Ns:"Địa danh",Ni:"Tổ chức"},wo={Nh:re.person,Ns:re.pin,Ni:re.flag},Ot=200;function vc(e){const t=document.createElement("span");return t.className="enttypeicon",t.innerHTML=wo[e]??"",t.title=gt[e]??e,t.setAttribute("role","img"),t.setAttribute("aria-label",gt[e]??e),t}function Sc({provider:e,glossaryStore:t,jobs:n,getRows:r,hasText:a,getFp:o=()=>"",onChange:s=()=>{}}={}){let i=null,u=null,l=[],p=null,f=null,m=Ot,d=null,v="",y=null,g=null,h=null,S=null,M=null;const C=k=>`${k.text}\0${k.type}`,L=()=>!!n.current();function z(k){const B=document.createElement("p");return B.className="hint",B.textContent=k,B}function G(k){if(h){if(!k||k.kind!=="analyze"){h.hidden=!0;return}h.hidden=!1,h.firstChild.textContent=k.phase==="tải mô hình"?`Tải mô hình ${(k.done/1048576).toFixed(1)}/${(k.total/1048576).toFixed(1)} MB…`:`Phân tích ${k.done}/${k.total} câu…`}}function fe(){u&&p!==o()&&(u=null,l=[],p=null,d=null,f=null,v="Văn bản đã đổi — bấm Quét tên để cập nhật.")}async function me(){const k=r();if(!k.length)return v="Chưa có văn bản để quét.",J(),"empty";v="";const B=o(),_=Promise.all([_r(),Ur()]).then(([T,j])=>{y=T,g=j}).catch(()=>{}),I=n.run({kind:"analyze",label:"Quét thực thể",total:k.length,exec:async T=>{await e.load({onProgress:$=>{$.stage==="weights"&&T.progress({phase:"tải mô hình",done:$.loaded??0,total:$.total??0})}}),T.progress({phase:"phân tích",done:0,total:k.length});const j=await e.run(k,{signal:T.signal,onProgress:$=>{$.stage==="analysis"&&T.progress({done:$.completedRows,total:$.totalRows})}});u=gc(j.entities),l=k,f=null,m=Ot,d=null}});J();let N="ok";try{await I==="refused"&&(v="Đang bận việc khác — chờ xong rồi quét.",N="refused")}catch(T){T?.name==="AbortError"?(v="Đã hủy quét.",N="cancelled"):(v=T?.code==="unsupported"?T.message:`Quét lỗi: ${T?.message??T}`,N="error")}return N==="ok"&&(p=B),await _,J(),s(),N}function we(){const k=bc(u),B=document.createElement("div");B.className="entfilter";for(const[_,I,N]of[[null,"Tất cả",k.all],["Nh",gt.Nh,k.Nh],["Ns",gt.Ns,k.Ns],["Ni",gt.Ni,k.Ni]]){const T=document.createElement("button");T.type="button",T.className=f===_?"ghost on":"ghost",_&&(T.innerHTML=wo[_]),T.append(`${I} ${N}`),T.addEventListener("click",()=>{f=_,m=Ot,J()}),B.append(T)}return B}function w(k){const B=Array.from(l[k.firstRow]??""),_=document.createElement("p");_.className="entexample";const I=document.createElement("mark");return I.textContent=B.slice(k.firstStart,k.firstEnd).join(""),_.append(B.slice(0,k.firstStart).join(""),I,B.slice(k.firstEnd).join("")),_}function V(k){const B=document.createElement("form");B.className="entadd";const _=document.createElement("input"),I=g?jr(k.text,g):null;_.value=I??(y?Dr(k.text,y):""),_.setAttribute("aria-label","Dịch thành");const N=document.createElement("button");if(N.type="submit",N.className="ghost",N.textContent="Lưu",B.append(_,N),!I&&g&&yc(k.text,g)){const T=document.createElement("p");T.className="hint",T.textContent="Có vẻ là tên phiên âm phương Tây — thường giữ dạng Latin thay vì Hán-Việt.",B.append(T)}return B.addEventListener("submit",T=>{T.preventDefault(),t.add({zh:k.text,vi:_.value})?(v=`đã thêm ${k.text} → ${_.value.trim()}`,d=null):(v="Cần nhập nghĩa tiếng Việt.",J())}),B}function ge(k,B,_){const I=C(k),N=document.createElement("tr"),T=document.createElement("td");T.className="entzh",T.append(vc(k.type),k.text);const j=document.createElement("td");j.className="enthv",j.textContent=y?Dr(k.text,y):"";const $=document.createElement("td");$.className="entvi";const ee=_.get(k.text),pe=!ee&&g?jr(k.text,g):null;ee!=null?($.textContent=ee,$.title="Theo từ điển tên riêng"):pe?($.textContent=pe,$.classList.add("entguess"),$.title="Gợi ý tên Tây/Nhật — bấm Thêm để sửa và lưu"):($.textContent="—",$.classList.add("entnone"),$.title="Chưa thêm — form Thêm sẽ điền sẵn âm Hán-Việt");const Me=document.createElement("td");Me.className="num entn",Me.textContent=`×${k.count}`;const oe=document.createElement("td");if(oe.className="num entact",B)oe.classList.add("entdone"),oe.textContent="✓",oe.title="Đã có trong từ điển — sửa bên panel Từ điển tên riêng";else{const P=document.createElement("button");P.type="button",P.className="ghost",P.textContent="Thêm",P.addEventListener("click",async Re=>{Re.stopPropagation(),[y,g]=await Promise.all([_r(),Ur()]),d={key:I,add:!0},J(),i?.querySelector(".entadd input")?.focus()}),oe.append(P)}N.append(T,j,$,Me,oe),N.addEventListener("click",()=>{d=d?.key===I?null:{key:I,add:!1},J()});const K=[N];if(d?.key===I){const P=document.createElement("tr");P.className="entdetail";const Re=document.createElement("td");Re.colSpan=5,Re.append(w(k)),d.add&&!B&&Re.append(V(k)),P.append(Re),P.addEventListener("click",x=>x.stopPropagation()),K.push(P)}return K}function Ee(k){const B=document.createElement("table");B.className="tmtable enttable";const _=document.createElement("thead"),I=document.createElement("tr");for(const[j,$,ee]of[["Tên",""],["Hán-Việt",""],["Dịch thành",""],["×","num","Số lần xuất hiện"],["","num"]]){const pe=document.createElement("th");pe.className=$,pe.textContent=j,ee&&(pe.title=ee),I.append(pe)}_.append(I);const N=document.createElement("tbody"),T=new Map(t.list().map(j=>[j.zh,j.vi]));return N.append(...k.slice(0,m).flatMap(j=>ge(j,T.has(j.text),T))),B.append(_,N),B}function J(){if(!i)return;const k=[],B=document.createElement("button");if(B.type="button",B.className="ghost",B.textContent=u===null?"Quét văn bản":"Quét lại",B.disabled=L()||!a(),B.addEventListener("click",me),u===null){k.push(z("Tìm tên người, địa danh, tổ chức trong văn bản rồi thêm vào từ điển. Mô hình ~29 MB, tải một lần."));const I=document.createElement("div");I.className="enttools",I.append(B),k.push(I)}else{const I=document.createElement("div");I.className="enthead",I.append(z(`${u.length} tên riêng trong ${l.length} câu.`),B),k.push(I)}h=document.createElement("p"),h.className="entprog",h.append(document.createTextNode(""));const _=document.createElement("button");if(_.type="button",_.className="ghost",_.textContent="Hủy",_.addEventListener("click",()=>n.cancel()),h.append(_),G(n.current()),k.push(h),!a()&&u===null&&k.push(z("Chưa có văn bản — dán hoặc mở file trước.")),u?.length){k.push(we());const I=f?u.filter(N=>N.type===f):u;if(k.push(Ee(I)),I.length>m){const N=document.createElement("button");N.type="button",N.className="ghost entmore",N.textContent=`Hiện thêm (còn ${I.length-m})`,N.addEventListener("click",()=>{m+=Ot,J()}),k.push(N)}}else u&&k.push(z("Không tìm thấy tên riêng nào."));v&&k.push(z(v)),i.replaceChildren(...k)}return{id:"entity",title:"Nhân vật & địa danh",icon:re.pin,prefers:"full",badge:()=>(fe(),u&&u.length||null),scan:me,mount(k){i=k,S=n.subscribe(G),M=t.subscribe(()=>{J(),s()}),fe(),J()},update(){fe(),J()},destroy(){n.current()?.kind==="analyze"&&n.cancel(),S?.(),S=null,M?.(),M=null,e.release(),i=null,h=null}}}const wc=3;function Eo(e){return(e.flags?.length??0)>0?"flags":e.schedule!==void 0&&e.schedule!==null?"schedule-autotune":((e.tmHits??0)+(e.resumeHits??0))/Math.max(1,e.sentences??0)>.05?"tm-reuse":e.decodedRows!==void 0&&e.decodedRows!==null&&e.decodedRows<30?"few-rows":e.mode==="file"||(e.sentences??0)>=30?null:"small"}const Ec={gpuWebgl:512,gpuName:256,model:128,platformVersion:64,cpuArch:32,browserFull:128};[...Object.keys(Ec)];const kc=e=>[...e].map(t=>t.toString(16).padStart(2,"0")).join("");async function Cc(e){if(!e.persistent)return null;let t=e.getItem(fr);return t||(t=kc(crypto.getRandomValues(new Uint8Array(16))),e.setItem(fr,t)),ha(t)}function ko(e=navigator){return e.userAgentData?.platform||e.platform||""}const Fe=(e,t=1)=>typeof e=="number"&&Number.isFinite(e)?Math.round(e*10**t)/10**t:null;function Mc(e){if(!e||typeof e!="object")return null;const t=Array.isArray(e.plannedSourceBucketHistogram)?e.plannedSourceBucketHistogram:[];return{rowCountBand:e.rowCountBand,batchCountBand:e.batchCountBand,sourceBucketHistogram:Object.fromEntries(t),batchSizeQuantiles:[...e.batchSizeQuantiles??[]],sourceTokenQuantiles:[...e.sourceTokenQuantiles??[]]}}function xc(e){return!e||typeof e!="object"?null:{amortizationRev:e.revision,amortizationStatus:e.status,amortizationAdmitted:e.admit??null,observationCacheState:e.observationCacheState,observationAgeMs:Fe(e.observationAgeMs),observationWrite:e.write??null,observedProfiledWallMs:Fe(e.observedProfiledWallMs),minimumExpectedSavingMs:Fe(e.minimumExpectedSavingMs),projectedWorstCaseScreenMs:Fe(e.projectedWorstCaseScreenMs),paybackRatio:Fe(e.paybackRatio,6)}}function Ac(e){const t=e?.scheduleAutotune;if(!t||!["shadow","apply","auto"].includes(t.mode))return null;const n=t.requestedSchedule??e.requestedDecodeSchedule,r=t.predictedSchedule??t.selectedSchedule,a=e.decodeSchedule??t.configuredSchedule,o=e.effectiveDecodeSchedule??t.effectiveSchedule,s=(e.batchStats??[]).reduce((m,d)=>m+(Number.isInteger(d?.submitShrinks)?d.submitShrinks:0),0),i=t.screenSubmitShrinks??0,u=t.invalidatedReason??(i>0?"submit-shrink":null)??(["promoted","selected"].includes(t.reason)?null:t.reason??null),l=xc(t.amortization),p=Fe(t.screenGain,6),f=Fe(t.confirmationMinGain,6);return{mode:t.mode,protocolRev:t.protocolRev,requested:{...n},predicted:{...r},configured:{...a},effective:{...o},source:t.source,cacheState:t.cache?.status??"not-checked",cacheWrite:t.cache?.write??null,scheduleTuneMs:Fe(t.scheduleTuneMs??e.stages?.scheduleTuneMs??0),selectedGain:Fe(t.selectedGain,6),...p!==null?{screenGain:p}:{},...f!==null?{confirmationMinGain:f}:{},sampleCount:t.sampleCount??0,confirmationCount:t.confirmationCount??0,projectedMs:Fe(t.evidence?.projectedMs??t.projection?.postPilot?.projectedMs??t.projection?.preGate?.projectedMs),overrunMs:Fe(t.deadline?.overrunMs??t.evidence?.overrunMs),screenSubmitShrinks:i,canonicalSubmitShrinks:s,fallbackReason:u,...l??{},workload:Mc(t.workload)}}function Co({info:e,stats:t,mode:n,srcChars:r,build:a,pseudo:o,ua:s,platform:i,extras:u=null}){const l=e.bench,p=Ac(t);return{v:wc,id:crypto.randomUUID(),ts:Date.now(),pseudo:o,run:{build:a,model:e.modelId,dtype:e.dtype,t2s:!!t.t2s,mode:n,srcChars:r,sentences:t.sentences,ms:Math.round(t.ms),tokPerSec:Math.round(t.tokPerSec*10)/10,outputTokens:t.tokens??null,decodedRows:t.decodedRows??null,batches:t.batches??null,tmHits:t.tmHits??null,resumeHits:t.resumeHits??null,forcedEos:t.forcedEos??null,stages:t.stages?Object.fromEntries(Object.entries(t.stages).map(([f,m])=>[f,typeof m=="number"?Math.round(m):m])):null,sBuckets:t.sBuckets??null,flags:[...l.flags??[]],weightsTag:e.weightsTag??null,...p?{schedule:p}:{}},device:{...l.adapterInfo,subgroupMin:l.subgroupMinSize,subgroupMax:l.subgroupMaxSize,fp16:l.hasF16,immediates:e.immediates,uniformPool:e.uniformPool,browserMajor:Hn(s),platform:i,limits:{...l.limits},gpuName:l.gpuName??null,gpuWebgl:l.gpuWebgl??null,webglSameGpu:l.webglSameGpu??null,adapterLimits:l.adapterLimits?{...l.adapterLimits}:null,features:l.features?[...l.features]:null,wgslFeatures:l.wgslFeatures?[...l.wgslFeatures]:null,...u??{}},autotune:{kernelRev:l.kernelRev,cacheState:l.tunedFrom,tuned:l.tuned,probeTimings:l.timings,safety:l.safety,protocolRev:l.protocolRev??null,tuneId:l.tuneId??null,measuredAt:l.measuredAt??null,cacheCheck:l.cacheCheck??null}}}function Nc({base:e,reason:t,phase:n,deviceLostReason:r=null,attachedSegment:a=null,comment:o=null,crumb:s=null}){return{...e,reason:t,phase:n,deviceLostReason:r,attachedSegment:a,comment:o,...s?{crumb:s}:{}}}let bn=null;const Pn="moxhi.deviceLost";async function Mo(e=navigator,t=null){if(!bn){let o={};try{o=await e.userAgentData?.getHighEntropyValues?.(["model","platformVersion","architecture","bitness","fullVersionList"])??{}}catch{o={}}const s=(o.fullVersionList??[]).find(i=>!/Not.A.Brand/i.test(i.brand));bn={model:o.model||null,platformVersion:o.platformVersion||null,cpuArch:o.architecture?`${o.architecture}${o.bitness?`-${o.bitness}`:""}`:null,browserFull:s?`${s.brand} ${s.version}`:null,deviceMemory:e.deviceMemory??null,cpuThreads:e.hardwareConcurrency??null}}let n=null,r=null;try{const o=await e.getBattery?.();n=o?.charging??null,r=o?.level??null}catch{}let a=null;if(t){const o=Math.floor(Number(t.getItem(Pn)??0));a=Number.isFinite(o)&&o>=0?o:0}return{...bn,charging:n,batteryLevel:r,deviceLostCount:a}}async function xo(e,t){const n=await fetch(fa()+e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)});if(!n.ok)throw new Error(`HTTP ${n.status}`);return n.json()}const Tc=20*1024*1024,Pc=600,Rc=900,Ao="moxhi.autotranslate",Kn="moxhi.model",ve=zt("local"),Vn=mc({}),yn={auto:"Tự động","utf-8":"UTF-8",gb18030:"GB18030 / GBK",big5:"Big5","utf-16le":"UTF-16 LE","utf-16be":"UTF-16 BE"},Bc=matchMedia("(prefers-reduced-motion: reduce)").matches,c=Sa(document.querySelector("#app"));qa(c.goBtn);const Ic=new URLSearchParams(location.search).get("profilestats")==="1",b={engine:null,doc:null,stashedTyped:null,srcWindow:0,outWindow:1/0,outRows:[],fileResultText:null,fileProfileText:null,filePartial:null,lastRun:null,pseudo:void 0};let ze=null;async function No(){if(!(ze&&!ze.released))try{ze=await navigator.wakeLock?.request("screen")??null,ze?.addEventListener("release",()=>{ze=null})}catch{ze=null}}function $c(){ze?.release().catch(()=>{}),ze=null}const He=za({onStart:No,onIdle:$c,onError:e=>console.error(e)});let zr=!1;He.subscribe(e=>{const t=!!e;t!==zr&&(zr=t,c.goBtn.classList.toggle("busy",t),c.chipBadge.classList.toggle("busy",t),c.goBtn.disabled=t,c.scanBtn.disabled=t,c.modelSelect.disabled=t)});let vn=!1;He.subscribe(e=>{e?.kind==="analyze"?(vn=!0,R(c.cancelBtn,!0),c.progress.textContent=e.phase==="tải mô hình"?`tải mô hình quét tên ${(e.done/1048576).toFixed(1)}/${(e.total/1048576).toFixed(1)} MB…`:`quét tên ${e.done}/${e.total} câu…`):!e&&vn&&(vn=!1,R(c.cancelBtn,!1),c.progress.textContent="")});document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&He.current()&&!ze&&No()});const R=(e,t=!0)=>{e.hidden=!t},qt=e=>(e/1048576).toFixed(1),Ft=e=>e<950?`${Math.round(e)}ms`:`${(e/1e3).toFixed(1)}s`;function ut(e,t,n=null){c.errMsg.textContent=e,R(c.errBanner),c.retryBtn.onclick=()=>{R(c.errBanner,!1),t()},R(c.reportErrBtn,!!n),c.reportErrBtn.onclick=n?()=>Ro(n):null}function To({title:e,summary:t,payload:n,attach:r=!1,comment:a=!1,send:o}){c.benchModalTitle.textContent=e,c.benchSummary.textContent=t,c.benchPrivacyHint.textContent=r?"Mặc định không gửi nội dung văn bản — chỉ gửi đoạn lỗi nếu bạn tick ô bên dưới.":"Không gửi nội dung văn bản — chỉ các thông số bên dưới.",R(c.benchAttachRow,r),c.benchAttachTgl.checked=!1,R(c.benchComment,a),c.benchComment.value="",c.benchStatus.textContent="",c.benchCancelBtn.textContent="Hủy";const s=()=>{const i=typeof n=="function"?n():n;return c.benchJson.textContent=JSON.stringify(i,null,2),i};s(),c.benchAttachTgl.onchange=s,c.benchSendBtn.disabled=!1,c.benchSendBtn.onclick=async()=>{c.benchSendBtn.disabled=!0,c.benchStatus.textContent="đang gửi…";try{await o(s(),i=>{i instanceof Node?c.benchStatus.replaceChildren(i):c.benchStatus.textContent=i}),c.benchCancelBtn.textContent="Đóng"}catch(i){c.benchStatus.textContent=navigator.onLine===!1?"đang offline — thử lại sau nhé":`gửi lỗi: ${i?.message??i}`,c.benchSendBtn.disabled=!1}},c.benchCancelBtn.onclick=()=>c.benchModal.close(),c.benchModal.showModal()}async function Po(){return b.pseudo===void 0&&(b.pseudo=await Cc(ve)),b.pseudo}function Lc(){const e=Math.floor(Number(ve.getItem(Pn)??0));ve.setItem(Pn,String((Number.isFinite(e)&&e>=0?e:0)+1))}function Oc(e){const t=Eo(e);if(t==="tm-reuse"){const n=(e.tmHits??0)+(e.resumeHits??0);return`Đã ghi nhận — cảm ơn bạn! Run này không xếp hạng: ${Math.round(n/Math.max(1,e.sentences??0)*100)}% câu lấy sẵn từ bộ nhớ dịch (${e.decodedRows??0} hàng dịch mới) nên tốc độ không phản ánh sức GPU.`}return t==="flags"?"Đã ghi nhận! Run chạy với cờ thử nghiệm trên URL nên không xếp hạng — data debug vẫn quý.":t==="schedule-autotune"?"Đã ghi nhận! Run autotune lịch giải mã hiện chỉ dùng để phân tích, chưa xếp hạng cho đến khi board có policy tách cold/warm rõ ràng.":t==="few-rows"||t==="small"?"Đã ghi nhận — cảm ơn bạn! Run nhỏ không xếp hạng (bảng cần ≥30 câu dịch mới), vẫn là data quý.":"Đã ghi nhận — cảm ơn bạn!"}function Fc(e=null){const t="95dca08";if(b.engine){const n=b.lastRun?.stats??{sentences:0,ms:0,tokPerSec:0,t2s:!1};return Co({info:b.engine.info,stats:n,mode:b.lastRun?.mode??"paste",srcChars:b.lastRun?.srcChars??0,build:t,pseudo:b.pseudo??null,ua:navigator.userAgent??"",platform:ko(),extras:e})}return{v:1,id:crypto.randomUUID(),ts:Date.now(),pseudo:b.pseudo??null,run:null,device:null,autotune:null}}async function Ro(e){await Po();const t=Fc(await Mo(navigator,ve));To({title:e.title??"Báo lỗi",summary:e.summary??"",attach:!!e.attach,comment:!0,payload:()=>Nc({base:t,reason:e.reason,phase:e.phase,deviceLostReason:e.deviceLostReason??null,attachedSegment:e.attach&&c.benchAttachTgl.checked?{src:c.src.value.slice(0,1e3),dst:_n(b.outRows).slice(0,1e3)}:null,comment:c.benchComment.value.trim()||null,crumb:e.crumb??null}),send:async(n,r)=>{await xo("/api/report",n),r("Đã ghi nhận — cảm ơn bạn!")}})}const qn="moxhi.lastfile";function _c(e){ve.setItem(qn,JSON.stringify(e))}function Bo(){try{return JSON.parse(ve.getItem(qn)??"null")}catch{return null}}function Dc(){ve.removeItem(qn)}const Jn="moxhi.crumb";function Hr(e){ve.setItem(Jn,JSON.stringify({...e,ts:Date.now(),build:"95dca08"}))}function Qn(){ve.removeItem(Jn)}async function Gc(){let e=null;try{e=JSON.parse(ve.getItem(Jn)??"null")}catch{}if(!e)return;Qn(),console.warn("[moxhi] phiên dịch trước dừng đột ngột (nghi hệ điều hành ngắt vì thiếu bộ nhớ):",e);const t=Bo(),n=!!t&&!t.complete&&(t.done??0)>0&&t.file===e.file;ut(`Phiên dịch file trước dừng đột ngột ở cụm ${e.done??0}/${e.rows??"?"} (batch ${e.batch??0}/${e.batches??"?"}) — thường do thiết bị cạn bộ nhớ.`+(n?' Phần đã dịch vẫn còn: mở lại đúng file đó rồi bấm "Dịch file" để dịch tiếp.':" Hãy dịch lại từ đầu."),()=>{},{reason:"oom",phase:"translate",title:"Báo lỗi văng phiên dịch",crumb:{batch:e.batch,batches:e.batches,done:e.done,rows:e.rows,build:e.build,model:e.model}})}addEventListener("pagehide",Qn);const Uc={gpu:"Gọi linh khí GPU…",weights:"Tải trọng số…",tokenizer:"Nạp từ điển…",autotune:"Đo mạch thiết bị (chỉ lần đầu)…"};async function dt(){R(c.gate,!1),R(c.studio,!1),R(c.loading,!0);const e=$n(ve.getItem(Kn)??Ln);c.modelSelect.value=e.id,c.modelSelect.disabled=!0,c.loadNote.innerHTML=`Lần đầu tải ~${e.downloadMB} MB trọng số (${e.name}) — các lần sau mở nhanh nhờ bộ nhớ đệm của trình duyệt.`;try{b.engine=await rc({model:e,scheduleDefaultEnabled:!0,onPhase:y=>{y!=="ready"&&(c.phaseLabel.textContent=Uc[y]??y,y==="tokenizer"&&(c.brushFill.style.width="100%",c.brushBar.setAttribute("aria-valuenow","100")))},onProgress:(y,g)=>{const h=g?Math.round(y/g*100):0;c.brushFill.style.width=`${h}%`,c.brushBar.setAttribute("aria-valuenow",String(h)),c.phaseLabel.textContent=`Tải trọng số — ${qt(y)} / ${qt(g)} MB (${h}%)`},onDeviceLost:y=>{Lc(),!He.current()&&ut(`GPU bị ngắt kết nối (${y.reason}): ${y.message||"không rõ nguyên nhân"}. Bấm thử lại để khởi động lại bộ dịch.`,dt,{reason:"device-lost",phase:"idle",deviceLostReason:`${y.reason}: ${y.message??""}`})}})}catch(y){console.error(y),c.modelSelect.disabled=!1,R(c.chipBadge,!1),R(c.gpuTip,!1),window.__moxhi=null;const g=String(y?.message??y);/WebGPU unavailable|no adapter/i.test(g)?(R(c.loading,!1),Zc(g),R(c.gate,!0)):ut(`Không khởi động được bộ dịch: ${g}`,dt,{reason:"other",phase:"load"});return}c.modelSelect.disabled=!1;const{gpuName:t,dtype:n,lmHeadQ8:r,lmShortN:a,tunedFrom:o,modelName:s}=b.engine.info,i=o==="cache"?"autotune đệm":o==="measured"?"autotune":o==="partial"?"autotune một phần":"routing mặc định",u="95dca08",l=new URLSearchParams(location.search).get("cap"),p=new URLSearchParams(location.search).get("tokenbudget"),f=new URLSearchParams(location.search).get("kvplanner"),m=new URLSearchParams(location.search).get("inplacecompact"),d=r?`·int8${a?` ${Math.round(a/1e3)}k`:""}`:"",v=ks(t);c.modelLink.textContent=s,e.credit?.url?(c.modelLink.href=e.credit.url,c.modelLink.title=e.credit.label):(c.modelLink.removeAttribute("href"),c.modelLink.removeAttribute("title")),c.statGpu.textContent=` · ${v} · ${n}${d} · ${i} · ${u}`+(l?` · cap=${l}`:"")+(p!==null?` · tokenbudget=${p}`:"")+(f!==null?` · kvplanner=${f}`:"")+(m!==null?` · inplacecompact=${m}`:""),R(c.chipBadge),c.chipBadge.title=[v!==t?t:null,b.engine.info.gpuTitle||null].filter(Boolean).join(" · "),R(c.gpuTip,Cs(t)),R(c.loading,!1),R(c.studio,!0),c.src.focus(),window.__moxhi={engine:b.engine,build:u,translate:y=>b.engine.translateText(y)},document.dispatchEvent(new CustomEvent("moxhi:ready"))}function jc(e){c.dstNote.textContent=e?`${e} ký tự`:""}function Je(e,t={}){b.outRows=e,t.count!==void 0&&(b.outWindow=t.count);const{chars:n,shown:r,total:a}=Ya(c.out,e,{},{...t,count:b.outWindow});jc(n),R(c.outMoreBtn,rHe.cancel());c.src.addEventListener("keydown",e=>{(e.ctrlKey||e.metaKey)&&e.key==="Enter"&&(e.preventDefault(),wt())});c.reportOutBtn.addEventListener("click",()=>Ro({title:"Báo lỗi dịch",reason:"wrong-output",phase:"translate",attach:!0,summary:"Bản dịch sai/lệch nghĩa? Tick ô bên dưới để đính kèm đoạn đang hiển thị."}));c.benchSubmitBtn.addEventListener("click",async()=>{if(!b.engine||!b.lastRun||b.lastRun.submitted)return;const e=await Po();if(!e)return;const t=await Mo(navigator,ve);b.lastRun.payload??=Co({info:b.engine.info,stats:b.lastRun.stats,mode:b.lastRun.mode,srcChars:b.lastRun.srcChars,build:"95dca08",pseudo:e,ua:navigator.userAgent??"",platform:ko(),extras:t});const n=b.lastRun.payload;To({title:"Gửi benchmark",summary:`${pa(e).emoji} ${ga(e)} · ${b.engine.info.gpuName} · ${b.engine.info.modelName} · ${Math.round(n.run.tokPerSec)} tok/s · ${n.run.sentences} câu`+(Eo(n.run)?" · sẽ không xếp hạng":""),payload:n,send:async(r,a)=>{const o=await xo("/api/submit",r);if(b.lastRun.submitted=!0,R(c.benchSubmitBtn,!1),o.rank){const s=document.createDocumentFragment(),i=document.createElement("a");i.href="/board",i.textContent="xem bảng tốc độ",s.append(`Hạng ${o.rank} bảng ${b.engine.info.modelName} — `,i),a(s)}else a(Oc(r.run))}})});let Rn=(ve.getItem(Ao)??"1")==="1";const Hc={autoTranslate:()=>Rn,setAutoTranslate:e=>{Rn=e,ve.setItem(Ao,e?"1":"0")}},$o=matchMedia("(min-width: 1440px)"),Wc=()=>$o.matches,Kc=()=>({doc:b.doc,job:He.current()}),Vc=ts(),Ue=Ca({tabs:c.panelTabs,overlay:{modal:c.panelModal,title:c.panelTitle,body:c.panelBody,closeBtn:c.panelCloseBtn,grip:c.panelGrip},rail:{isOpen:Wc,title:c.railTitle,body:c.railBody,onChange:e=>c.page.classList.toggle("rail-open",e)},getState:Kc}),Lo=Da({getNamespace:()=>b.engine?Vr(b.engine.info):null,enabled:new URLSearchParams(location.search).get("tm")!=="0",onChange:()=>Ue.refresh(),prefs:Hc});On(Lo);On(Ga({store:Vn,onChange:()=>Ue.refresh()}));const Oo=Sc({provider:pc(),glossaryStore:Vn,jobs:He,getRows:()=>{const e=b.doc??_t(c.src.value);return e.text.trim()?Yr(e.text).sentences:[]},hasText:()=>!!(b.doc??_t(c.src.value)).text.trim(),getFp:()=>Vc((b.doc??_t(c.src.value)).text),onChange:()=>Ue.refresh()});On(Oo);c.scanBtn.addEventListener("click",async()=>{const e=await Oo.scan();(e==="ok"||e==="empty"||e==="error")&&Ue.open("entity")});c.settingsBtn.addEventListener("click",()=>Ue.open("memory"));c.helpBtn.addEventListener("click",()=>c.helpModal.showModal());c.helpCloseBtn.addEventListener("click",()=>c.helpModal.close());c.helpModal.addEventListener("click",e=>{e.target===c.helpModal&&c.helpModal.close()});c.railCloseBtn.addEventListener("click",()=>Ue.close());$o.addEventListener("change",()=>Ue.rehost());Ue.refresh();c.modelSelect.replaceChildren(...ma.map(e=>{const t=document.createElement("option");return t.value=e.id,t.textContent=e.name,t}));c.modelSelect.value=$n(ve.getItem(Kn)??Ln).id;c.modelSelect.addEventListener("change",()=>{ve.setItem(Kn,c.modelSelect.value),b.filePartial=null,c.progress.textContent="",b.engine?.destroy?.(),b.engine=null,b.lastRun=null,R(c.benchSubmitBtn,!1),R(c.reportOutBtn,!1),dt()});let Wr=0;c.src.addEventListener("input",()=>{if(c.srcCount.textContent=`${c.src.value.length} ký tự`,b.filePartial=null,Ue.refresh(),clearTimeout(Wr),!(!Rn||!b.engine||b.doc)){if(c.src.value.length>Pc){c.progress.textContent="văn bản dài — bấm Dịch";return}c.progress.textContent="",Wr=setTimeout(wt,Rc)}});c.pasteBtn.addEventListener("click",async()=>{try{c.src.value=await navigator.clipboard.readText(),c.src.dispatchEvent(new Event("input"))}catch{c.src.focus(),c.progress.textContent="trình duyệt chặn đọc clipboard — dán bằng Ctrl+V"}});c.clearBtn.addEventListener("click",()=>{c.src.value="",Je([]),R(c.reportOutBtn,!1),c.src.dispatchEvent(new Event("input")),c.src.focus()});c.copyBtn.addEventListener("click",async()=>{const e=_n(b.outRows);e&&await navigator.clipboard.writeText(e).catch(()=>{})});function Fo(e,t){const n=document.createElement("a");n.href=URL.createObjectURL(new Blob([t],{type:"text/plain;charset=utf-8"})),n.download=e,n.click(),URL.revokeObjectURL(n.href)}c.saveBtn.addEventListener("click",()=>{const e=_n(b.outRows);e&&Fo(os(b.doc),e)});function qc(e){c.encSelect.replaceChildren(...oc.map(t=>{const n=document.createElement("option");return n.value=t,n.textContent=t==="auto"?`${yn.auto} (${yn[e]??e})`:yn[t],n})),c.encSelect.value="auto"}const Jc=2e3,Qc=400;function _o(){const{text:e}=b.doc,t=Math.min(b.srcWindow,e.length);c.srcView.textContent=e.slice(0,t)+(tTc){ut(`File ${qt(e.size)} MB vượt giới hạn 20 MB.`,()=>{});return}const t=new Uint8Array(await e.arrayBuffer()),{text:n,encoding:r}=vo(t,"auto");b.fileResultText=null,b.fileProfileText=null,b.filePartial=null,qc(r),Xn(Xr({name:e.name,bytes:t,text:n,encoding:r})),Je([]),R(c.profileBtn,!1),R(c.reportOutBtn,!1),c.progress.textContent="";const a=Bo(),o=Do();Na(a,o)?c.progress.textContent=`phiên trước dừng ở ${a.done}/${a.rows} cụm — "Dịch file" sẽ dịch tiếp từ bộ nhớ dịch`:a&&!a.complete&&(a.done??0)>0&&a.file===o.file&&a.model===o.model&&(c.progress.textContent="file đã thay đổi so phiên dịch dở trước — phần trùng sẽ lấy lại từ bộ nhớ dịch")}c.openBtn.addEventListener("click",()=>c.fileInput.click());c.fileInput.addEventListener("change",()=>Go(c.fileInput.files[0]));c.srcMoreBtn.addEventListener("click",()=>{b.srcWindow*=4,_o()});let mt=0;const Uo=e=>{mt=e?mt+1:Math.max(0,mt-1),R(c.dropveil,mt>0)};c.panes.addEventListener("dragenter",e=>{e.preventDefault(),Uo(!0)});c.panes.addEventListener("dragover",e=>{e.preventDefault()});c.panes.addEventListener("dragleave",e=>{e.preventDefault(),Uo(!1)});c.panes.addEventListener("drop",e=>{e.preventDefault(),mt=0,R(c.dropveil,!1),Go(e.dataTransfer.files[0])});c.encSelect.addEventListener("change",()=>{const e=c.encSelect.value,{text:t,encoding:n}=vo(b.doc.bytes,e);b.doc.text=t,b.doc.encoding=n,b.filePartial=null,b.fileProfileText=null,R(c.profileBtn,!1),c.progress.textContent="",Xn(Xr({...b.doc,text:t,encoding:n}))});c.docCloseBtn.addEventListener("click",()=>{b.fileResultText=null,b.fileProfileText=null,b.filePartial=null,c.fileInput.value="",R(c.profileBtn,!1),Xn(null)});async function Xc(e){const t=b.doc??_t(c.src.value),n=t.origin==="file",r=rs(t);if(!n&&!t.text.trim()){Io();return}R(c.benchSubmitBtn,!1),R(c.cancelBtn,!0),R(c.profileBtn,!1),b.fileProfileText=null,r||(c.progress.textContent="đang dịch…"),n&&Hr({file:t.name,batch:0,model:b.engine?.info.modelId??""});const a=n?Do():null,o=Vr(b.engine.info),s=lc(Vn.list()),i=s?{protect:d=>uc(d,s),restore:(d,v)=>dc(d,v)}:null,u=s?d=>{const v=hc(d,s);return v?d+"\0"+v:d}:d=>d,l=r&&new URLSearchParams(location.search).get("tm")!=="0",p=d=>l?{get:async v=>{c.progress.textContent="tra bộ nhớ dịch…";const y=await Pa(o,v.map(d)),g=y.filter(Boolean).length;return c.progress.textContent=g?`khôi phục ${g}/${v.length} cụm từ bộ nhớ dịch`:"",y},put:v=>Ra(o,v.map(([y,g])=>[d(y),g]))}:null,f=performance.now(),m=({glossary:d,resume:v,tm:y})=>b.engine.translateText(t.text,{pack:r,glossary:d,scheduleTuneMode:r?b.engine.info.scheduleTuneMode:void 0,onScheduleTune:r?({active:g})=>{g?c.progress.textContent="đang tối ưu GPU…":c.progress.textContent==="đang tối ưu GPU…"&&(c.progress.textContent="")}:null,resume:v,tm:y,shouldStop:()=>e.signal.aborted,onBatch:r?(g,h,S)=>{b.filePartial=S;const M=S.filter(Boolean).length;n&&(Hr({file:t.name,batch:g,batches:h,done:M,rows:S.length,model:b.engine?.info.modelId??""}),_c({...a,done:M,rows:S.length}));const C=Math.round(g/h*100),L=(performance.now()-f)/1e3,z=g>0?Math.max(0,L/g*(h-g)):0;c.progress.textContent=`${M}/${S.length} cụm câu · ${C}% · còn ~${Math.ceil(z)}s`}:(g,h,S)=>{const M=S.filter(Boolean).length;c.progress.textContent=`câu ${M}/${S.length}`,h>1&&Je(sn(S.filter(Boolean).join(" ")))}});try{let d=await m({glossary:i,resume:r?b.filePartial:null,tm:p(u)});if(i&&d.stats.glossaryFailed?.length&&!d.cancelled){const y=d.stats,g=[...d.rowTexts];for(const S of y.glossaryFailed)g[S]="";const h=await m({glossary:null,resume:g,tm:p(S=>S)});d={...h,stats:{...y,glossaryFailed:y.glossaryFailed}},h.cancelled&&(d.cancelled=!0)}const v=(d.stats.glossaryFailed??[]).length;if(!r){d.cancelled?c.progress.textContent="đã hủy":(Je(sn(d.text),{ink:!0,reduced:Bc}),c.progress.textContent="",c.statPerf.textContent=`${Math.round(d.stats.tokPerSec)} tok/s · ${Ft(d.stats.ms)} · ${d.stats.sentences} câu`+(d.stats.t2s?" · phồn→giản":"")+(v?` · ⚠ ${v} câu lỗi term`:""),b.lastRun={stats:d.stats,mode:"paste",srcChars:t.text.length,submitted:!1},ve.persistent&&R(c.benchSubmitBtn,!0),R(c.reportOutBtn,!0));return}if(d.cancelled||(b.filePartial=null,n&&Dc(),Ba()),b.fileResultText=d.text+(d.cancelled?` + +[— bản dịch dở dang —]`:""),c.progress.textContent=d.cancelled?"đã hủy — phần dịch dở vẫn tải được":`xong — ${Ft(d.stats.ms)} · ${Math.round(d.stats.tokPerSec)} tok/s`+(d.stats.tmHits?` · ${d.stats.tmHits} cụm từ bộ nhớ dịch`:"")+(d.stats.forcedEos?` · ⚠ ${d.stats.forcedEos} cụm chạm trần token`:"")+(v?` · ⚠ ${v} cụm lỗi term`:""),Je(sn(b.fileResultText),{count:Qc}),Ic){const y=new URLSearchParams(location.search);let g=null;try{g=await Qi(b.fileResultText)}catch(M){console.warn("[moxhi profile] output SHA-256 unavailable:",M)}const h=d.stats.scheduleAutotune??{},S={build:"95dca08",capturedAt:new Date().toISOString(),file:{name:t.name,bytes:t.bytes?.length??null,encoding:t.encoding},engine:{modelId:b.engine.info.modelId,modelName:b.engine.info.modelName,gpuName:b.engine.info.gpuName,dtype:b.engine.info.dtype,immediates:b.engine.info.immediates,uniformPool:b.engine.info.uniformPool,inPlaceCompact:b.engine.info.inPlaceCompact,scheduleTuneMode:b.engine.info.scheduleTuneMode,scheduleDefault:{...b.engine.info.scheduleDefault},kvPolicy:b.engine.info.kvPolicy,kvPlannerOverride:b.engine.info.kvPlannerOverride,kvCapacityOverride:b.engine.info.kvCapacityOverride},policy:{cap:y.get("cap"),tokenbudget:y.get("tokenbudget"),kvplanner:y.get("kvplanner"),kvcap:y.get("kvcap"),inplacecompact:y.get("inplacecompact"),scheduletune:y.get("scheduletune"),tm:y.get("tm")},totals:{cancelled:d.cancelled,sentences:d.stats.sentences,tokens:d.stats.tokens,ms:Math.round(d.stats.ms*10)/10,tokPerSec:Math.round(d.stats.tokPerSec*10)/10,forcedEos:d.stats.forcedEos,batches:d.stats.batches,resumeHits:d.stats.resumeHits,tmHits:d.stats.tmHits,decodedRows:d.stats.decodedRows,profiledMs:d.stats.profiledMs,profiledDecodeMs:d.stats.profiledDecodeMs,stages:d.stats.stages,outputSha256:g},schedule:{featureMode:h.mode??"off",requested:d.stats.requestedDecodeSchedule??null,predicted:h.predictedSchedule??null,configured:d.stats.decodeSchedule??null,effective:d.stats.effectiveDecodeSchedule??null,canonicalUsesTunerVerdict:h.canonicalUsesTunerVerdict??!1,source:h.source??"default",protocolRev:h.protocolRev??null,reason:h.reason??null,fallbackReason:h.invalidatedReason??(h.source==="default"?h.reason??null:null),invalidatedReason:h.invalidatedReason??null,cache:h.cache??null,workload:h.workload??null,evidence:h.evidence??null,candidateEvidence:h.candidateEvidence??[],projection:h.projection??null,deadline:h.deadline??null,screenSubmitShrinks:h.screenSubmitShrinks??0,selectedGain:h.selectedGain??null,sampleCount:h.sampleCount??0,confirmationCount:h.confirmationCount??0,scheduleTuneMs:h.scheduleTuneMs??0},sBuckets:d.stats.sBuckets,batchStats:d.stats.batchStats};b.fileProfileText=JSON.stringify(S,null,2),globalThis.__moxhiLastProfile=S,console.log("[moxhi profile]",S),R(c.profileBtn,!0)}if(c.statPerf.textContent=`${Math.round(d.stats.tokPerSec)} tok/s · ${Ft(d.stats.ms)} · ${d.stats.sentences} cụm câu`+(d.stats.t2s?" · phồn→giản":""),d.cancelled||(b.lastRun={stats:d.stats,mode:n?"file":"paste",srcChars:t.text.length,submitted:!1},ve.persistent&&R(c.benchSubmitBtn,!0),n||R(c.reportOutBtn,!0)),d.stats.stages){const y=d.stats.stages,g=h=>`${(h/1e3).toFixed(1)}s ${Math.round(h/d.stats.ms*100)}%`;console.log(`[moxhi] ${d.stats.batches} batch · ${Ft(d.stats.ms)} — tokenize ${g(y.tokenizeMs)} · encoder ${g(y.encoderMs)} · decode ${g(y.decodeMs)} · detok ${g(y.detokMs)} · gap ${g(y.gapMs)} · encoder/decode là cửa sổ chồng lấn (không cộng)`+(y.tmMs?` · tm ${(y.tmMs/1e3).toFixed(1)}s (ngoài wall)`:""))}}catch(d){console.error(d);const v=b.filePartial?b.filePartial.filter(Boolean).length:0;if(b.engine?.isLost?.()){const{reason:y,message:g}=b.engine.isLost();c.progress.textContent=v?`đã dịch ${v} cụm — sẽ tiếp tục từ đó`:"",ut(`GPU bị ngắt kết nối (${y}): ${g||"không rõ nguyên nhân"}. Thử lại sẽ khởi động lại bộ dịch${v?" và dịch tiếp từ chỗ dừng":""}.`,async()=>{await dt(),wt()},{reason:"device-lost",phase:"translate",deviceLostReason:`${y}: ${g??""}`})}else c.progress.textContent="",ut(`${n?"Dịch file lỗi":"Dịch lỗi"}: ${d?.message??d}`,wt,{reason:"other",phase:"translate"})}finally{n&&Qn(),R(c.cancelBtn,!1),r&&Lo.update()}}c.outMoreBtn.addEventListener("click",()=>{Je(b.outRows,{count:b.outWindow*4})});c.profileBtn.addEventListener("click",async()=>{if(b.fileProfileText)try{await navigator.clipboard.writeText(b.fileProfileText),c.profileBtn.title="Đã chép profile"}catch{const e=b.doc?.name?.replace(/\.txt$/i,"")||"moxhi";Fo(`${e}.profile.json`,b.fileProfileText)}});function jo(e){const t=document.createElement("div");t.className="gate-address";const n=document.createElement("code");n.textContent=e;const r=document.createElement("button");return r.type="button",r.className="ghost gate-copy",r.dataset.copyAddress=e,r.textContent="Sao chép",r.setAttribute("aria-label",`Sao chép địa chỉ ${e}`),t.append(n,r),t}function Yc(e){const t=document.createElement("li"),n=document.createElement("span");return n.className="gate-step-text",n.textContent=e.text,t.append(n),e.address&&t.append(jo(e.address)),t}function Zc(e){const t=navigator.userAgentData,n=hs({userAgent:navigator.userAgent,platform:t?.platform??navigator.platform,mobile:t?.mobile,maxTouchPoints:navigator.maxTouchPoints,message:e});if(c.gateSummary.textContent=n.summary,c.gateSteps.replaceChildren(...n.steps.map(Yc)),c.gateCopyStatus.textContent="",c.gateAdvanced.open=!1,c.gateAdvancedBody.replaceChildren(),R(c.gateAdvanced,!!n.advanced),n.advanced){const r=document.createElement("p");r.textContent=n.advanced.text,c.gateAdvancedBody.append(r),n.advanced.address&&c.gateAdvancedBody.append(jo(n.advanced.address))}c.gateErr.textContent=`Chi tiết kỹ thuật: ${e}`}c.gate.addEventListener("click",async e=>{const t=e.target.closest?.("[data-copy-address]");if(!t||!c.gate.contains(t))return;const n=t.dataset.copyAddress;try{if(!navigator.clipboard?.writeText)throw new Error("clipboard unavailable");await navigator.clipboard.writeText(n),c.gateCopyStatus.textContent=`Đã sao chép ${n}`}catch{c.gateCopyStatus.textContent="Trình duyệt chặn sao chép tự động — hãy chọn địa chỉ rồi sao chép thủ công."}});c.gateRetryBtn.addEventListener("click",dt);Gc();dt();"serviceWorker"in navigator&&window.addEventListener("load",()=>{navigator.serviceWorker.register("/sw.js").catch(()=>{})});