cap-widget 0.1.53 → 0.1.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cap.d.ts +20 -0
- package/cap.min.js +1 -1
- package/package.json +1 -1
- package/src/cap.js +217 -110
- package/src/i18n/translations.js +87 -0
- package/src/worker.js +10 -8
package/cap.d.ts
CHANGED
|
@@ -2,9 +2,12 @@ declare global {
|
|
|
2
2
|
interface Window {
|
|
3
3
|
CAP_CUSTOM_FETCH?: typeof fetch;
|
|
4
4
|
CAP_CUSTOM_WASM_URL?: string;
|
|
5
|
+
CAP_PAKO_URL?: string;
|
|
5
6
|
CAP_CSS_NONCE?: string;
|
|
6
7
|
CAP_SCRIPT_NONCE?: string;
|
|
7
8
|
CAP_DONT_SKIP_REDEFINE?: boolean;
|
|
9
|
+
CAP_DEBUG?: boolean;
|
|
10
|
+
CAP_SILENT?: boolean;
|
|
8
11
|
Cap: typeof Cap;
|
|
9
12
|
}
|
|
10
13
|
}
|
|
@@ -17,8 +20,24 @@ interface CapSolveEventDetail {
|
|
|
17
20
|
token: string;
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
type CapErrorCode =
|
|
24
|
+
| "missing_endpoint"
|
|
25
|
+
| "network_error"
|
|
26
|
+
| "challenge_parse_error"
|
|
27
|
+
| "challenge_unsupported"
|
|
28
|
+
| "solve_failed"
|
|
29
|
+
| "instr_timeout"
|
|
30
|
+
| "instr_blocked"
|
|
31
|
+
| "redeem_failed"
|
|
32
|
+
| "invalid_solution"
|
|
33
|
+
| "invalid_expires"
|
|
34
|
+
| "wasm_load_failed"
|
|
35
|
+
| "worker_spawn_failed"
|
|
36
|
+
| "unknown";
|
|
37
|
+
|
|
20
38
|
interface CapErrorEventDetail {
|
|
21
39
|
isCap: boolean;
|
|
40
|
+
code: CapErrorCode;
|
|
22
41
|
message: string;
|
|
23
42
|
}
|
|
24
43
|
|
|
@@ -116,6 +135,7 @@ export {
|
|
|
116
135
|
type CapProgressEvent,
|
|
117
136
|
type CapSolveEvent,
|
|
118
137
|
type CapErrorEvent,
|
|
138
|
+
type CapErrorCode,
|
|
119
139
|
type CapResetEvent,
|
|
120
140
|
type SolveResult,
|
|
121
141
|
};
|
package/cap.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{const e="vibrate"in navigator&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches;if("undefined"==typeof window)return;const t=(e,t={})=>window?.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(e,t):fetch(e,t);function i(e,t){let i=function(e){let t=2166136261;for(let i=0;i<e.length;i++)t^=e.charCodeAt(i),t+=(t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24);return t>>>0}(e),s="";function r(){return i^=i<<13,i^=i>>>17,i^=i<<5,i>>>0}for(;s.length<t;){s+=r().toString(16).padStart(8,"0")}return s.substring(0,t)}let s=null;async function r(e){const t=(e=>{const t=atob(e),i=new Uint8Array(t.length);for(let e=0;e<t.length;e++)i[e]=t.charCodeAt(e);return i})(e),i=(new TextDecoder).decode(await async function(e){if("undefined"!=typeof DecompressionStream)try{const t=new DecompressionStream("deflate-raw"),i=t.writable.getWriter(),s=t.readable.getReader();i.write(e).then(()=>i.close()).catch(()=>{});const r=[];for(;;){const{done:e,value:t}=await s.read();if(e)break;r.push(t)}let n=0;for(const e of r)n+=e.length;const a=new Uint8Array(n);let o=0;for(const e of r)a.set(e,o),o+=e.length;return a}catch{}return s||(s=new Promise((e,t)=>{const i=window.CAP_PAKO_URL||"https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako_inflate.min.js",r=document.createElement("script");r.src=i;const n=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE;n&&r.setAttribute("nonce",n),r.onload=()=>{window.pako?.inflateRaw?e(window.pako):t(new Error("[cap] pako loaded but inflateRaw is missing"))},r.onerror=()=>{s=null,t(new Error(`[cap] failed to load pako fallback from ${i}`))},document.head.appendChild(r)})),(await s).inflateRaw(e)}(t));return new Promise(e=>{var t=setTimeout(()=>{n(),e({__timeout:!0})},2e4),s=document.createElement("iframe");s.setAttribute("sandbox","allow-scripts"),s.setAttribute("aria-hidden","true"),s.style.cssText="position:absolute;width:1px;height:1px;top:-9999px;left:-9999px;border:none;opacity:0;pointer-events:none;";var r=!1;function n(){r||(r=!0,clearTimeout(t),window.removeEventListener("message",a),s.parentNode&&s.parentNode.removeChild(s))}function a(t){if(s.contentWindow&&t.source===s.contentWindow){var i=t.data;i&&"object"==typeof i&&("cap:instr"===i.type?(n(),i.blocked?e({__blocked:!0,blockReason:i.blockReason||"automated_browser"}):i.result?e(i.result):e({__timeout:!0})):"cap:error"===i.type&&(n(),e({__timeout:!0})))}}window.addEventListener("message",a);const o=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE,l=o?` nonce="${String(o).replace(/"/g,""")}"`:"";s.srcdoc='<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><script'+l+">"+i+"\n<\/script></body></html>",document.body.appendChild(s)})}let n=null;const a=()=>{if(n)return n;const e=window.CAP_CUSTOM_WASM_URL||"https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.7/browser/cap_wasm_bg.wasm";return n=fetch(e).then(e=>{if(!e.ok)throw new Error(`Failed to fetch wasm: ${e.status}`);return e.arrayBuffer()}).then(e=>WebAssembly.compile(e)).catch(e=>{throw n=null,e}),n};"object"==typeof WebAssembly&&"function"==typeof WebAssembly.compile&&a().catch(()=>{});let o=null;function l(){return o||(o=URL.createObjectURL(new Blob(['(()=>{const e=async({salt:e,target:t})=>{let n=0;const o=new TextEncoder,r=4*t.length,s=Math.floor(r/8),a=r%8,l=t.length%2==0?t:`${t}0`,i=l.length/2,c=new Uint8Array(i);for(let e=0;e<i;e++)c[e]=parseInt(l.substring(2*e,2*e+2),16);const f=a>0?255<<8-a&255:0;for(;;)try{for(let t=0;t<5e4;t++){const t=e+n,r=o.encode(t),l=await crypto.subtle.digest("SHA-256",r),i=new Uint8Array(l);let g=!0;for(let e=0;e<s;e++)if(i[e]!==c[e]){g=!1;break}if(g&&a>0&&(i[s]&f)!==(c[s]&f)&&(g=!1),g)return void self.postMessage({nonce:n,found:!0});n++}}catch(e){return console.error("[cap worker]",e),void self.postMessage({found:!1,error:e.message})}},t=e=>{const t=BigInt("0x"+e.N);let n=BigInt("0x"+e.x);const o=0|e.t,r=Math.max(64,Math.floor(o/50)),s=performance.now();for(let e=0;e<o;e+=r){const s=Math.min(o,e+r);for(let o=e;o<s;o++)n=n*n%t;s<o&&self.postMessage({progress:s/o})}self.postMessage({found:!0,y:n.toString(16),durationMs:(performance.now()-s).toFixed(2)})};if("object"!=typeof WebAssembly||"function"!=typeof WebAssembly?.instantiate)return console.warn("[cap worker] wasm not supported, falling back to alternative solver. this will be significantly slower."),void(self.onmessage=async({data:n})=>"rsw"===n?.kind?t(n):e({salt:n.salt,target:n.target}));let n=null;self.onmessage=async({data:o})=>{if("rsw"===o?.kind)return t(o);const{salt:r,target:s,wasmModule:a}=o;if(a instanceof WebAssembly.Module&&null===n){const t=(e=>{try{let t,o=0,r=null;const s=()=>(null!==r&&0!==r.byteLength||(r=new Uint8Array(t.memory.buffer)),r),a=new TextEncoder,l=(e,t,n)=>{if(void 0===n){const n=a.encode(e),r=t(n.length,1)>>>0;return s().subarray(r,r+n.length).set(n),o=n.length,r}let r=e.length,l=t(r,1)>>>0;const i=s();let c=0;for(;c<r;c++){const t=e.charCodeAt(c);if(t>127)break;i[l+c]=t}if(c!==r){0!==c&&(e=e.slice(c));const t=c+3*e.length;l=n(l,r,t,1)>>>0,r=t;const o=s().subarray(l+c,l+r),{written:i}=a.encodeInto(e,o);c+=i,l=n(l,r,c,1)>>>0}return o=c,l},i={wbg:{}};i.wbg.__wbindgen_init_externref_table=()=>{const e=t.__wbindgen_export_0,n=e.grow(4);e.set(0,void 0),e.set(n+0,void 0),e.set(n+1,null),e.set(n+2,!0),e.set(n+3,!1)};const c=new WebAssembly.Instance(e,i);return t=c.exports,t.__wbindgen_start&&t.__wbindgen_start(),n=(e,n)=>{const r=l(e,t.__wbindgen_malloc,t.__wbindgen_realloc),s=o,a=l(n,t.__wbindgen_malloc,t.__wbindgen_realloc),i=o;return BigInt.asUintN(64,t.solve_pow(r,s,a,i))},!0}catch(e){return console.error("[cap worker] failed to init wasm from module:",e),!1}})(a);if(!t)return console.warn("[cap worker] wasm init failed, falling back to JS solver."),e({salt:r,target:s})}if(null===n)return console.warn("[cap worker] no wasm module provided, falling back to JS solver."),e({salt:r,target:s});try{const e=performance.now(),t=n(r,s),o=performance.now();self.postMessage({nonce:Number(t),found:!0,durationMs:(o-e).toFixed(2)})}catch(e){console.error("[cap worker]",e),self.postMessage({found:!1,error:e.message||String(e)})}},self.onerror=e=>{self.postMessage({found:!1,error:e})}})();'],{type:"application/javascript"})),o)}class c{constructor(e){this._size=e,this._workers=[],this._idle=[],this._queue=[],this._wasmModule=null,this._spawnFailures=0}setWasm(e){this._wasmModule=e}_spawn(){const e=l(),t=new Worker(e);return t._busy=!1,this._workers.push(t),this._idle.push(t),t}_replaceWorker(e){const t=this._workers.indexOf(e);-1!==t&&this._workers.splice(t,1);const i=this._idle.indexOf(e);-1!==i&&this._idle.splice(i,1);try{e.terminate()}catch{}return this._spawnFailures++,this._spawnFailures>3?(console.error("[cap] worker spawn failed repeatedly, not retrying"),null):this._spawn()}_ensureSize(e){for(;this._workers.length<e;)this._spawn()}run(e,t){return new Promise((i,s)=>{this._queue.push({salt:e,target:t,resolve:i,reject:s}),this._dispatch()})}runMsg(e,t){return new Promise((i,s)=>{this._queue.push({msg:e,onProgress:t,resolve:i,reject:s}),this._dispatch()})}_dispatch(){for(;this._idle.length>0&&this._queue.length>0;){const e=this._idle.shift(),t=this._queue.shift(),{resolve:i,reject:s}=t,r=void 0!==t.msg;let n=!1;const a=({data:l})=>{if(!n)if(!l||"number"!=typeof l.progress||l.found)n=!0,e.removeEventListener("message",a),e.removeEventListener("error",o),this._spawnFailures=0,this._idle.push(e),l.found?i(r?l:l.nonce):s(new Error(l.error||"worker failed")),this._dispatch();else if(t.onProgress)try{t.onProgress(l.progress)}catch{}},o=t=>{if(n)return;n=!0,e.removeEventListener("message",a),e.removeEventListener("error",o);const i=this._replaceWorker(e);s(t),i&&this._dispatch()};e.addEventListener("message",a),e.addEventListener("error",o),r?e.postMessage(t.msg):this._wasmModule?e.postMessage({salt:t.salt,target:t.target,wasmModule:this._wasmModule},[]):e.postMessage({salt:t.salt,target:t.target})}}terminate(){for(const e of this._workers)try{e.terminate()}catch{}this._workers=[],this._idle=[],this._queue=[]}}class h extends HTMLElement{static formAssociated=!0;#e=null;#t=navigator.hardwareConcurrency||8;token=null;#i;#s;#r;#n;#a;#o;#l=!1;#c;#h;#d=null;#p=null;#u=null;#g=null;get#v(){return e&&!window.CAP_DISABLE_HAPTICS&&!this.hasAttribute("data-cap-disable-haptics")}#m(){return{state:"idle",challengeResp:null,challenges:null,results:[],completedCount:0,solvePromise:null,promoteFn:null,_listeners:[],pendingPromotion:null,token:null,tokenExpires:null,notify(){for(const e of this._listeners)e();this._listeners=[]},onSettled(e){"done"===this.state||"error"===this.state?e():this._listeners.push(e)}}}#b(){this.#d=this.#m(),this.#f()}#w(){this.#g&&(window.removeEventListener("mousemove",this.#g),window.removeEventListener("touchstart",this.#g),window.removeEventListener("keydown",this.#g),this.#g=null)}#f(){this.#w();const e=()=>{this.#w(),this.#y()};this.#g=e,window.addEventListener("mousemove",e,{passive:!0}),window.addEventListener("touchstart",e,{passive:!0}),window.addEventListener("keydown",e,{passive:!0})}#k(){return"function"==typeof this.checkVisibility?this.checkVisibility({checkOpacity:!0,checkVisibilityCSS:!0}):!!(this.offsetParent||this.getClientRects().length>0)}#y(){"idle"===this.#d.state&&this.#k()&&(this.#d.state="waiting",this.#p=setTimeout(()=>{this.#x()},2500))}async#x(){if("waiting"!==this.#d.state)return;this.#d.state="fetching";let e=this.getAttribute("data-cap-api-endpoint");if(!e&&window?.CAP_CUSTOM_FETCH&&(e="/"),e){e.endsWith("/")||(e+="/");try{const s=await t(`${e}challenge`,{method:"POST"});let r;try{r=await s.json()}catch{throw new Error("Failed to parse speculative challenge response")}if(r.error)throw new Error(r.error);if(r._apiEndpoint=e,this.#d.challengeResp=r,2===r.format&&Array.isArray(r.challenges))return this.#d.state="idle",void this.#d.notify();const{challenge:n,token:a}=r;let o=n;if(!Array.isArray(o)){let e=0;o=Array.from({length:n.c},()=>(e++,[i(`${a}${e}`,n.s),i(`${a}${e}d`,n.d)]))}this.#d.challenges=o,this.#d.state="solving",this.#d.solvePromise=this.#_(o)}catch(e){console.warn("[cap] speculative challenge fetch failed:",e),this.#d.state="error",this.#d.notify()}}else this.#d.state="idle"}async#_(e){l();let t=null;try{t=await a()}catch{}this.#u||(this.#u=new c(1),this.#u._spawn()),this.#u.setWasm(t);const i=e.length,s=new Array(i);let r=1,n=!1;this.#d.promoteFn=e=>{n||(n=!0,r=e,this.#u._size=e,this.#u._ensureSize(e))},null!==this.#d.pendingPromotion&&(this.#d.promoteFn(this.#d.pendingPromotion),this.#d.pendingPromotion=null);let o=0;for(;o<i;){const t=r,a=[],l=[];for(let s=0;s<t&&o<i;s++)l.push(o),a.push(e[o]),o++;this.#u._ensureSize(Math.max(r,t));const c=await Promise.all(a.map(e=>this.#u.run(e[0],e[1]).then(e=>(this.#d.completedCount++,e))));for(let e=0;e<l.length;e++)s[l[e]]=c[e];!n&&o<i&&await new Promise(e=>setTimeout(e,120))}return this.#d.results=s,this.#d.state="redeeming",this.#E(s),s}async#E(e){try{const i=this.#d.challengeResp,s=i._apiEndpoint;if(!s)throw new Error("[cap] speculative redeem: missing apiEndpoint");let n=null;if(i.instrumentation&&(n=await r(i.instrumentation),n?.__timeout||n?.__blocked))return this.#d.state="done",void this.#d.notify();const a=await t(`${s}redeem`,{method:"POST",body:JSON.stringify({token:i.token,solutions:e,...n&&{instr:n}}),headers:{"Content-Type":"application/json"}});let o;try{o=await a.json()}catch{throw new Error("Failed to parse speculative redeem response")}if(!o.success)throw new Error(o.error||"Speculative redeem failed");this.#d.token=o.token,this.#d.tokenExpires=new Date(o.expires).getTime(),this.#d.state="done",this.#d.notify()}catch(e){console.warn("[cap] speculative redeem failed (will redo on click):",e),this.#d.state="done",this.#d.notify()}}getI18nText(e,t){return this.getAttribute(`data-cap-i18n-${e}`)||t}static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","data-cap-worker-count","data-cap-i18n-initial-state","required"]}constructor(){super(),this.#c&&this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c=new Map,this.boundHandleProgress=this.handleProgress.bind(this),this.boundHandleSolve=this.handleSolve.bind(this),this.boundHandleError=this.handleError.bind(this),this.boundHandleReset=this.handleReset.bind(this);try{this.#h=this.attachInternals()}catch{}}#A(){this.#h?.setValidity&&(this.hasAttribute("required")&&!this.token?this.#h.setValidity({valueMissing:!0},this.getI18nText("required-label","Please verify you're human"),this.#s||this):this.#h.setValidity({}))}initialize(){l(),this.#d||(this.#d=this.#m()),this.#u||(this.#u=new c(1),this.#u._spawn())}attributeChangedCallback(e,t,i){if(e.startsWith("on")){const t=e.slice(2),s=this.#c.get(e);if(s&&this.removeEventListener(t,s),i){const i=t=>{const i=this.getAttribute(e);"function"==typeof window[i]&&window[i].call(this,t)};this.#c.set(e,i),this.addEventListener(t,i)}}"data-cap-worker-count"===e&&this.setWorkersCount(parseInt(i,10)),"data-cap-i18n-initial-state"===e&&this.#s&&this.#s?.querySelector(".label.active")&&this.animateLabel(this.getI18nText("initial-state","Verify you're human")),"required"===e&&this.#A()}async connectedCallback(){this.#o=this,this.shadowRoot?this.#i=this.shadowRoot:this.#i=this.attachShadow({mode:"open"}),this.#s||(this.#s=document.createElement("div")),this.createUI(),this.addEventListeners(),this.initialize(),this.#r.removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count"),t=e?parseInt(e,10):null;this.setWorkersCount(t||navigator.hardwareConcurrency||8);const i=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.#o.innerHTML=`<input type="hidden" name="${i}">`,this.#f(),this.#A(),this.addEventListener("invalid",this.#C)}#C=()=>{if(this.#s){try{this.scrollIntoView({behavior:"smooth",block:"center"})}catch{this.scrollIntoView()}this.#s.classList.remove("invalid"),this.#s.offsetWidth,this.#s.classList.add("invalid"),setTimeout(()=>this.#s?.classList.remove("invalid"),1500)}};async solve(){if(!this.#l){this.#S();try{this.#l=!0,this.updateUI("verifying",this.getI18nText("verifying-label","Verifying..."),!0),this.#r.setAttribute("aria-label",this.getI18nText("verifying-aria-label","Verifying you're a human, please wait")),this.dispatchEvent("progress",{progress:0});try{let e,s,n=this.getAttribute("data-cap-api-endpoint");if(!n&&window?.CAP_CUSTOM_FETCH)n="/";else if(!n)throw new Error("Missing API endpoint. Either custom fetch or an API endpoint must be provided.");if(n.endsWith("/")||(n+="/"),"done"===this.#d.state&&this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires){this.dispatchEvent("progress",{progress:100});const e=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${e}']`)&&(this.querySelector(`input[name='${e}']`).value=this.#d.token),this.dispatchEvent("solve",{token:this.#d.token}),this.token=this.#d.token;const t=this.#d.tokenExpires-Date.now();return this.#e&&clearTimeout(this.#e),this.#e=setTimeout(()=>this.reset(),t),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#v&&navigator.vibrate([10,50,20,30,40]),this.#b(),this.#l=!1,{success:!0,token:this.token}}if("done"===this.#d.state)e=this.#d.results,s=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100});else if("solving"===this.#d.state||"redeeming"===this.#d.state||"fetching"===this.#d.state||"waiting"===this.#d.state){"waiting"===this.#d.state&&(this.#p&&(clearTimeout(this.#p),this.#p=null),this.#d.state="waiting",this.#x()),this.#d.pendingPromotion=this.#t,this.#d.promoteFn&&this.#d.promoteFn(this.#t);const t=setInterval(()=>{const e=this.#d.state;if("done"===e||"error"===e)return void clearInterval(t);const i=this.#d.challenges?this.#d.challenges.length:1,s=this.#d.completedCount,r="redeeming"===e?99:"fetching"===e||"waiting"===e?0:Math.min(98,Math.round(s/i*100));this.dispatchEvent("progress",{progress:r})},150);if(await new Promise(e=>this.#d.onSettled(e)),clearInterval(t),"idle"===this.#d.state&&2===this.#d.challengeResp?.format&&Array.isArray(this.#d.challengeResp.challenges))s=this.#d.challengeResp,this.#d.challengeResp=null,e=await this.solveChallengesV2(s.challenges);else{if("done"!==this.#d.state)throw new Error("Speculative solve failed – please try again");if(this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires){this.dispatchEvent("progress",{progress:100});const e=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${e}']`)&&(this.querySelector(`input[name='${e}']`).value=this.#d.token),this.dispatchEvent("solve",{token:this.#d.token}),this.token=this.#d.token;const t=this.#d.tokenExpires-Date.now();return this.#e&&clearTimeout(this.#e),this.#e=setTimeout(()=>this.reset(),t),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#v&&navigator.vibrate([10,50,20,30,40]),this.#b(),this.#l=!1,{success:!0,token:this.token}}e=this.#d.results,s=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100})}}else{const r=this.#d.challengeResp;if(2===r?.format&&Array.isArray(r.challenges))s=r,this.#d.challengeResp=null;else{const e=await t(`${n}challenge`,{method:"POST"});try{s=await e.json()}catch{throw new Error("Failed to parse challenge response from server")}if(s.error)throw new Error(s.error)}if(2===s.format&&Array.isArray(s.challenges))e=await this.solveChallengesV2(s.challenges);else{const{challenge:t,token:r}=s;let n=t;if(!Array.isArray(n)){let e=0;n=Array.from({length:t.c},()=>(e++,[i(`${r}${e}`,t.s),i(`${r}${e}d`,t.d)]))}e=await this.solveChallenges(n)}}const a=s.instrumentation?r(s.instrumentation):Promise.resolve(null),o=await a;if(o?.__timeout||o?.__blocked){t(`${n}redeem`,{method:"POST",body:JSON.stringify({token:s.token,solutions:e,...o.__blocked&&{instr_blocked:!0},...o.__timeout&&{instr_timeout:!0}}),headers:{"Content-Type":"application/json"}}).catch(()=>{}),this.updateUIBlocked(this.getI18nText("error-label","Error"),o?.__blocked),this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again")),this.removeEventListener("error",this.boundHandleError);const i=new CustomEvent("error",{bubbles:!0,composed:!0,detail:{isCap:!0,message:"Instrumentation failed"}});return super.dispatchEvent(i),this.addEventListener("error",this.boundHandleError),this.executeAttributeCode("onerror",i),console.error("[cap]","Instrumentation failed"),void(this.#l=!1)}const{token:l}=s,c=await t(`${n}redeem`,{method:"POST",body:JSON.stringify({token:l,solutions:e,...o&&{instr:o}}),headers:{"Content-Type":"application/json"}});let h;try{h=await c.json()}catch{throw new Error("Failed to parse server response")}if(this.dispatchEvent("progress",{progress:100}),!h.success)throw new Error(h.error||"Invalid solution");const d=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${d}']`)&&(this.querySelector(`input[name='${d}']`).value=h.token),this.dispatchEvent("solve",{token:h.token}),this.token=h.token,this.#b(),this.#e&&clearTimeout(this.#e);const p=new Date(h.expires).getTime()-Date.now();return p>0&&p<864e5?this.#e=setTimeout(()=>this.reset(),p):this.error("Invalid expiration time"),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#v&&navigator.vibrate([10,50,20,30,40]),{success:!0,token:this.token}}catch(e){throw this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again")),this.error(e.message),e}}finally{this.#l=!1}}}async solveChallengesV2(e){const t=e.length;let i=0;const s=new Array(e.length);for(let t=0;t<e.length;t++){const i=e[t];if(!i||"object"!=typeof i||"sha256-pow"!==i.protocol&&"rsw"!==i.protocol&&"instrumentation"!==i.protocol)throw new Error(`[cap] unsupported format-2 protocol '${i?.protocol}'`)}let n=null;if("object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate)try{n=await a()}catch(e){console.warn("[cap] wasm unavailable, falling back to JS solver:",e)}const o=Math.max(1,Math.min(this.#t,e.length)),l=new c(o);l.setWasm(n),l._ensureSize(o);const h=(e,t)=>Promise.race([e,new Promise((e,i)=>setTimeout(()=>i(new Error(`[cap] ${t} timed out after 60000ms`)),6e4))]),d=new Array(e.length).fill(0),p=()=>{const e=d.reduce((e,t)=>e+t,0)+i,s=Math.min(99,Math.round(e/t*100));this.dispatchEvent("progress",{progress:s})};try{await Promise.all(e.map((e,t)=>"sha256-pow"===e.protocol?h(l.run(e.payload.salt,e.payload.target),`sha256-pow worker #${t}`).then(e=>{s[t]={nonce:Number(e)},d[t]=0,i++,p()}):"rsw"===e.protocol?h(l.runMsg({kind:"rsw",N:e.payload.N,x:e.payload.x,t:0|e.payload.t},e=>{d[t]=e,p()}),`rsw worker #${t}`).then(e=>{s[t]={y:e.y},d[t]=0,i++,p()}):r(e.payload.blob).then(e=>{s[t]=e?.__timeout?{timeout:!0}:e?.__blocked?{blocked:!0}:{instr:e},d[t]=0,i++,p()})))}finally{l.terminate()}return s}async solveChallenges(e){const t=e.length;let i=0;let s=null;const r="object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate;if(r)try{s=await a()}catch(e){console.warn("[cap] wasm unavailable, falling back to JS solver:",e)}if(!r&&!this.#i.querySelector(".warning")){const e=document.createElement("div");e.className="warning",e.style.cssText="width:var(--cap-widget-width,230px);background:rgb(237,56,46);color:white;padding:4px 6px;padding-bottom:calc(var(--cap-border-radius,14px) + 5px);font-size:10px;box-sizing:border-box;font-family:system-ui;border-top-left-radius:8px;border-top-right-radius:8px;text-align:center;user-select:none;margin-bottom:-35.5px;opacity:0;transition:margin-bottom .3s,opacity .3s;",e.innerText=this.getI18nText("wasm-disabled","Enable WASM for significantly faster solving"),this.#i.insertBefore(e,this.#i.firstChild),setTimeout(()=>{e.style.marginBottom="calc(-1 * var(--cap-border-radius, 14px))",e.style.opacity=1},10)}const n=new c(this.#t);n.setWasm(s),n._ensureSize(this.#t);const o=[];try{for(let s=0;s<e.length;s+=this.#t){const r=e.slice(s,Math.min(s+this.#t,e.length)),a=await Promise.all(r.map(([e,s])=>n.run(e,s).then(e=>{i++;const s=Math.min(99,Math.round((0+i)/t*100));return this.dispatchEvent("progress",{progress:s}),e})));o.push(...a)}}finally{n.terminate()}return o}setWorkersCount(e){const t=parseInt(e,10),i=Math.min(navigator.hardwareConcurrency||8,16);this.#t=!Number.isNaN(t)&&t>0&&t<=i?t:navigator.hardwareConcurrency||8}createUI(){this.#s.classList.add("captcha"),this.#s.setAttribute("role","group"),this.#s.setAttribute("aria-label",this.getI18nText("group-aria-label","Cap verification")),this.#r=document.createElement("div"),this.#r.className="captcha-trigger",this.#r.setAttribute("part","trigger"),this.#r.setAttribute("role","button"),this.#r.setAttribute("tabindex","0"),this.#r.setAttribute("aria-label",this.getI18nText("verify-aria-label","Click to verify you're a human")),this.#r.setAttribute("aria-live","polite"),this.#r.setAttribute("disabled","true"),this.#r.innerHTML=`<div class="checkbox" part="checkbox" aria-hidden="true"><svg class="progress-ring" viewBox="0 0 32 32" aria-hidden="true"><circle class="progress-ring-bg" cx="16" cy="16" r="14"></circle><circle class="progress-ring-circle" cx="16" cy="16" r="14"></circle></svg></div><p part="label" class="label-wrapper"><span class="label active">${this.getI18nText("initial-state","Verify you're human")}</span></p>`,this.#s.appendChild(this.#r),this.#a=document.createElement("a"),this.#a.className="cap-troubleshoot-link",this.#a.setAttribute("part","troubleshoot"),this.#a.setAttribute("target","_blank"),this.#a.setAttribute("rel","noopener"),this.#a.hidden=!0,this.#s.appendChild(this.#a),this.#n=document.createElement("a"),this.#n.className="credits",this.#n.setAttribute("aria-label","Secured by Cap"),this.#n.setAttribute("href","https://trycap.dev"),this.#n.setAttribute("target","_blank"),this.#n.setAttribute("title","Secured by Cap: The self-hosted CAPTCHA for the modern web."),this.#n.textContent="Cap",this.#s.appendChild(this.#n),this.#i.innerHTML=`<style${window.CAP_CSS_NONCE?` nonce=${window.CAP_CSS_NONCE}`:""}>:host{display:inline-block}@media (prefers-reduced-motion:reduce){.captcha,.captcha *{transition:none!important;animation:none!important}.label{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}.label:not(.active),.label.exit{display:none!important}}.captcha,.captcha *{box-sizing:border-box}.captcha{width:var(--cap-widget-width,260px);height:var(--cap-widget-height,58px);background-color:var(--cap-background,#fdfdfd);border:1px solid var(--cap-border-color,#dddddd8f);border-radius:var(--cap-border-radius,14px);-webkit-user-select:none;user-select:none;cursor:pointer;-webkit-tap-highlight-color:#fff0;color:var(--cap-color,#212121);font-family:var(--cap-font,system, -apple-system, "BlinkMacSystemFont", ".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif);transition:filter .2s,transform .2s,height .2s;display:inline-block;position:relative;overflow:hidden}.captcha.has-troubleshoot{height:calc(var(--cap-widget-height,58px) + 26px)}.captcha.has-troubleshoot .captcha-trigger{inset-block-end:26px}.captcha:not([data-state]):active{transform:scale(.97)}.captcha:hover{filter:brightness(98%)}.captcha-trigger{padding:var(--cap-widget-padding,14px);align-items:center;gap:var(--cap-gap,15px);border-radius:inherit;transition:inset .2s;display:flex;position:absolute;inset:0}.captcha-trigger:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:-3px}.checkbox{width:var(--cap-checkbox-size,25px);height:var(--cap-checkbox-size,25px);border:var(--cap-checkbox-border,1px solid #aaaaaad1);border-radius:var(--cap-checkbox-border-radius,6px);background-color:var(--cap-checkbox-background,#fafafa91);margin-top:var(--cap-checkbox-margin,2px);margin-bottom:var(--cap-checkbox-margin,2px);flex-shrink:0;transition:opacity .2s}.captcha p{-webkit-user-select:none;user-select:none;margin:0;font-size:15px;font-weight:500}.label-wrapper{flex:1;align-items:center;min-width:0;height:2em;display:flex;position:relative;overflow:hidden}.label-wrapper:before,.label-wrapper:after{content:"";pointer-events:none;z-index:1;width:100%;height:.6em;position:absolute;inset-inline-start:0}.label-wrapper:before{background:linear-gradient(to bottom, var(--cap-background,#fdfdfd), transparent);top:0}.label-wrapper:after{background:linear-gradient(to top, var(--cap-background,#fdfdfd), transparent);bottom:0}.label{white-space:nowrap;opacity:0;filter:blur(2px);transition:transform .5s cubic-bezier(.25,1,.5,1),opacity .5s,filter .5s;position:absolute;transform:translateY(100%)}.label.active{opacity:1;filter:none;transform:translateY(0)}.label.exit{opacity:0;filter:blur(2px);transform:translateY(-100%)}.checkbox .progress-ring{width:100%;height:100%;display:none;transform:rotate(-90deg)}.checkbox .progress-ring-bg{fill:none;stroke:var(--cap-spinner-background-color,#eee);stroke-width:var(--cap-spinner-thickness,3)}.checkbox .progress-ring-circle{fill:none;stroke:var(--cap-spinner-color,#000);stroke-width:var(--cap-spinner-thickness,3);stroke-linecap:round;stroke-dasharray:87.96;stroke-dashoffset:87.96px;transition:stroke-dashoffset .3s}.captcha[data-state=verifying] .checkbox{background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;display:flex;transform:scale(1.1)}.captcha[data-state=verifying] .checkbox .progress-ring{display:block}.captcha[data-state=done] .checkbox{background-image:var(--cap-checkmark,url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E));background-size:cover;border:1px solid #0000}.captcha[data-state=done] .checkbox .progress-ring{display:none}.captcha[data-state=error] .checkbox{background-image:var(--cap-error-cross,url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 24 24'%3E%3Cpath fill='%23f55b50' d='M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8'/%3E%3C%2Fsvg%3E"));background-size:cover;border:1px solid #0000}.captcha[data-state=error] .checkbox .progress-ring{display:none}.captcha.invalid{border-color:var(--cap-invalid-border-color,#f55b50);box-shadow:0 0 0 3px var(--cap-invalid-ring-color,#f55b5033);animation:.5s cubic-bezier(.36,.07,.19,.97) cap-shake}@keyframes cap-shake{10%,90%{transform:translate(-1px)}20%,80%{transform:translate(2px)}30%,50%,70%{transform:translate(-4px)}40%,60%{transform:translate(4px)}}@media (prefers-reduced-motion:reduce){.captcha.invalid{animation:none!important}}.captcha-trigger[disabled]{cursor:not-allowed}.captcha[data-state=verifying] .captcha-trigger{cursor:progress}.captcha[data-state=done] .captcha-trigger{cursor:default}.credits{color:var(--cap-color,#212121);text-underline-offset:.18em;z-index:2;border-radius:4px;justify-content:flex-end;align-items:center;min-width:24px;min-height:24px;padding:4px 6px;text-decoration:underline;text-decoration-thickness:.08em;position:absolute;inset-block-end:4px;inset-inline-end:4px;opacity:.8!important;font-size:12px!important;display:inline-flex!important}.captcha .credits{visibility:visible!important;pointer-events:all!important;display:inline-flex!important}.credits:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px;opacity:1!important}.cap-troubleshoot-link{min-width:24px;min-height:24px;color:var(--cap-troubleshoot-color,#0050a0);text-underline-offset:.15em;cursor:pointer;z-index:2;border-radius:4px;align-items:center;padding:4px 6px;font-size:13px;font-weight:500;text-decoration:underline;text-decoration-thickness:.08em;display:inline-flex;position:absolute;inset-block-end:4px;inset-inline-start:14px}.cap-troubleshoot-link[hidden]{display:none}.cap-troubleshoot-link:hover{opacity:.85}.cap-troubleshoot-link:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px}@media (forced-colors:active){.captcha,.checkbox{border-color:canvastext}:is(.captcha-trigger:focus-visible,.credits:focus-visible,.cap-troubleshoot-link:focus-visible){outline-color:highlight}.progress-ring-bg{stroke:graytext}.progress-ring-circle{stroke:canvastext}.captcha.invalid{box-shadow:none;border-color:mark}.credits{opacity:1!important}}</style>`,this.#i.appendChild(this.#s),this.#S(),setTimeout(()=>this.#S(),100)}addEventListeners(){this.#r&&(this.#n.addEventListener("click",e=>{e.preventDefault(),window.open(`https://trycap.dev/?${new URLSearchParams({utm_source:"cap_widget",utm_medium:"referral",utm_campaign:"widget",utm_content:window.CAP_DISABLE_WIDGET_REF?"":location.hostname,ref:window.CAP_DISABLE_WIDGET_REF?"":location.href||"",sub:window.CAP_DISABLE_WIDGET_REF?"":document.referrer||""}).toString()}`,"_blank")}),this.#r.addEventListener("click",()=>{this.#r.hasAttribute("disabled")||this.solve()}),this.#r.addEventListener("mousedown",()=>{!this.#r.hasAttribute("disabled")&&this.#v&&navigator.vibrate(5)}),this.#r.addEventListener("keydown",e=>{e.target===this.#r&&("Enter"!==e.key&&" "!==e.key||this.#r.hasAttribute("disabled")||(e.preventDefault(),e.stopPropagation(),this.solve()))}),this.addEventListener("progress",this.boundHandleProgress),this.addEventListener("solve",this.boundHandleSolve),this.addEventListener("error",this.boundHandleError),this.addEventListener("reset",this.boundHandleReset))}#T(){if(!this.#o)return!1;const e=this.#o.getBoundingClientRect();if(0===e.width&&0===e.height)return!0;const t=window.getComputedStyle(this.#o);return"none"===t.display||"hidden"===t.visibility}#S(){this.#n&&this.#s&&!this.#T()&&(this.#n.isConnected&&this.#n.parentNode===this.#s||this.#s.appendChild(this.#n),this.#n.textContent&&this.#n.textContent.trim()||(this.#n.textContent="Cap"),"https://trycap.dev"!==this.#n.getAttribute("href")&&this.#n.setAttribute("href","https://trycap.dev"),this.#n.style.cssText=["display: inline-flex !important","visibility: visible !important","opacity: 0.8 !important","pointer-events: all !important","font-size: 12px !important","transform: none !important","clip-path: none !important","filter: none !important","position: absolute !important"].join("; "))}animateLabel(e){if(!this.#r)return;const t=this.#r.querySelector(".label-wrapper");if(!t)return;if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches){const i=t.querySelector(".label.active");if(i)i.textContent=e;else{const i=document.createElement("span");i.className="label active",i.textContent=e,t.appendChild(i)}return}const i=t.querySelector(".label.active"),s=document.createElement("span");s.className="label",s.textContent=e,t.appendChild(s),s.offsetWidth,s.classList.add("active"),i&&(i.classList.remove("active"),i.classList.add("exit"),i.addEventListener("transitionend",()=>i.remove(),{once:!0}))}updateUI(e,t,i=!1){this.#s&&this.#r&&(this.#s.setAttribute("data-state",e),this.#s.classList.remove("has-troubleshoot"),this.animateLabel(t),this.#a&&(this.#a.hidden=!0),i?this.#r.setAttribute("disabled","true"):this.#r.removeAttribute("disabled"))}updateUIBlocked(e,t=!1){if(this.#s&&this.#r&&(this.#s.setAttribute("data-state","error"),this.#r.removeAttribute("disabled"),this.animateLabel(e),this.#a))if(t){const e=this.getAttribute("data-cap-troubleshooting-url")||"https://trycap.dev/guide/troubleshooting/instrumentation.html";this.#a.setAttribute("href",e),this.#a.textContent=this.getI18nText("troubleshooting-label","Troubleshoot"),this.#a.hidden=!1,this.#s.classList.add("has-troubleshoot")}else this.#a.hidden=!0,this.#s.classList.remove("has-troubleshoot")}handleProgress(e){if(!this.#r)return;const t=this.#r.querySelector(".progress-ring-circle");if(t){const i=2*Math.PI*14,s=i-e.detail.progress/100*i;t.style.strokeDashoffset=s}const i=this.#r.querySelector(".label-wrapper");if(i){const e=i.querySelector(".label.active");e&&(e.textContent=`${this.getI18nText("verifying-label","Verifying...")}`)}this.executeAttributeCode("onprogress",e)}handleSolve(e){this.updateUI("done",this.getI18nText("solved-label","You're a human"),!0),this.executeAttributeCode("onsolve",e),this.#h?.setValidity?.({}),this.#s?.classList.remove("invalid")}handleError(e){this.updateUI("error",this.getI18nText("error-label","Error. Try again.")),this.executeAttributeCode("onerror",e),this.#v&&navigator.vibrate([10,40,10])}handleReset(e){this.updateUI("",this.getI18nText("initial-state","I'm a human")),this.executeAttributeCode("onreset",e),this.#A()}executeAttributeCode(e,t){const i=this.getAttribute(e);i&&(console.error("[cap] using `onxxx='…'` is strongly discouraged and will be deprecated soon. please use `addEventListener` callbacks instead."),new Function("event",i).call(this,t))}error(e="Unknown error"){console.error("[cap]",e),this.dispatchEvent("error",{isCap:!0,message:e})}dispatchEvent(e,t={}){const i=new CustomEvent(e,{bubbles:!0,composed:!0,detail:t});super.dispatchEvent(i)}reset(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.token=null,this.dispatchEvent("reset");const e=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${e}']`)&&(this.querySelector(`input[name='${e}']`).value="")}get tokenValue(){return this.token}disconnectedCallback(){this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c.clear(),this.#i&&(this.#i.innerHTML=""),this.reset(),this.cleanup()}cleanup(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.#w(),this.#p&&(clearTimeout(this.#p),this.#p=null),this.#u&&(this.#u.terminate(),this.#u=null),this.#d&&(this.#d.state="error",this.#d.notify(),this.#d=null)}}class d{constructor(e={},t){const i=t||document.createElement("cap-widget");if(Object.entries(e).forEach(([e,t])=>{i.setAttribute(e,t)}),!e.apiEndpoint&&!window?.CAP_CUSTOM_FETCH)throw i.remove(),new Error("Missing API endpoint. Either custom fetch or an API endpoint must be provided.");e.apiEndpoint&&i.setAttribute("data-cap-api-endpoint",e.apiEndpoint),t||i.hasAttribute("data-cap-disable-haptics")||i.setAttribute("data-cap-disable-haptics",""),this.widget=i,this.solve=this.widget.solve.bind(this.widget),this.reset=this.widget.reset.bind(this.widget),this.addEventListener=this.widget.addEventListener.bind(this.widget),Object.defineProperty(this,"token",{get:()=>i.token,configurable:!0,enumerable:!0}),t||(i.style.display="none",document.documentElement.appendChild(i))}}window.Cap=d,customElements.get("cap-widget")||window?.CAP_DONT_SKIP_REDEFINE?customElements.get("cap-widget")&&console.warn("[cap] the cap-widget element has already been defined, skipping re-defining it.\nto prevent this, set window.CAP_DONT_SKIP_REDEFINE to true"):customElements.define("cap-widget",h),"object"==typeof exports&&"undefined"!=typeof module?module.exports=d:"function"==typeof define&&define.amd&&define([],()=>d),"undefined"!=typeof exports&&(exports.default=d)})();
|
|
1
|
+
(()=>{const e="vibrate"in navigator&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches;if("undefined"==typeof window)return;const t=["#f5c2e7","#cba6f7","#f38ba8","#fab387","#f9e2af","#a6e3a1","#94e2d5","#89dceb","#b4befe"],i=(e,i,s)=>{const r=0===i?"9999px":"0",n=i===s-1?"9999px":"0";return`color:#1e1e2e;background:${(e=>{if("cap"===e)return"#89b4fa";let i=0;for(let t=0;t<e.length;t++)i=e.charCodeAt(t)+((i<<5)-i);return t[Math.abs(i)%t.length]})(e)};margin-left:${i?"-6px":0};padding:0 6px;border-radius:${r} ${n} ${n} ${r};font-weight:600`},s={};for(const e of["debug","info","warn","error"])s[e]=(t,...s)=>{if(window.CAP_SILENT||"debug"===e&&!window.CAP_DEBUG)return;const r=t.map(e=>`%c${e}`).join(" "),n=t.map((e,s)=>i(e,s,t.length));console["debug"===e?"log":e](r,...n,...s)};const r=e=>e?["cap",e]:["cap"],n=e=>`${Math.round(performance.now()-e)}ms`,a=(e,t)=>Object.assign(new Error(t),{code:e}),o=(e,t={})=>window?.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(e,t):fetch(e,t),l=(e,t)=>t?t.aborted?Promise.reject(a("aborted","aborted")):Promise.race([e,new Promise((e,i)=>t.addEventListener("abort",()=>i(a("aborted","aborted")),{once:!0}))]):e,c="initial-state,verifying-label,solved-label,error-label,required-label,troubleshooting-label,group-aria-label,verify-aria-label,verifying-aria-label,verified-aria-label,error-aria-label".split(","),h={"zh-cn":"确认你是真人/正在验证.../你是真人/出错了。请重试。/请确认你是真人/故障排除/Cap 验证/点击以确认你是真人/正在验证你是真人,请稍候/我们已确认你是真人,你可以继续了/发生错误,请重试",es:"Verifica que eres humano/Verificando.../Eres humano/Error. Inténtalo de nuevo./Verifica que eres humano/Solucionar problemas/Verificación de Cap/Haz clic para verificar que eres humano/Verificando que eres humano, espera/Hemos verificado que eres humano, ya puedes continuar/Se produjo un error, inténtalo de nuevo",hi:"पुष्टि करें कि आप मानव हैं/सत्यापित हो रहा है.../आप मानव हैं/त्रुटि। पुनः प्रयास करें।/कृपया पुष्टि करें कि आप मानव हैं/समस्या निवारण/Cap सत्यापन/पुष्टि करने के लिए क्लिक करें कि आप मानव हैं/सत्यापित किया जा रहा है कि आप मानव हैं, प्रतीक्षा करें/हमने पुष्टि कर दी है कि आप मानव हैं, अब आप जारी रख सकते हैं/एक त्रुटि हुई, पुनः प्रयास करें",ar:"تحقق من أنك إنسان/جارٍ التحقق.../أنت إنسان/خطأ. حاول مرة أخرى./يرجى التحقق من أنك إنسان/استكشاف الأخطاء وإصلاحها/تحقق Cap/انقر للتحقق من أنك إنسان/جارٍ التحقق من أنك إنسان، يرجى الانتظار/لقد تحققنا من أنك إنسان، يمكنك المتابعة الآن/حدث خطأ، يرجى المحاولة مرة أخرى",pt:"Sou humano/Verificando.../Você é humano/Erro. Tente novamente./Verifique que você é humano/Solução de problemas/Verificação Cap/Clique para verificar que você é humano/Verificando que você é humano, aguarde/Verificamos que você é humano, você pode continuar/Ocorreu um erro, tente novamente",ru:"Я человек/Проверка.../Вы человек/Ошибка. Повторите./Подтвердите, что вы человек/Устранение неполадок/Проверка Cap/Нажмите, чтобы подтвердить, что вы человек/Проверяем, что вы человек, подождите/Мы подтвердили, что вы человек, можете продолжить/Произошла ошибка, повторите попытку",ja:"私は人間です/確認中.../あなたは人間です/エラー。再試行を。/あなたが人間であることを確認してください/トラブルシューティング/Cap 認証/クリックして人間であることを確認/あなたが人間であることを確認しています。お待ちください/あなたが人間であることを確認しました。続行できます/エラーが発生しました。もう一度お試しください",de:"Ich bin ein Mensch/Wird überprüft.../Sie sind ein Mensch/Fehler. Erneut versuchen./Bitte bestätigen Sie, dass Sie ein Mensch sind/Fehlerbehebung/Cap-Verifizierung/Klicken, um zu bestätigen, dass Sie ein Mensch sind/Überprüfung, ob Sie ein Mensch sind, bitte warten/Wir haben bestätigt, dass Sie ein Mensch sind, Sie können fortfahren/Ein Fehler ist aufgetreten, bitte erneut versuchen",fr:"Je suis humain/Vérification.../Vous êtes humain/Erreur. Réessayez./Veuillez vérifier que vous êtes humain/Dépannage/Vérification Cap/Cliquez pour vérifier que vous êtes humain/Vérification que vous êtes humain, veuillez patienter/Nous avons vérifié que vous êtes humain, vous pouvez continuer/Une erreur s'est produite, veuillez réessayer"};function d(e,t){let i=function(e){let t=2166136261;for(let i=0;i<e.length;i++)t^=e.charCodeAt(i),t+=(t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24);return t>>>0}(e),s="";function r(){return i^=i<<13,i^=i>>>17,i^=i<<5,i>>>0}for(;s.length<t;){s+=r().toString(16).padStart(8,"0")}return s.substring(0,t)}let u=null;async function p(e){const t=(e=>{const t=atob(e),i=new Uint8Array(t.length);for(let e=0;e<t.length;e++)i[e]=t.charCodeAt(e);return i})(e),i=(new TextDecoder).decode(await async function(e){if("undefined"!=typeof DecompressionStream)try{const t=new DecompressionStream("deflate-raw"),i=t.writable.getWriter(),s=t.readable.getReader();i.write(e).then(()=>i.close()).catch(()=>{});const r=[];for(;;){const{done:e,value:t}=await s.read();if(e)break;r.push(t)}let n=0;for(const e of r)n+=e.length;const a=new Uint8Array(n);let o=0;for(const e of r)a.set(e,o),o+=e.length;return a}catch{}return u||(u=new Promise((e,t)=>{const i=window.CAP_PAKO_URL||"https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako_inflate.min.js";s.debug(r("instr"),"DecompressionStream unavailable, loading pako from",i);const n=document.createElement("script");n.src=i;const a=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE;a&&n.setAttribute("nonce",a),n.onload=()=>{window.pako?.inflateRaw?e(window.pako):t(new Error("pako loaded but inflateRaw is missing"))},n.onerror=()=>{u=null,t(new Error(`failed to load pako fallback from ${i}`))},document.head.appendChild(n)})),(await u).inflateRaw(e)}(t));return new Promise(e=>{var t=setTimeout(()=>{n(),e({__timeout:!0})},2e4),s=document.createElement("iframe");s.setAttribute("sandbox","allow-scripts"),s.setAttribute("aria-hidden","true"),s.style.cssText="position:absolute;width:1px;height:1px;top:-9999px;left:-9999px;border:none;opacity:0;pointer-events:none;";var r=!1;function n(){r||(r=!0,clearTimeout(t),window.removeEventListener("message",a),s.parentNode&&s.parentNode.removeChild(s))}function a(t){if(s.contentWindow&&t.source===s.contentWindow){var i=t.data;i&&"object"==typeof i&&("cap:instr"===i.type?(n(),i.blocked?e({__blocked:!0,blockReason:i.blockReason||"automated_browser"}):i.result?e(i.result):e({__timeout:!0})):"cap:error"===i.type&&(n(),e({__timeout:!0})))}}window.addEventListener("message",a);const o=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE,l=o?` nonce="${String(o).replace(/"/g,""")}"`:"";s.srcdoc='<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><script'+l+">"+i+"\n<\/script></body></html>",document.body.appendChild(s)})}let g=null;const v=()=>{if(g)return g;const e=window.CAP_CUSTOM_WASM_URL||"https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.7/browser/cap_wasm_bg.wasm",t=performance.now();return s.debug(r("wasm"),"fetching",e),g=fetch(e).then(e=>{if(!e.ok)throw new Error(`Failed to fetch wasm: ${e.status}`);return e.arrayBuffer()}).then(e=>WebAssembly.compile(e)).then(e=>(s.debug(r("wasm"),`ready in ${n(t)}`),e)).catch(e=>{throw g=null,s.warn(r("wasm"),`load failed (${n(t)}):`,e.message||e),e}),g};"object"==typeof WebAssembly&&"function"==typeof WebAssembly.compile&&v().catch(()=>{});let b=null;function m(){return b||(b=URL.createObjectURL(new Blob(['(()=>{const e=(e,...t)=>{self.CAP_SILENT||console[e]("[cap worker]",...t)},t=async({salt:t,target:n})=>{let s=0;const r=new TextEncoder,o=4*n.length,a=Math.floor(o/8),l=o%8,i=n.length%2==0?n:`${n}0`,c=i.length/2,f=new Uint8Array(c);for(let e=0;e<c;e++)f[e]=parseInt(i.substring(2*e,2*e+2),16);const g=l>0?255<<8-l&255:0;for(;;)try{for(let e=0;e<5e4;e++){const e=t+s,n=r.encode(e),o=await crypto.subtle.digest("SHA-256",n),i=new Uint8Array(o);let c=!0;for(let e=0;e<a;e++)if(i[e]!==f[e]){c=!1;break}if(c&&l>0&&(i[a]&g)!==(f[a]&g)&&(c=!1),c)return void self.postMessage({nonce:s,found:!0});s++}}catch(t){return e("error","fallback solver crashed:",t.message||t),void self.postMessage({found:!1,error:t.message})}},n=e=>{const t=BigInt("0x"+e.N);let n=BigInt("0x"+e.x);const s=0|e.t,r=Math.max(64,Math.floor(s/50)),o=performance.now();for(let e=0;e<s;e+=r){const o=Math.min(s,e+r);for(let s=e;s<o;s++)n=n*n%t;o<s&&self.postMessage({progress:o/s})}self.postMessage({found:!0,y:n.toString(16),durationMs:(performance.now()-o).toFixed(2)})};if("object"!=typeof WebAssembly||"function"!=typeof WebAssembly?.instantiate)return e("warn","WebAssembly unavailable, using JS fallback solver (significantly slower)"),void(self.onmessage=async({data:e})=>"rsw"===e?.kind?n(e):t({salt:e.salt,target:e.target}));let s=null;self.onmessage=async({data:r})=>{if("rsw"===r?.kind)return n(r);const{salt:o,target:a,wasmModule:l}=r;if(l instanceof WebAssembly.Module&&null===s){const n=(t=>{try{let e,n=0,r=null;const o=()=>(null!==r&&0!==r.byteLength||(r=new Uint8Array(e.memory.buffer)),r),a=new TextEncoder,l=(e,t,s)=>{if(void 0===s){const s=a.encode(e),r=t(s.length,1)>>>0;return o().subarray(r,r+s.length).set(s),n=s.length,r}let r=e.length,l=t(r,1)>>>0;const i=o();let c=0;for(;c<r;c++){const t=e.charCodeAt(c);if(t>127)break;i[l+c]=t}if(c!==r){0!==c&&(e=e.slice(c));const t=c+3*e.length;l=s(l,r,t,1)>>>0,r=t;const n=o().subarray(l+c,l+r),{written:i}=a.encodeInto(e,n);c+=i,l=s(l,r,c,1)>>>0}return n=c,l},i={wbg:{}};i.wbg.__wbindgen_init_externref_table=()=>{const t=e.__wbindgen_export_0,n=t.grow(4);t.set(0,void 0),t.set(n+0,void 0),t.set(n+1,null),t.set(n+2,!0),t.set(n+3,!1)};const c=new WebAssembly.Instance(t,i);return e=c.exports,e.__wbindgen_start&&e.__wbindgen_start(),s=(t,s)=>{const r=l(t,e.__wbindgen_malloc,e.__wbindgen_realloc),o=n,a=l(s,e.__wbindgen_malloc,e.__wbindgen_realloc),i=n;return BigInt.asUintN(64,e.solve_pow(r,o,a,i))},!0}catch(t){return e("error","wasm init failed:",t.message||t),!1}})(l);if(!n)return e("warn","wasm init failed, falling back to JS solver"),t({salt:o,target:a})}if(null===s)return e("warn","no wasm module provided, falling back to JS solver"),t({salt:o,target:a});try{const e=performance.now(),t=s(o,a),n=performance.now();self.postMessage({nonce:Number(t),found:!0,durationMs:(n-e).toFixed(2)})}catch(t){e("error","solve_pow threw:",t.message||t),self.postMessage({found:!1,error:t.message||String(t)})}},self.onerror=e=>{self.postMessage({found:!1,error:e})}})();'],{type:"application/javascript"})),b)}class f{constructor(e){this._size=e,this._workers=[],this._idle=[],this._queue=[],this._wasmModule=null,this._spawnFailures=0}setWasm(e){this._wasmModule=e}_spawn(){const e=m(),t=new Worker(e);return t._busy=!1,this._workers.push(t),this._idle.push(t),t}_replaceWorker(e){const t=this._workers.indexOf(e);-1!==t&&this._workers.splice(t,1);const i=this._idle.indexOf(e);-1!==i&&this._idle.splice(i,1);try{e.terminate()}catch{}return this._spawnFailures++,s.warn(r("pool"),`worker died, replacing (attempt ${this._spawnFailures}/3)`),this._spawnFailures>3?(s.error(r("pool"),"worker spawn failed repeatedly, giving up"),null):this._spawn()}_ensureSize(e){for(;this._workers.length<e;)this._spawn()}run(e,t){return new Promise((i,s)=>{this._queue.push({salt:e,target:t,resolve:i,reject:s}),this._dispatch()})}runMsg(e,t){return new Promise((i,s)=>{this._queue.push({msg:e,onProgress:t,resolve:i,reject:s}),this._dispatch()})}_dispatch(){for(;this._idle.length>0&&this._queue.length>0;){const e=this._idle.shift(),t=this._queue.shift(),{resolve:i,reject:s}=t,r=void 0!==t.msg;let n=!1;const a=({data:l})=>{if(!n)if(!l||"number"!=typeof l.progress||l.found)n=!0,e.removeEventListener("message",a),e.removeEventListener("error",o),this._spawnFailures=0,this._idle.push(e),l.found?i(r?l:l.nonce):s(new Error(l.error||"worker failed")),this._dispatch();else if(t.onProgress)try{t.onProgress(l.progress)}catch{}},o=t=>{if(n)return;n=!0,e.removeEventListener("message",a),e.removeEventListener("error",o);const i=this._replaceWorker(e);s(t),i&&this._dispatch()};e.addEventListener("message",a),e.addEventListener("error",o),r?e.postMessage(t.msg):this._wasmModule?e.postMessage({salt:t.salt,target:t.target,wasmModule:this._wasmModule},[]):e.postMessage({salt:t.salt,target:t.target})}}terminate(){for(const e of this._workers)try{e.terminate()}catch{}this._workers=[],this._idle=[],this._queue=[]}}class w extends HTMLElement{static formAssociated=!0;#e=null;#t=navigator.hardwareConcurrency||8;token=null;#i;#s;#r;#n;#a;#o;#l=!1;#c;#h;#d=null;#u=null;#p=null;#g=null;#v=null;#b=null;get#m(){return e&&!window.CAP_DISABLE_HAPTICS&&!this.hasAttribute("data-cap-disable-haptics")}#f(){return{state:"idle",challengeResp:null,challenges:null,results:[],completedCount:0,solvePromise:null,promoteFn:null,_listeners:[],pendingPromotion:null,token:null,tokenExpires:null,notify(){for(const e of this._listeners)e();this._listeners=[]},onSettled(e){"done"===this.state||"error"===this.state?e():this._listeners.push(e)}}}#w(){this.#d=this.#f(),this.#y()}#k(){this.#g&&(window.removeEventListener("mousemove",this.#g),window.removeEventListener("touchstart",this.#g),window.removeEventListener("keydown",this.#g),this.#g=null)}#y(){this.#k();const e=()=>{this.#k(),this.#x()};this.#g=e,window.addEventListener("mousemove",e,{passive:!0}),window.addEventListener("touchstart",e,{passive:!0}),window.addEventListener("keydown",e,{passive:!0})}#_(){return"function"==typeof this.checkVisibility?this.checkVisibility({checkOpacity:!0,checkVisibilityCSS:!0}):!!(this.offsetParent||this.getClientRects().length>0)}#E(){this.#_()||s.info(r("challenges"),"solved invisible challenge")}#x(){"idle"===this.#d.state&&this.#_()&&(this.#d.state="waiting",this.#u=setTimeout(()=>{this.#C()},2500))}async#C(){if("waiting"!==this.#d.state)return;this.#d.state="fetching",this.#d._t0=performance.now();let e=this.getAttribute("data-cap-api-endpoint");if(!e&&window?.CAP_CUSTOM_FETCH&&(e="/"),e){e.endsWith("/")||(e+="/");try{const t=await o(`${e}challenge`,{method:"POST",signal:this.#b?.signal});let i;try{i=await t.json()}catch{throw new Error("Failed to parse speculative challenge response")}if(i.error)throw new Error(i.error);if(!this.#d)return;if(i._apiEndpoint=e,this.#d.challengeResp=i,2===i.format&&Array.isArray(i.challenges))return this.#d.state="idle",void this.#d.notify();const{challenge:s,token:r}=i;let n=s;if(!Array.isArray(n)){let e=0;n=Array.from({length:s.c},()=>(e++,[d(`${r}${e}`,s.s),d(`${r}${e}d`,s.d)]))}this.#d.challenges=n,this.#d.state="solving",this.#d.solvePromise=this.#A(n)}catch{if(!this.#d)return;this.#d.state="error",this.#d.notify()}}else this.#d.state="idle"}async#A(e){m();let t=null;try{t=await v()}catch{}this.#p||(this.#p=new f(1),this.#p._spawn()),this.#p.setWasm(t);const i=e.length,s=new Array(i);let r=1,n=!1;this.#d.promoteFn=e=>{n||(n=!0,r=e,this.#p._size=e,this.#p._ensureSize(e))},null!==this.#d.pendingPromotion&&(this.#d.promoteFn(this.#d.pendingPromotion),this.#d.pendingPromotion=null);let a=0;for(;a<i;){const t=r,o=[],l=[];for(let s=0;s<t&&a<i;s++)l.push(a),o.push(e[a]),a++;this.#p._ensureSize(Math.max(r,t));const c=await Promise.all(o.map(e=>this.#p.run(e[0],e[1]).then(e=>(this.#d&&this.#d.completedCount++,e))));for(let e=0;e<l.length;e++)s[l[e]]=c[e];!n&&a<i&&await new Promise(e=>setTimeout(e,120))}return this.#d?(this.#d.results=s,this.#d.state="redeeming",this.#S(s),s):s}async#S(e){try{if(!this.#d)return;const t=this.#d.challengeResp,i=t._apiEndpoint;if(!i)throw a("missing_endpoint","speculative redeem: missing apiEndpoint");let s=null;if(t.instrumentation){if(s=await p(t.instrumentation),!this.#d)return;if(s?.__timeout||s?.__blocked)return this.#d.state="done",void this.#d.notify()}const r=await o(`${i}redeem`,{method:"POST",body:JSON.stringify({token:t.token,solutions:e,...s&&{instr:s}}),headers:{"Content-Type":"application/json"},signal:this.#b?.signal});let l;try{l=await r.json()}catch{throw new Error("Failed to parse speculative redeem response")}if(!this.#d)return;if(!l.success)throw new Error(l.error||"Speculative redeem failed");this.#d.token=l.token,this.#d.tokenExpires=new Date(l.expires).getTime(),this.#d.state="done",this.#d._invisibleElapsed=this.#d._t0?n(this.#d._t0):"?",this.#d.notify()}catch{if(!this.#d)return;this.#d.state="done",this.#d.notify()}}get#T(){return this.getAttribute("data-cap-hidden-field-name")||"cap-token"}#L(e){const t=this.querySelector(`input[name='${this.#T}']`);t&&(t.value=e)}getI18nText(e,t){return this.getAttribute(`data-cap-i18n-${e}`)||this.#v?.[e]||t}#I(){s.debug(r("solve"),`served from speculative cache (saved ${this.#d._invisibleElapsed||"?"})`),this.dispatchEvent("progress",{progress:100}),this.#L(this.#d.token),this.dispatchEvent("solve",{token:this.#d.token}),this.token=this.#d.token;const e=this.#d.tokenExpires-Date.now();return this.#e&&clearTimeout(this.#e),this.#e=setTimeout(()=>this.reset(),e),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#m&&navigator.vibrate([10,50,20,30,40]),this.#E(),this.#w(),this.#l=!1,{success:!0,token:this.token}}#P(){this.#v=function(e){const t=e?[e]:navigator.languages||[navigator.language||""];for(let e of t){if(!e)continue;if(e=e.toLowerCase(),"en"===e||e.startsWith("en-"))return null;const t=h[e]?e:h[e.split("-")[0]]?e.split("-")[0]:null;if(!t)return null;const i=h[t].split("/"),s={};return c.forEach((e,t)=>{s[e]=i[t]}),s}return null}(window.CAP_LANG||this.getAttribute("data-cap-lang"))}static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","data-cap-worker-count","data-cap-i18n-initial-state","required"]}constructor(){super(),this.#c&&this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c=new Map,this.boundHandleProgress=this.handleProgress.bind(this),this.boundHandleSolve=this.handleSolve.bind(this),this.boundHandleError=this.handleError.bind(this),this.boundHandleReset=this.handleReset.bind(this);try{this.#h=this.attachInternals()}catch{}}#M(){this.#h?.setValidity&&(this.hasAttribute("required")&&!this.token?this.#h.setValidity({valueMissing:!0},this.getI18nText("required-label","Please verify you're human"),this.#s||this):this.#h.setValidity({}))}initialize(){m(),this.#b=new AbortController,this.#d||(this.#d=this.#f()),this.#p||(this.#p=new f(1),this.#p._spawn())}attributeChangedCallback(e,t,i){if(e.startsWith("on")){const t=e.slice(2),s=this.#c.get(e);if(s&&this.removeEventListener(t,s),i){const i=t=>{const i=this.getAttribute(e);"function"==typeof window[i]&&window[i].call(this,t)};this.#c.set(e,i),this.addEventListener(t,i)}}"data-cap-worker-count"===e&&this.setWorkersCount(parseInt(i,10)),"data-cap-i18n-initial-state"===e&&this.#s&&this.#s?.querySelector(".label.active")&&this.animateLabel(this.getI18nText("initial-state","Verify you're human")),"required"===e&&this.#M()}async connectedCallback(){this.#o=this,this.shadowRoot?this.#i=this.shadowRoot:this.#i=this.attachShadow({mode:"open"}),this.#s||(this.#s=document.createElement("div")),this.#P(),this.createUI(),this.addEventListeners(),this.initialize(),this.#r.removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count"),t=e?parseInt(e,10):null;this.setWorkersCount(t||navigator.hardwareConcurrency||8),this.#o.innerHTML=`<input type="hidden" name="${this.#T}">`,s.debug(r(),`widget ready (workers=${this.#t}, haptics=${this.#m})`),this.#y(),this.#M(),this.addEventListener("invalid",this.#H)}#H=()=>{if(this.#s){try{this.scrollIntoView({behavior:"smooth",block:"center"})}catch{this.scrollIntoView()}this.#s.classList.remove("invalid"),this.#s.offsetWidth,this.#s.classList.add("invalid"),setTimeout(()=>this.#s?.classList.remove("invalid"),1500)}};async solve(){if(this.#l)return;this.#$();const e=performance.now(),t=this.#b?.signal;s.debug(r("solve"),"starting");try{this.#l=!0,this.updateUI("verifying",this.getI18nText("verifying-label","Verifying..."),!0),this.#r.setAttribute("aria-label",this.getI18nText("verifying-aria-label","Verifying you're a human, please wait")),this.dispatchEvent("progress",{progress:0});try{let i,l,c=this.getAttribute("data-cap-api-endpoint");if(!c&&window?.CAP_CUSTOM_FETCH)c="/";else if(!c)throw a("missing_endpoint","Missing API endpoint. Either custom fetch or an API endpoint must be provided.");if(c.endsWith("/")||(c+="/"),"done"===this.#d.state&&this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires)return this.#I();if("done"===this.#d.state)i=this.#d.results,l=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100});else if("solving"===this.#d.state||"redeeming"===this.#d.state||"fetching"===this.#d.state||"waiting"===this.#d.state){"waiting"===this.#d.state&&(this.#u&&(clearTimeout(this.#u),this.#u=null),this.#d.state="waiting",this.#C()),this.#d.pendingPromotion=this.#t,this.#d.promoteFn&&this.#d.promoteFn(this.#t);const e=setInterval(()=>{if(t?.aborted||!this.#d)return void clearInterval(e);const i=this.#d.state;if("done"===i||"error"===i)return void clearInterval(e);const s=this.#d.challenges?this.#d.challenges.length:1,r=this.#d.completedCount,n="redeeming"===i?99:"fetching"===i||"waiting"===i?0:Math.min(98,Math.round(r/s*100));this.dispatchEvent("progress",{progress:n})},150);if(await new Promise(e=>this.#d.onSettled(e)),clearInterval(e),t?.aborted||!this.#d)return;if("idle"===this.#d.state&&2===this.#d.challengeResp?.format&&Array.isArray(this.#d.challengeResp.challenges))l=this.#d.challengeResp,this.#d.challengeResp=null,i=await this.solveChallengesV2(l.challenges,t);else{if("done"!==this.#d.state)throw a("solve_failed","Unable to solve challenge, self-hosted instance likely down. This is not an issue with Cap.");if(this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires)return this.#I();i=this.#d.results,l=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100})}}else{const e=this.#d.challengeResp;if(2===e?.format&&Array.isArray(e.challenges))l=e,this.#d.challengeResp=null;else{const e=await o(`${c}challenge`,{method:"POST",signal:t});try{l=await e.json()}catch{throw a("challenge_parse_error","Failed to parse challenge response from server")}if(l.error)throw a("network_error",l.error)}if(2===l.format&&Array.isArray(l.challenges))i=await this.solveChallengesV2(l.challenges,t);else{const{challenge:e,token:s}=l;let r=e;if(!Array.isArray(r)){let t=0;r=Array.from({length:e.c},()=>(t++,[d(`${s}${t}`,e.s),d(`${s}${t}d`,e.d)]))}i=await this.solveChallenges(r,t)}}const h=l.instrumentation?p(l.instrumentation):Promise.resolve(null),u=await h;if(t?.aborted||!this.#d)return;if(u?.__timeout||u?.__blocked){o(`${c}redeem`,{method:"POST",body:JSON.stringify({token:l.token,solutions:i,...u.__blocked&&{instr_blocked:!0},...u.__timeout&&{instr_timeout:!0}}),headers:{"Content-Type":"application/json"},signal:t}).catch(()=>{}),this.updateUIBlocked(this.getI18nText("error-label","Error"),u?.__blocked),this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again"));const e=u?.__blocked?"instr_blocked":"instr_timeout",n=u?.__blocked?`Instrumentation blocked (${u.blockReason||"automated_browser"})`:"Instrumentation timed out";this.removeEventListener("error",this.boundHandleError);const a=new CustomEvent("error",{bubbles:!0,composed:!0,detail:{isCap:!0,code:e,message:n}});return super.dispatchEvent(a),this.addEventListener("error",this.boundHandleError),this.executeAttributeCode("onerror",a),s.error(r("instr"),`[${e}] ${n}`),void(this.#l=!1)}const{token:g}=l,v=await o(`${c}redeem`,{method:"POST",body:JSON.stringify({token:g,solutions:i,...u&&{instr:u}}),headers:{"Content-Type":"application/json"},signal:t});let b;try{b=await v.json()}catch{throw a("redeem_failed","Failed to parse server response")}if(t?.aborted||!this.#d)return;if(this.dispatchEvent("progress",{progress:100}),!b.success)throw a("invalid_solution",b.error||"Invalid solution");this.#L(b.token),this.dispatchEvent("solve",{token:b.token}),this.token=b.token,this.#w(),this.#e&&clearTimeout(this.#e);const m=new Date(b.expires).getTime()-Date.now();return m>0&&m<864e5?this.#e=setTimeout(()=>this.reset(),m):this.error("Invalid expiration time","invalid_expires"),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#m&&navigator.vibrate([10,50,20,30,40]),s.debug(r("solve"),`verified in ${n(e)}`),this.#E(),{success:!0,token:this.token}}catch(e){if(t?.aborted||!this.#d)return;throw this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again")),this.error(e.message,e.code||"solve_failed"),e}}finally{this.#l=!1}}async solveChallengesV2(e,t){const i=e.length;let n=0;const o=new Array(e.length);for(let t=0;t<e.length;t++){const i=e[t];if(!i||"object"!=typeof i||"sha256-pow"!==i.protocol&&"rsw"!==i.protocol&&"instrumentation"!==i.protocol)throw a("challenge_unsupported",`unsupported format-2 protocol '${i?.protocol}'`)}let c=null;if("object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate)try{c=await v()}catch(e){s.warn(r("wasm"),"unavailable, falling back to JS solver:",e.message||e)}const h=Math.max(1,Math.min(this.#t,e.length)),d=new f(h);d.setWasm(c),d._ensureSize(h);const u=(e,t)=>Promise.race([e,new Promise((e,i)=>setTimeout(()=>i(new Error(`[cap] ${t} timed out after 60000ms`)),6e4))]),g=new Array(e.length).fill(0),b=()=>{const e=g.reduce((e,t)=>e+t,0)+n,t=Math.min(99,Math.round(e/i*100));this.dispatchEvent("progress",{progress:t})};try{await l(Promise.all(e.map((e,t)=>"sha256-pow"===e.protocol?u(d.run(e.payload.salt,e.payload.target),`sha256-pow worker #${t}`).then(e=>{o[t]={nonce:Number(e)},g[t]=0,n++,b()}):"rsw"===e.protocol?u(d.runMsg({kind:"rsw",N:e.payload.N,x:e.payload.x,t:0|e.payload.t},e=>{g[t]=e,b()}),`rsw worker #${t}`).then(e=>{o[t]={y:e.y},g[t]=0,n++,b()}):p(e.payload.blob).then(e=>{o[t]=e?.__timeout?{timeout:!0}:e?.__blocked?{blocked:!0}:{instr:e},g[t]=0,n++,b()}))),t)}finally{d.terminate()}return o}async solveChallenges(e,t){const i=e.length;let n=0;let a=null;const o="object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate;if(o)try{a=await v()}catch(e){s.warn(r("wasm"),"unavailable, falling back to JS solver:",e.message||e)}if(!o&&(s.warn(r("wasm"),"WebAssembly disabled in this browser, solver will be ~10x slower"),!this.#i.querySelector(".warning"))){const e=document.createElement("div");e.className="warning",e.style.cssText="width:var(--cap-widget-width,230px);background:rgb(237,56,46);color:white;padding:4px 6px;padding-bottom:calc(var(--cap-border-radius,14px) + 5px);font-size:10px;box-sizing:border-box;font-family:system-ui;border-top-left-radius:8px;border-top-right-radius:8px;text-align:center;user-select:none;margin-bottom:-35.5px;opacity:0;transition:margin-bottom .3s,opacity .3s;",e.innerText=this.getI18nText("wasm-disabled","Enable WASM for significantly faster solving"),this.#i.insertBefore(e,this.#i.firstChild),setTimeout(()=>{e.style.marginBottom="calc(-1 * var(--cap-border-radius, 14px))",e.style.opacity=1},10)}const c=new f(this.#t);c.setWasm(a),c._ensureSize(this.#t);const h=[];try{for(let s=0;s<e.length;s+=this.#t){const r=e.slice(s,Math.min(s+this.#t,e.length)),a=await l(Promise.all(r.map(([e,t])=>c.run(e,t).then(e=>{n++;const t=Math.min(99,Math.round((0+n)/i*100));return this.dispatchEvent("progress",{progress:t}),e}))),t);h.push(...a)}}finally{c.terminate()}return h}setWorkersCount(e){const t=parseInt(e,10),i=Math.min(navigator.hardwareConcurrency||8,16);this.#t=!Number.isNaN(t)&&t>0&&t<=i?t:navigator.hardwareConcurrency||8}createUI(){this.#s.classList.add("captcha"),this.#s.setAttribute("role","group"),this.#s.setAttribute("aria-label",this.getI18nText("group-aria-label","Cap verification")),this.#r=document.createElement("div"),this.#r.className="captcha-trigger",this.#r.setAttribute("part","trigger"),this.#r.setAttribute("role","button"),this.#r.setAttribute("tabindex","0"),this.#r.setAttribute("aria-label",this.getI18nText("verify-aria-label","Click to verify you're a human")),this.#r.setAttribute("aria-live","polite"),this.#r.setAttribute("disabled","true"),this.#r.innerHTML=`<div class="checkbox" part="checkbox" aria-hidden="true"><svg class="progress-ring" viewBox="0 0 32 32" aria-hidden="true"><circle class="progress-ring-bg" cx="16" cy="16" r="14"></circle><circle class="progress-ring-circle" cx="16" cy="16" r="14"></circle></svg></div><p part="label" class="label-wrapper"><span class="label active">${this.getI18nText("initial-state","Verify you're human")}</span></p>`,this.#s.appendChild(this.#r),this.#a=document.createElement("a"),this.#a.className="cap-troubleshoot-link",this.#a.setAttribute("part","troubleshoot"),this.#a.setAttribute("target","_blank"),this.#a.setAttribute("rel","noopener"),this.#a.hidden=!0,this.#s.appendChild(this.#a),this.#n=document.createElement("a"),this.#n.className="credits",this.#n.setAttribute("aria-label","Secured by Cap"),this.#n.setAttribute("href","https://trycap.dev"),this.#n.setAttribute("target","_blank"),this.#n.setAttribute("title","Secured by Cap: The self-hosted CAPTCHA for the modern web."),this.#n.textContent="Cap",this.#s.appendChild(this.#n),this.#i.innerHTML=`<style${window.CAP_CSS_NONCE?` nonce=${window.CAP_CSS_NONCE}`:""}>:host{display:inline-block}@media (prefers-reduced-motion:reduce){.captcha,.captcha *{transition:none!important;animation:none!important}.label{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}.label:not(.active),.label.exit{display:none!important}}.captcha,.captcha *{box-sizing:border-box}.captcha{width:var(--cap-widget-width,260px);height:var(--cap-widget-height,58px);background-color:var(--cap-background,#fdfdfd);border:1px solid var(--cap-border-color,#dddddd8f);border-radius:var(--cap-border-radius,14px);-webkit-user-select:none;user-select:none;cursor:pointer;-webkit-tap-highlight-color:#fff0;color:var(--cap-color,#212121);font-family:var(--cap-font,system, -apple-system, "BlinkMacSystemFont", ".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif);transition:filter .2s,transform .2s,height .2s;display:inline-block;position:relative;overflow:hidden}.captcha.has-troubleshoot{height:calc(var(--cap-widget-height,58px) + 26px)}.captcha.has-troubleshoot .captcha-trigger{inset-block-end:26px}.captcha:not([data-state]):active{transform:scale(.97)}.captcha:hover{filter:brightness(98%)}.captcha-trigger{padding:var(--cap-widget-padding,14px);align-items:center;gap:var(--cap-gap,15px);border-radius:inherit;transition:inset .2s;display:flex;position:absolute;inset:0}.captcha-trigger:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:-3px}.checkbox{width:var(--cap-checkbox-size,25px);height:var(--cap-checkbox-size,25px);border:var(--cap-checkbox-border,1px solid #aaaaaad1);border-radius:var(--cap-checkbox-border-radius,6px);background-color:var(--cap-checkbox-background,#fafafa91);margin-top:var(--cap-checkbox-margin,2px);margin-bottom:var(--cap-checkbox-margin,2px);flex-shrink:0;transition:opacity .2s}.captcha p{-webkit-user-select:none;user-select:none;margin:0;font-size:15px;font-weight:500}.label-wrapper{flex:1;align-items:center;min-width:0;height:2em;display:flex;position:relative;overflow:hidden}.label-wrapper:before,.label-wrapper:after{content:"";pointer-events:none;z-index:1;width:100%;height:.6em;position:absolute;inset-inline-start:0}.label-wrapper:before{background:linear-gradient(to bottom, var(--cap-background,#fdfdfd), transparent);top:0}.label-wrapper:after{background:linear-gradient(to top, var(--cap-background,#fdfdfd), transparent);bottom:0}.label{white-space:nowrap;opacity:0;filter:blur(2px);transition:transform .5s cubic-bezier(.25,1,.5,1),opacity .5s,filter .5s;position:absolute;transform:translateY(100%)}.label.active{opacity:1;filter:none;transform:translateY(0)}.label.exit{opacity:0;filter:blur(2px);transform:translateY(-100%)}.checkbox .progress-ring{width:100%;height:100%;display:none;transform:rotate(-90deg)}.checkbox .progress-ring-bg{fill:none;stroke:var(--cap-spinner-background-color,#eee);stroke-width:var(--cap-spinner-thickness,3)}.checkbox .progress-ring-circle{fill:none;stroke:var(--cap-spinner-color,#000);stroke-width:var(--cap-spinner-thickness,3);stroke-linecap:round;stroke-dasharray:87.96;stroke-dashoffset:87.96px;transition:stroke-dashoffset .3s}.captcha[data-state=verifying] .checkbox{background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;display:flex;transform:scale(1.1)}.captcha[data-state=verifying] .checkbox .progress-ring{display:block}.captcha[data-state=done] .checkbox{background-image:var(--cap-checkmark,url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E));background-size:cover;border:1px solid #0000}.captcha[data-state=done] .checkbox .progress-ring{display:none}.captcha[data-state=error] .checkbox{background-image:var(--cap-error-cross,url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 24 24'%3E%3Cpath fill='%23f55b50' d='M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8'/%3E%3C%2Fsvg%3E"));background-size:cover;border:1px solid #0000}.captcha[data-state=error] .checkbox .progress-ring{display:none}.captcha.invalid{border-color:var(--cap-invalid-border-color,#f55b50);box-shadow:0 0 0 3px var(--cap-invalid-ring-color,#f55b5033);animation:.5s cubic-bezier(.36,.07,.19,.97) cap-shake}@keyframes cap-shake{10%,90%{transform:translate(-1px)}20%,80%{transform:translate(2px)}30%,50%,70%{transform:translate(-4px)}40%,60%{transform:translate(4px)}}@media (prefers-reduced-motion:reduce){.captcha.invalid{animation:none!important}}.captcha-trigger[disabled]{cursor:not-allowed}.captcha[data-state=verifying] .captcha-trigger{cursor:progress}.captcha[data-state=done] .captcha-trigger{cursor:default}.credits{color:var(--cap-color,#212121);text-underline-offset:.18em;z-index:2;border-radius:4px;justify-content:flex-end;align-items:center;min-width:24px;min-height:24px;padding:4px 6px;text-decoration:underline;text-decoration-thickness:.08em;position:absolute;inset-block-end:4px;inset-inline-end:4px;opacity:.8!important;font-size:12px!important;display:inline-flex!important}.captcha .credits{visibility:visible!important;pointer-events:all!important;display:inline-flex!important}.credits:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px;opacity:1!important}.cap-troubleshoot-link{min-width:24px;min-height:24px;color:var(--cap-troubleshoot-color,#0050a0);text-underline-offset:.15em;cursor:pointer;z-index:2;border-radius:4px;align-items:center;padding:4px 6px;font-size:13px;font-weight:500;text-decoration:underline;text-decoration-thickness:.08em;display:inline-flex;position:absolute;inset-block-end:4px;inset-inline-start:14px}.cap-troubleshoot-link[hidden]{display:none}.cap-troubleshoot-link:hover{opacity:.85}.cap-troubleshoot-link:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px}@media (forced-colors:active){.captcha,.checkbox{border-color:canvastext}:is(.captcha-trigger:focus-visible,.credits:focus-visible,.cap-troubleshoot-link:focus-visible){outline-color:highlight}.progress-ring-bg{stroke:graytext}.progress-ring-circle{stroke:canvastext}.captcha.invalid{box-shadow:none;border-color:mark}.credits{opacity:1!important}}</style>`,this.#i.appendChild(this.#s),this.#$(),setTimeout(()=>this.#$(),100)}addEventListeners(){this.#r&&(this.#n.addEventListener("click",e=>{e.preventDefault(),window.open(`https://trycap.dev/?${new URLSearchParams({utm_source:"cap_widget",utm_medium:"referral",utm_campaign:"widget",utm_content:window.CAP_DISABLE_WIDGET_REF?"":location.hostname,ref:window.CAP_DISABLE_WIDGET_REF?"":location.href||"",sub:window.CAP_DISABLE_WIDGET_REF?"":document.referrer||""}).toString()}`,"_blank")}),this.#r.addEventListener("click",()=>{this.#r.hasAttribute("disabled")||this.solve()}),this.#r.addEventListener("mousedown",()=>{!this.#r.hasAttribute("disabled")&&this.#m&&navigator.vibrate(5)}),this.#r.addEventListener("keydown",e=>{e.target===this.#r&&("Enter"!==e.key&&" "!==e.key||this.#r.hasAttribute("disabled")||(e.preventDefault(),e.stopPropagation(),this.solve()))}),this.addEventListener("progress",this.boundHandleProgress),this.addEventListener("solve",this.boundHandleSolve),this.addEventListener("error",this.boundHandleError),this.addEventListener("reset",this.boundHandleReset))}#N(){if(!this.#o)return!1;const e=this.#o.getBoundingClientRect();if(0===e.width&&0===e.height)return!0;const t=window.getComputedStyle(this.#o);return"none"===t.display||"hidden"===t.visibility}#$(){this.#n&&this.#s&&!this.#N()&&(this.#n.isConnected&&this.#n.parentNode===this.#s||this.#s.appendChild(this.#n),this.#n.textContent&&this.#n.textContent.trim()||(this.#n.textContent="Cap"),"https://trycap.dev"!==this.#n.getAttribute("href")&&this.#n.setAttribute("href","https://trycap.dev"),this.#n.style.cssText=["display: inline-flex !important","visibility: visible !important","opacity: 0.8 !important","pointer-events: all !important","font-size: 12px !important","transform: none !important","clip-path: none !important","filter: none !important","position: absolute !important"].join("; "))}animateLabel(e){if(!this.#r)return;const t=this.#r.querySelector(".label-wrapper");if(!t)return;if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches){const i=t.querySelector(".label.active");if(i)i.textContent=e;else{const i=document.createElement("span");i.className="label active",i.textContent=e,t.appendChild(i)}return}const i=t.querySelector(".label.active"),s=document.createElement("span");s.className="label",s.textContent=e,t.appendChild(s),s.offsetWidth,s.classList.add("active"),i&&(i.classList.remove("active"),i.classList.add("exit"),i.addEventListener("transitionend",()=>i.remove(),{once:!0}))}updateUI(e,t,i=!1){this.#s&&this.#r&&(this.#s.setAttribute("data-state",e),this.#s.classList.remove("has-troubleshoot"),this.animateLabel(t),this.#a&&(this.#a.hidden=!0),i?this.#r.setAttribute("disabled","true"):this.#r.removeAttribute("disabled"))}updateUIBlocked(e,t=!1){if(this.#s&&this.#r&&(this.#s.setAttribute("data-state","error"),this.#r.removeAttribute("disabled"),this.animateLabel(e),this.#a))if(t){const e=this.getAttribute("data-cap-troubleshooting-url")||"https://trycap.dev/guide/troubleshooting/instrumentation.html";this.#a.setAttribute("href",e),this.#a.textContent=this.getI18nText("troubleshooting-label","Troubleshoot"),this.#a.hidden=!1,this.#s.classList.add("has-troubleshoot")}else this.#a.hidden=!0,this.#s.classList.remove("has-troubleshoot")}handleProgress(e){if(!this.#r)return;const t=this.#r.querySelector(".progress-ring-circle");if(t){const i=2*Math.PI*14,s=i-e.detail.progress/100*i;t.style.strokeDashoffset=s}const i=this.#r.querySelector(".label-wrapper");if(i){const e=i.querySelector(".label.active");e&&(e.textContent=`${this.getI18nText("verifying-label","Verifying...")}`)}this.executeAttributeCode("onprogress",e)}handleSolve(e){this.updateUI("done",this.getI18nText("solved-label","You're a human"),!0),this.executeAttributeCode("onsolve",e),this.#h?.setValidity?.({}),this.#s?.classList.remove("invalid")}handleError(e){this.updateUI("error",this.getI18nText("error-label","Error. Try again.")),this.executeAttributeCode("onerror",e),this.#m&&navigator.vibrate([10,40,10])}handleReset(e){this.updateUI("",this.getI18nText("initial-state","I'm a human")),this.executeAttributeCode("onreset",e),this.#M()}executeAttributeCode(e,t){const i=this.getAttribute(e);i&&(s.warn(r(),"inline `onxxx='…'` handlers are deprecated. use `addEventListener` callbacks instead."),new Function("event",i).call(this,t))}error(e="Unknown error",t="unknown"){s.error(r("solve"),`[${t}] ${e}`),this.dispatchEvent("error",{isCap:!0,code:t,message:e})}dispatchEvent(e,t={}){const i=new CustomEvent(e,{bubbles:!0,composed:!0,detail:t});super.dispatchEvent(i)}reset(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.token=null,this.dispatchEvent("reset"),this.#L("")}get tokenValue(){return this.token}disconnectedCallback(){this.#b?.abort(),this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c.clear(),this.#i&&(this.#i.innerHTML=""),this.reset(),this.cleanup()}cleanup(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.#k(),this.#u&&(clearTimeout(this.#u),this.#u=null),this.#p&&(this.#p.terminate(),this.#p=null),this.#d&&(this.#d.state="error",this.#d.notify(),this.#d=null)}}class y{constructor(e={},t){const i=t||document.createElement("cap-widget");if(Object.entries(e).forEach(([e,t])=>{i.setAttribute(e,t)}),!e.apiEndpoint&&!window?.CAP_CUSTOM_FETCH)throw i.remove(),new Error("Missing API endpoint. Either custom fetch or an API endpoint must be provided.");e.apiEndpoint&&i.setAttribute("data-cap-api-endpoint",e.apiEndpoint),t||i.hasAttribute("data-cap-disable-haptics")||i.setAttribute("data-cap-disable-haptics",""),this.widget=i,this.solve=this.widget.solve.bind(this.widget),this.reset=this.widget.reset.bind(this.widget),this.addEventListener=this.widget.addEventListener.bind(this.widget),Object.defineProperty(this,"token",{get:()=>i.token,configurable:!0,enumerable:!0}),t||(i.style.display="none",document.documentElement.appendChild(i))}}window.Cap=y,customElements.get("cap-widget")||window?.CAP_DONT_SKIP_REDEFINE?customElements.get("cap-widget")&&s.warn(r(),"cap-widget custom element already defined, skipping re-define. set window.CAP_DONT_SKIP_REDEFINE = true to override"):customElements.define("cap-widget",w),"object"==typeof exports&&"undefined"!=typeof module?module.exports=y:"function"==typeof define&&define.amd&&define([],()=>y),"undefined"!=typeof exports&&(exports.default=y)})();
|
package/package.json
CHANGED
package/src/cap.js
CHANGED
|
@@ -8,6 +8,31 @@
|
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
const _ctp = ["#f5c2e7","#cba6f7","#f38ba8","#fab387","#f9e2af","#a6e3a1","#94e2d5","#89dceb","#b4befe"];
|
|
12
|
+
const _bg = (s) => {
|
|
13
|
+
if (s === "cap") return "#89b4fa";
|
|
14
|
+
let h = 0;
|
|
15
|
+
for (let i = 0; i < s.length; i++) h = s.charCodeAt(i) + ((h << 5) - h);
|
|
16
|
+
return _ctp[Math.abs(h) % _ctp.length];
|
|
17
|
+
};
|
|
18
|
+
const _style = (t, i, n) => {
|
|
19
|
+
const l = i === 0 ? "9999px" : "0";
|
|
20
|
+
const r = i === n - 1 ? "9999px" : "0";
|
|
21
|
+
return `color:#1e1e2e;background:${_bg(t)};margin-left:${i ? "-6px" : 0};padding:0 6px;border-radius:${l} ${r} ${r} ${l};font-weight:600`;
|
|
22
|
+
};
|
|
23
|
+
const log = {};
|
|
24
|
+
for (const lvl of ["debug", "info", "warn", "error"]) {
|
|
25
|
+
log[lvl] = (tags, ...args) => {
|
|
26
|
+
if (window.CAP_SILENT || (lvl === "debug" && !window.CAP_DEBUG)) return;
|
|
27
|
+
const fmt = tags.map((t) => `%c${t}`).join(" ");
|
|
28
|
+
const styles = tags.map((t, i) => _style(t, i, tags.length));
|
|
29
|
+
console[lvl === "debug" ? "log" : lvl](fmt, ...styles, ...args);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const T = (sub) => (sub ? ["cap", sub] : ["cap"]);
|
|
33
|
+
const since = (t) => `${Math.round(performance.now() - t)}ms`;
|
|
34
|
+
const _err = (code, message) => Object.assign(new Error(message), { code });
|
|
35
|
+
|
|
11
36
|
const capFetch = (u, conf = {}) => {
|
|
12
37
|
if (window?.CAP_CUSTOM_FETCH) {
|
|
13
38
|
return window.CAP_CUSTOM_FETCH(u, conf);
|
|
@@ -16,6 +41,48 @@
|
|
|
16
41
|
return fetch(u, conf);
|
|
17
42
|
};
|
|
18
43
|
|
|
44
|
+
const raceAbort = (promise, signal) => {
|
|
45
|
+
if (!signal) return promise;
|
|
46
|
+
if (signal.aborted) return Promise.reject(_err("aborted", "aborted"));
|
|
47
|
+
return Promise.race([
|
|
48
|
+
promise,
|
|
49
|
+
new Promise((_, reject) =>
|
|
50
|
+
signal.addEventListener(
|
|
51
|
+
"abort",
|
|
52
|
+
() => reject(_err("aborted", "aborted")),
|
|
53
|
+
{ once: true },
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
]);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const I18N_KEYS = "%%i18nKeys%%".split(",");
|
|
60
|
+
const I18N_ROWS = %%i18nData%%;
|
|
61
|
+
|
|
62
|
+
function _resolveI18nMap(forced) {
|
|
63
|
+
const prefs = forced
|
|
64
|
+
? [forced]
|
|
65
|
+
: navigator.languages || [navigator.language || ""];
|
|
66
|
+
for (let pref of prefs) {
|
|
67
|
+
if (!pref) continue;
|
|
68
|
+
pref = pref.toLowerCase();
|
|
69
|
+
if (pref === "en" || pref.startsWith("en-")) return null;
|
|
70
|
+
const code = I18N_ROWS[pref]
|
|
71
|
+
? pref
|
|
72
|
+
: I18N_ROWS[pref.split("-")[0]]
|
|
73
|
+
? pref.split("-")[0]
|
|
74
|
+
: null;
|
|
75
|
+
if (!code) return null;
|
|
76
|
+
const parts = I18N_ROWS[code].split("/");
|
|
77
|
+
const map = {};
|
|
78
|
+
I18N_KEYS.forEach((k, i) => {
|
|
79
|
+
map[k] = parts[i];
|
|
80
|
+
});
|
|
81
|
+
return map;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
19
86
|
function prng(seed, length) {
|
|
20
87
|
function fnv1a(str) {
|
|
21
88
|
let hash = 2166136261;
|
|
@@ -78,17 +145,18 @@
|
|
|
78
145
|
const url =
|
|
79
146
|
window.CAP_PAKO_URL ||
|
|
80
147
|
"https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako_inflate.min.js";
|
|
148
|
+
log.debug(T("instr"), "DecompressionStream unavailable, loading pako from", url);
|
|
81
149
|
const script = document.createElement("script");
|
|
82
150
|
script.src = url;
|
|
83
151
|
const pakoNonce = window.CAP_SCRIPT_NONCE || window.CAP_CSS_NONCE;
|
|
84
152
|
if (pakoNonce) script.setAttribute("nonce", pakoNonce);
|
|
85
153
|
script.onload = () => {
|
|
86
154
|
if (window.pako?.inflateRaw) resolve(window.pako);
|
|
87
|
-
else reject(new Error("
|
|
155
|
+
else reject(new Error("pako loaded but inflateRaw is missing"));
|
|
88
156
|
};
|
|
89
157
|
script.onerror = () => {
|
|
90
158
|
_pakoPromise = null;
|
|
91
|
-
reject(new Error(`
|
|
159
|
+
reject(new Error(`failed to load pako fallback from ${url}`));
|
|
92
160
|
};
|
|
93
161
|
document.head.appendChild(script);
|
|
94
162
|
});
|
|
@@ -178,14 +246,21 @@
|
|
|
178
246
|
window.CAP_CUSTOM_WASM_URL ||
|
|
179
247
|
`https://cdn.jsdelivr.net/npm/@cap.js/wasm@${WASM_VERSION}/browser/cap_wasm_bg.wasm`;
|
|
180
248
|
|
|
249
|
+
const t0 = performance.now();
|
|
250
|
+
log.debug(T("wasm"), "fetching", wasmUrl);
|
|
181
251
|
wasmModulePromise = fetch(wasmUrl)
|
|
182
252
|
.then((r) => {
|
|
183
253
|
if (!r.ok) throw new Error(`Failed to fetch wasm: ${r.status}`);
|
|
184
254
|
return r.arrayBuffer();
|
|
185
255
|
})
|
|
186
256
|
.then((buf) => WebAssembly.compile(buf))
|
|
257
|
+
.then((mod) => {
|
|
258
|
+
log.debug(T("wasm"), `ready in ${since(t0)}`);
|
|
259
|
+
return mod;
|
|
260
|
+
})
|
|
187
261
|
.catch((e) => {
|
|
188
262
|
wasmModulePromise = null;
|
|
263
|
+
log.warn(T("wasm"), `load failed (${since(t0)}):`, e.message || e);
|
|
189
264
|
throw e;
|
|
190
265
|
});
|
|
191
266
|
|
|
@@ -251,8 +326,9 @@
|
|
|
251
326
|
} catch {}
|
|
252
327
|
|
|
253
328
|
this._spawnFailures++;
|
|
329
|
+
log.warn(T("pool"), `worker died, replacing (attempt ${this._spawnFailures}/3)`);
|
|
254
330
|
if (this._spawnFailures > 3) {
|
|
255
|
-
|
|
331
|
+
log.error(T("pool"), "worker spawn failed repeatedly, giving up");
|
|
256
332
|
return null;
|
|
257
333
|
}
|
|
258
334
|
|
|
@@ -367,6 +443,8 @@
|
|
|
367
443
|
#speculativeTimer = null;
|
|
368
444
|
#speculativePool = null;
|
|
369
445
|
#interactionHandler = null;
|
|
446
|
+
#i18n = null;
|
|
447
|
+
#abort = null;
|
|
370
448
|
|
|
371
449
|
get #hasHaptics() {
|
|
372
450
|
return (
|
|
@@ -438,10 +516,13 @@
|
|
|
438
516
|
checkVisibilityCSS: true,
|
|
439
517
|
});
|
|
440
518
|
}
|
|
441
|
-
// Fallback: offsetParent is null for display:none; also check the style directly
|
|
442
519
|
return !!(this.offsetParent || this.getClientRects().length > 0);
|
|
443
520
|
}
|
|
444
521
|
|
|
522
|
+
#logInvisible() {
|
|
523
|
+
if (!this.#isVisible()) log.info(T("challenges"), "solved invisible challenge");
|
|
524
|
+
}
|
|
525
|
+
|
|
445
526
|
#onFirstInteraction() {
|
|
446
527
|
if (this.#speculative.state !== "idle") return;
|
|
447
528
|
if (!this.#isVisible()) return;
|
|
@@ -454,6 +535,7 @@
|
|
|
454
535
|
async #beginSpeculativeSolve() {
|
|
455
536
|
if (this.#speculative.state !== "waiting") return;
|
|
456
537
|
this.#speculative.state = "fetching";
|
|
538
|
+
this.#speculative._t0 = performance.now();
|
|
457
539
|
|
|
458
540
|
let apiEndpoint = this.getAttribute("data-cap-api-endpoint");
|
|
459
541
|
if (!apiEndpoint && window?.CAP_CUSTOM_FETCH) {
|
|
@@ -468,6 +550,7 @@
|
|
|
468
550
|
try {
|
|
469
551
|
const raw = await capFetch(`${apiEndpoint}challenge`, {
|
|
470
552
|
method: "POST",
|
|
553
|
+
signal: this.#abort?.signal,
|
|
471
554
|
});
|
|
472
555
|
let resp;
|
|
473
556
|
try {
|
|
@@ -476,6 +559,7 @@
|
|
|
476
559
|
throw new Error("Failed to parse speculative challenge response");
|
|
477
560
|
}
|
|
478
561
|
if (resp.error) throw new Error(resp.error);
|
|
562
|
+
if (!this.#speculative) return;
|
|
479
563
|
|
|
480
564
|
resp._apiEndpoint = apiEndpoint;
|
|
481
565
|
this.#speculative.challengeResp = resp;
|
|
@@ -502,8 +586,8 @@
|
|
|
502
586
|
this.#speculative.state = "solving";
|
|
503
587
|
|
|
504
588
|
this.#speculative.solvePromise = this.#speculativeSolveAll(challenges);
|
|
505
|
-
} catch
|
|
506
|
-
|
|
589
|
+
} catch {
|
|
590
|
+
if (!this.#speculative) return;
|
|
507
591
|
this.#speculative.state = "error";
|
|
508
592
|
this.#speculative.notify();
|
|
509
593
|
}
|
|
@@ -562,7 +646,7 @@
|
|
|
562
646
|
this.#speculativePool
|
|
563
647
|
.run(challenge[0], challenge[1])
|
|
564
648
|
.then((nonce) => {
|
|
565
|
-
this.#speculative.completedCount++;
|
|
649
|
+
if (this.#speculative) this.#speculative.completedCount++;
|
|
566
650
|
return nonce;
|
|
567
651
|
}),
|
|
568
652
|
),
|
|
@@ -579,6 +663,7 @@
|
|
|
579
663
|
}
|
|
580
664
|
}
|
|
581
665
|
|
|
666
|
+
if (!this.#speculative) return results;
|
|
582
667
|
this.#speculative.results = results;
|
|
583
668
|
this.#speculative.state = "redeeming";
|
|
584
669
|
this.#speculativeRedeem(results);
|
|
@@ -587,16 +672,18 @@
|
|
|
587
672
|
|
|
588
673
|
async #speculativeRedeem(solutions) {
|
|
589
674
|
try {
|
|
675
|
+
if (!this.#speculative) return;
|
|
590
676
|
const challengeResp = this.#speculative.challengeResp;
|
|
591
677
|
const apiEndpoint = challengeResp._apiEndpoint;
|
|
592
678
|
if (!apiEndpoint)
|
|
593
|
-
throw
|
|
679
|
+
throw _err("missing_endpoint", "speculative redeem: missing apiEndpoint");
|
|
594
680
|
|
|
595
681
|
let instrOut = null;
|
|
596
682
|
if (challengeResp.instrumentation) {
|
|
597
683
|
instrOut = await runInstrumentationChallenge(
|
|
598
684
|
challengeResp.instrumentation,
|
|
599
685
|
);
|
|
686
|
+
if (!this.#speculative) return;
|
|
600
687
|
if (instrOut?.__timeout || instrOut?.__blocked) {
|
|
601
688
|
this.#speculative.state = "done";
|
|
602
689
|
this.#speculative.notify();
|
|
@@ -612,6 +699,7 @@
|
|
|
612
699
|
...(instrOut && { instr: instrOut }),
|
|
613
700
|
}),
|
|
614
701
|
headers: { "Content-Type": "application/json" },
|
|
702
|
+
signal: this.#abort?.signal,
|
|
615
703
|
});
|
|
616
704
|
|
|
617
705
|
let resp;
|
|
@@ -621,25 +709,71 @@
|
|
|
621
709
|
throw new Error("Failed to parse speculative redeem response");
|
|
622
710
|
}
|
|
623
711
|
|
|
712
|
+
if (!this.#speculative) return;
|
|
624
713
|
if (!resp.success)
|
|
625
714
|
throw new Error(resp.error || "Speculative redeem failed");
|
|
626
715
|
|
|
627
716
|
this.#speculative.token = resp.token;
|
|
628
717
|
this.#speculative.tokenExpires = new Date(resp.expires).getTime();
|
|
629
718
|
this.#speculative.state = "done";
|
|
719
|
+
this.#speculative._invisibleElapsed = this.#speculative._t0 ? since(this.#speculative._t0) : "?";
|
|
630
720
|
this.#speculative.notify();
|
|
631
|
-
} catch
|
|
632
|
-
|
|
633
|
-
"[cap] speculative redeem failed (will redo on click):",
|
|
634
|
-
e,
|
|
635
|
-
);
|
|
721
|
+
} catch {
|
|
722
|
+
if (!this.#speculative) return;
|
|
636
723
|
this.#speculative.state = "done";
|
|
637
724
|
this.#speculative.notify();
|
|
638
725
|
}
|
|
639
726
|
}
|
|
640
727
|
|
|
728
|
+
get #fieldName() {
|
|
729
|
+
return this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
#setToken(value) {
|
|
733
|
+
const input = this.querySelector(`input[name='${this.#fieldName}']`);
|
|
734
|
+
if (input) input.value = value;
|
|
735
|
+
}
|
|
736
|
+
|
|
641
737
|
getI18nText(key, defaultValue) {
|
|
642
|
-
return
|
|
738
|
+
return (
|
|
739
|
+
this.getAttribute(`data-cap-i18n-${key}`) ||
|
|
740
|
+
this.#i18n?.[key] ||
|
|
741
|
+
defaultValue
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
#commitSpeculativeToken() {
|
|
746
|
+
log.debug(T("solve"), `served from speculative cache (saved ${this.#speculative._invisibleElapsed || "?"})`);
|
|
747
|
+
this.dispatchEvent("progress", { progress: 100 });
|
|
748
|
+
|
|
749
|
+
this.#setToken(this.#speculative.token);
|
|
750
|
+
|
|
751
|
+
this.dispatchEvent("solve", { token: this.#speculative.token });
|
|
752
|
+
this.token = this.#speculative.token;
|
|
753
|
+
|
|
754
|
+
const expiresIn = this.#speculative.tokenExpires - Date.now();
|
|
755
|
+
if (this.#resetTimer) clearTimeout(this.#resetTimer);
|
|
756
|
+
this.#resetTimer = setTimeout(() => this.reset(), expiresIn);
|
|
757
|
+
|
|
758
|
+
this.#trigger.setAttribute(
|
|
759
|
+
"aria-label",
|
|
760
|
+
this.getI18nText(
|
|
761
|
+
"verified-aria-label",
|
|
762
|
+
"We have verified you're a human, you may now continue",
|
|
763
|
+
),
|
|
764
|
+
);
|
|
765
|
+
if (this.#hasHaptics) navigator.vibrate([10, 50, 20, 30, 40]);
|
|
766
|
+
|
|
767
|
+
this.#logInvisible();
|
|
768
|
+
this.#resetSpeculativeState();
|
|
769
|
+
this.#solving = false;
|
|
770
|
+
return { success: true, token: this.token };
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
#resolveI18n() {
|
|
774
|
+
this.#i18n = _resolveI18nMap(
|
|
775
|
+
window.CAP_LANG || this.getAttribute("data-cap-lang"),
|
|
776
|
+
);
|
|
643
777
|
}
|
|
644
778
|
|
|
645
779
|
static get observedAttributes() {
|
|
@@ -688,6 +822,7 @@
|
|
|
688
822
|
|
|
689
823
|
initialize() {
|
|
690
824
|
_getSharedWorkerUrl();
|
|
825
|
+
this.#abort = new AbortController();
|
|
691
826
|
if (!this.#speculative) {
|
|
692
827
|
this.#speculative = this.#makeSpeculativeState();
|
|
693
828
|
}
|
|
@@ -746,6 +881,7 @@
|
|
|
746
881
|
}
|
|
747
882
|
|
|
748
883
|
if (!this.#div) this.#div = document.createElement("div");
|
|
884
|
+
this.#resolveI18n();
|
|
749
885
|
this.createUI();
|
|
750
886
|
this.addEventListeners();
|
|
751
887
|
this.initialize();
|
|
@@ -754,10 +890,9 @@
|
|
|
754
890
|
const workers = this.getAttribute("data-cap-worker-count");
|
|
755
891
|
const parsedWorkers = workers ? parseInt(workers, 10) : null;
|
|
756
892
|
this.setWorkersCount(parsedWorkers || navigator.hardwareConcurrency || 8);
|
|
757
|
-
|
|
758
|
-
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
759
|
-
this.#host.innerHTML = `<input type="hidden" name="${fieldName}">`;
|
|
893
|
+
this.#host.innerHTML = `<input type="hidden" name="${this.#fieldName}">`;
|
|
760
894
|
|
|
895
|
+
log.debug(T(), `widget ready (workers=${this.#workersCount}, haptics=${this.#hasHaptics})`);
|
|
761
896
|
this.#attachInteractionListeners();
|
|
762
897
|
this.#updateValidity();
|
|
763
898
|
|
|
@@ -783,6 +918,9 @@
|
|
|
783
918
|
}
|
|
784
919
|
|
|
785
920
|
this.#enforceCredits();
|
|
921
|
+
const _solveT0 = performance.now();
|
|
922
|
+
const signal = this.#abort?.signal;
|
|
923
|
+
log.debug(T("solve"), "starting");
|
|
786
924
|
|
|
787
925
|
try {
|
|
788
926
|
this.#solving = true;
|
|
@@ -805,7 +943,8 @@
|
|
|
805
943
|
if (!apiEndpoint && window?.CAP_CUSTOM_FETCH) {
|
|
806
944
|
apiEndpoint = "/";
|
|
807
945
|
} else if (!apiEndpoint) {
|
|
808
|
-
throw
|
|
946
|
+
throw _err(
|
|
947
|
+
"missing_endpoint",
|
|
809
948
|
"Missing API endpoint. Either custom fetch or an API endpoint must be provided.",
|
|
810
949
|
);
|
|
811
950
|
}
|
|
@@ -820,33 +959,7 @@
|
|
|
820
959
|
this.#speculative.tokenExpires &&
|
|
821
960
|
Date.now() < this.#speculative.tokenExpires
|
|
822
961
|
) {
|
|
823
|
-
this
|
|
824
|
-
|
|
825
|
-
const fieldName =
|
|
826
|
-
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
827
|
-
if (this.querySelector(`input[name='${fieldName}']`)) {
|
|
828
|
-
this.querySelector(`input[name='${fieldName}']`).value =
|
|
829
|
-
this.#speculative.token;
|
|
830
|
-
}
|
|
831
|
-
this.dispatchEvent("solve", { token: this.#speculative.token });
|
|
832
|
-
this.token = this.#speculative.token;
|
|
833
|
-
|
|
834
|
-
const expiresIn = this.#speculative.tokenExpires - Date.now();
|
|
835
|
-
if (this.#resetTimer) clearTimeout(this.#resetTimer);
|
|
836
|
-
this.#resetTimer = setTimeout(() => this.reset(), expiresIn);
|
|
837
|
-
|
|
838
|
-
this.#trigger.setAttribute(
|
|
839
|
-
"aria-label",
|
|
840
|
-
this.getI18nText(
|
|
841
|
-
"verified-aria-label",
|
|
842
|
-
"We have verified you're a human, you may now continue",
|
|
843
|
-
),
|
|
844
|
-
);
|
|
845
|
-
if (this.#hasHaptics) navigator.vibrate([10, 50, 20, 30, 40]);
|
|
846
|
-
|
|
847
|
-
this.#resetSpeculativeState();
|
|
848
|
-
this.#solving = false;
|
|
849
|
-
return { success: true, token: this.token };
|
|
962
|
+
return this.#commitSpeculativeToken();
|
|
850
963
|
}
|
|
851
964
|
|
|
852
965
|
if (this.#speculative.state === "done") {
|
|
@@ -874,6 +987,10 @@
|
|
|
874
987
|
}
|
|
875
988
|
|
|
876
989
|
const progressInterval = setInterval(() => {
|
|
990
|
+
if (signal?.aborted || !this.#speculative) {
|
|
991
|
+
clearInterval(progressInterval);
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
877
994
|
const st = this.#speculative.state;
|
|
878
995
|
if (st === "done" || st === "error") {
|
|
879
996
|
clearInterval(progressInterval);
|
|
@@ -896,6 +1013,7 @@
|
|
|
896
1013
|
this.#speculative.onSettled(resolve),
|
|
897
1014
|
);
|
|
898
1015
|
clearInterval(progressInterval);
|
|
1016
|
+
if (signal?.aborted || !this.#speculative) return;
|
|
899
1017
|
|
|
900
1018
|
if (
|
|
901
1019
|
this.#speculative.state === "idle" &&
|
|
@@ -904,10 +1022,13 @@
|
|
|
904
1022
|
) {
|
|
905
1023
|
challengeResp = this.#speculative.challengeResp;
|
|
906
1024
|
this.#speculative.challengeResp = null;
|
|
907
|
-
solutions = await this.solveChallengesV2(
|
|
1025
|
+
solutions = await this.solveChallengesV2(
|
|
1026
|
+
challengeResp.challenges,
|
|
1027
|
+
signal,
|
|
1028
|
+
);
|
|
908
1029
|
} else {
|
|
909
1030
|
if (this.#speculative.state !== "done") {
|
|
910
|
-
throw
|
|
1031
|
+
throw _err("solve_failed", "Unable to solve challenge, self-hosted instance likely down. This is not an issue with Cap.");
|
|
911
1032
|
}
|
|
912
1033
|
|
|
913
1034
|
if (
|
|
@@ -915,33 +1036,7 @@
|
|
|
915
1036
|
this.#speculative.tokenExpires &&
|
|
916
1037
|
Date.now() < this.#speculative.tokenExpires
|
|
917
1038
|
) {
|
|
918
|
-
this
|
|
919
|
-
|
|
920
|
-
const fieldName =
|
|
921
|
-
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
922
|
-
if (this.querySelector(`input[name='${fieldName}']`)) {
|
|
923
|
-
this.querySelector(`input[name='${fieldName}']`).value =
|
|
924
|
-
this.#speculative.token;
|
|
925
|
-
}
|
|
926
|
-
this.dispatchEvent("solve", { token: this.#speculative.token });
|
|
927
|
-
this.token = this.#speculative.token;
|
|
928
|
-
|
|
929
|
-
const expiresIn = this.#speculative.tokenExpires - Date.now();
|
|
930
|
-
if (this.#resetTimer) clearTimeout(this.#resetTimer);
|
|
931
|
-
this.#resetTimer = setTimeout(() => this.reset(), expiresIn);
|
|
932
|
-
|
|
933
|
-
this.#trigger.setAttribute(
|
|
934
|
-
"aria-label",
|
|
935
|
-
this.getI18nText(
|
|
936
|
-
"verified-aria-label",
|
|
937
|
-
"We have verified you're a human, you may now continue",
|
|
938
|
-
),
|
|
939
|
-
);
|
|
940
|
-
if (this.#hasHaptics) navigator.vibrate([10, 50, 20, 30, 40]);
|
|
941
|
-
|
|
942
|
-
this.#resetSpeculativeState();
|
|
943
|
-
this.#solving = false;
|
|
944
|
-
return { success: true, token: this.token };
|
|
1039
|
+
return this.#commitSpeculativeToken();
|
|
945
1040
|
}
|
|
946
1041
|
|
|
947
1042
|
solutions = this.#speculative.results;
|
|
@@ -956,20 +1051,24 @@
|
|
|
956
1051
|
} else {
|
|
957
1052
|
const challengeRaw = await capFetch(`${apiEndpoint}challenge`, {
|
|
958
1053
|
method: "POST",
|
|
1054
|
+
signal,
|
|
959
1055
|
});
|
|
960
1056
|
try {
|
|
961
1057
|
challengeResp = await challengeRaw.json();
|
|
962
1058
|
} catch {
|
|
963
|
-
throw
|
|
1059
|
+
throw _err("challenge_parse_error", "Failed to parse challenge response from server");
|
|
964
1060
|
}
|
|
965
|
-
if (challengeResp.error) throw
|
|
1061
|
+
if (challengeResp.error) throw _err("network_error", challengeResp.error);
|
|
966
1062
|
}
|
|
967
1063
|
|
|
968
1064
|
if (
|
|
969
1065
|
challengeResp.format === 2 &&
|
|
970
1066
|
Array.isArray(challengeResp.challenges)
|
|
971
1067
|
) {
|
|
972
|
-
solutions = await this.solveChallengesV2(
|
|
1068
|
+
solutions = await this.solveChallengesV2(
|
|
1069
|
+
challengeResp.challenges,
|
|
1070
|
+
signal,
|
|
1071
|
+
);
|
|
973
1072
|
} else {
|
|
974
1073
|
const { challenge, token } = challengeResp;
|
|
975
1074
|
let challenges = challenge;
|
|
@@ -983,7 +1082,7 @@
|
|
|
983
1082
|
];
|
|
984
1083
|
});
|
|
985
1084
|
}
|
|
986
|
-
solutions = await this.solveChallenges(challenges);
|
|
1085
|
+
solutions = await this.solveChallenges(challenges, signal);
|
|
987
1086
|
}
|
|
988
1087
|
}
|
|
989
1088
|
|
|
@@ -992,6 +1091,7 @@
|
|
|
992
1091
|
: Promise.resolve(null);
|
|
993
1092
|
|
|
994
1093
|
const instrOut = await instrPromise;
|
|
1094
|
+
if (signal?.aborted || !this.#speculative) return;
|
|
995
1095
|
|
|
996
1096
|
if (instrOut?.__timeout || instrOut?.__blocked) {
|
|
997
1097
|
capFetch(`${apiEndpoint}redeem`, {
|
|
@@ -1003,6 +1103,7 @@
|
|
|
1003
1103
|
...(instrOut.__timeout && { instr_timeout: true }),
|
|
1004
1104
|
}),
|
|
1005
1105
|
headers: { "Content-Type": "application/json" },
|
|
1106
|
+
signal,
|
|
1006
1107
|
}).catch(() => {});
|
|
1007
1108
|
|
|
1008
1109
|
this.updateUIBlocked(
|
|
@@ -1016,16 +1117,20 @@
|
|
|
1016
1117
|
"An error occurred, please try again",
|
|
1017
1118
|
),
|
|
1018
1119
|
);
|
|
1120
|
+
const instrCode = instrOut?.__blocked ? "instr_blocked" : "instr_timeout";
|
|
1121
|
+
const instrMsg = instrOut?.__blocked
|
|
1122
|
+
? `Instrumentation blocked (${instrOut.blockReason || "automated_browser"})`
|
|
1123
|
+
: "Instrumentation timed out";
|
|
1019
1124
|
this.removeEventListener("error", this.boundHandleError);
|
|
1020
1125
|
const errEvent = new CustomEvent("error", {
|
|
1021
1126
|
bubbles: true,
|
|
1022
1127
|
composed: true,
|
|
1023
|
-
detail: { isCap: true, message:
|
|
1128
|
+
detail: { isCap: true, code: instrCode, message: instrMsg },
|
|
1024
1129
|
});
|
|
1025
1130
|
super.dispatchEvent(errEvent);
|
|
1026
1131
|
this.addEventListener("error", this.boundHandleError);
|
|
1027
1132
|
this.executeAttributeCode("onerror", errEvent);
|
|
1028
|
-
|
|
1133
|
+
log.error(T("instr"), `[${instrCode}] ${instrMsg}`);
|
|
1029
1134
|
this.#solving = false;
|
|
1030
1135
|
return;
|
|
1031
1136
|
}
|
|
@@ -1040,23 +1145,22 @@
|
|
|
1040
1145
|
...(instrOut && { instr: instrOut }),
|
|
1041
1146
|
}),
|
|
1042
1147
|
headers: { "Content-Type": "application/json" },
|
|
1148
|
+
signal,
|
|
1043
1149
|
});
|
|
1044
1150
|
|
|
1045
1151
|
let resp;
|
|
1046
1152
|
try {
|
|
1047
1153
|
resp = await redeemResponse.json();
|
|
1048
1154
|
} catch {
|
|
1049
|
-
throw
|
|
1155
|
+
throw _err("redeem_failed", "Failed to parse server response");
|
|
1050
1156
|
}
|
|
1051
1157
|
|
|
1158
|
+
if (signal?.aborted || !this.#speculative) return;
|
|
1159
|
+
|
|
1052
1160
|
this.dispatchEvent("progress", { progress: 100 });
|
|
1053
|
-
if (!resp.success) throw
|
|
1161
|
+
if (!resp.success) throw _err("invalid_solution", resp.error || "Invalid solution");
|
|
1054
1162
|
|
|
1055
|
-
|
|
1056
|
-
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
1057
|
-
if (this.querySelector(`input[name='${fieldName}']`)) {
|
|
1058
|
-
this.querySelector(`input[name='${fieldName}']`).value = resp.token;
|
|
1059
|
-
}
|
|
1163
|
+
this.#setToken(resp.token);
|
|
1060
1164
|
|
|
1061
1165
|
this.dispatchEvent("solve", { token: resp.token });
|
|
1062
1166
|
this.token = resp.token;
|
|
@@ -1068,7 +1172,7 @@
|
|
|
1068
1172
|
if (expiresIn > 0 && expiresIn < 24 * 60 * 60 * 1000) {
|
|
1069
1173
|
this.#resetTimer = setTimeout(() => this.reset(), expiresIn);
|
|
1070
1174
|
} else {
|
|
1071
|
-
this.error("Invalid expiration time");
|
|
1175
|
+
this.error("Invalid expiration time", "invalid_expires");
|
|
1072
1176
|
}
|
|
1073
1177
|
|
|
1074
1178
|
this.#trigger.setAttribute(
|
|
@@ -1080,8 +1184,11 @@
|
|
|
1080
1184
|
);
|
|
1081
1185
|
if (this.#hasHaptics) navigator.vibrate([10, 50, 20, 30, 40]);
|
|
1082
1186
|
|
|
1187
|
+
log.debug(T("solve"), `verified in ${since(_solveT0)}`);
|
|
1188
|
+
this.#logInvisible();
|
|
1083
1189
|
return { success: true, token: this.token };
|
|
1084
1190
|
} catch (err) {
|
|
1191
|
+
if (signal?.aborted || !this.#speculative) return;
|
|
1085
1192
|
this.#trigger.setAttribute(
|
|
1086
1193
|
"aria-label",
|
|
1087
1194
|
this.getI18nText(
|
|
@@ -1089,7 +1196,7 @@
|
|
|
1089
1196
|
"An error occurred, please try again",
|
|
1090
1197
|
),
|
|
1091
1198
|
);
|
|
1092
|
-
this.error(err.message);
|
|
1199
|
+
this.error(err.message, err.code || "solve_failed");
|
|
1093
1200
|
throw err;
|
|
1094
1201
|
}
|
|
1095
1202
|
} finally {
|
|
@@ -1097,7 +1204,7 @@
|
|
|
1097
1204
|
}
|
|
1098
1205
|
}
|
|
1099
1206
|
|
|
1100
|
-
async solveChallengesV2(challenges) {
|
|
1207
|
+
async solveChallengesV2(challenges, signal) {
|
|
1101
1208
|
const total = challenges.length;
|
|
1102
1209
|
let completed = 0;
|
|
1103
1210
|
|
|
@@ -1115,7 +1222,7 @@
|
|
|
1115
1222
|
) {
|
|
1116
1223
|
// Unknown protocol = older widget on a newer server. Fall back to
|
|
1117
1224
|
// erroring out -- the host can detect this and serve format-1.
|
|
1118
|
-
throw
|
|
1225
|
+
throw _err("challenge_unsupported", `unsupported format-2 protocol '${ch?.protocol}'`);
|
|
1119
1226
|
}
|
|
1120
1227
|
}
|
|
1121
1228
|
|
|
@@ -1125,7 +1232,7 @@
|
|
|
1125
1232
|
typeof WebAssembly.instantiate === "function";
|
|
1126
1233
|
if (wasmSupported) {
|
|
1127
1234
|
try { wasmModule = await getWasmModule(); }
|
|
1128
|
-
catch (e) {
|
|
1235
|
+
catch (e) { log.warn(T("wasm"), "unavailable, falling back to JS solver:", e.message || e); }
|
|
1129
1236
|
}
|
|
1130
1237
|
|
|
1131
1238
|
const poolSize = Math.max(1, Math.min(this.#workersCount, challenges.length));
|
|
@@ -1150,7 +1257,7 @@
|
|
|
1150
1257
|
};
|
|
1151
1258
|
|
|
1152
1259
|
try {
|
|
1153
|
-
await Promise.all(
|
|
1260
|
+
await raceAbort(Promise.all(
|
|
1154
1261
|
challenges.map((ch, idx) => {
|
|
1155
1262
|
if (ch.protocol === "sha256-pow") {
|
|
1156
1263
|
return withTimeout(
|
|
@@ -1188,7 +1295,7 @@
|
|
|
1188
1295
|
emit();
|
|
1189
1296
|
});
|
|
1190
1297
|
}),
|
|
1191
|
-
);
|
|
1298
|
+
), signal);
|
|
1192
1299
|
} finally {
|
|
1193
1300
|
pool.terminate();
|
|
1194
1301
|
}
|
|
@@ -1196,7 +1303,7 @@
|
|
|
1196
1303
|
return solutions;
|
|
1197
1304
|
}
|
|
1198
1305
|
|
|
1199
|
-
async solveChallenges(challenges) {
|
|
1306
|
+
async solveChallenges(challenges, signal) {
|
|
1200
1307
|
const total = challenges.length;
|
|
1201
1308
|
let completed = 0;
|
|
1202
1309
|
|
|
@@ -1211,11 +1318,12 @@
|
|
|
1211
1318
|
try {
|
|
1212
1319
|
wasmModule = await getWasmModule();
|
|
1213
1320
|
} catch (e) {
|
|
1214
|
-
|
|
1321
|
+
log.warn(T("wasm"), "unavailable, falling back to JS solver:", e.message || e);
|
|
1215
1322
|
}
|
|
1216
1323
|
}
|
|
1217
1324
|
|
|
1218
1325
|
if (!wasmSupported) {
|
|
1326
|
+
log.warn(T("wasm"), "WebAssembly disabled in this browser, solver will be ~10x slower");
|
|
1219
1327
|
if (!this.#shadow.querySelector(".warning")) {
|
|
1220
1328
|
const warningEl = document.createElement("div");
|
|
1221
1329
|
warningEl.className = "warning";
|
|
@@ -1243,7 +1351,7 @@
|
|
|
1243
1351
|
i,
|
|
1244
1352
|
Math.min(i + this.#workersCount, challenges.length),
|
|
1245
1353
|
);
|
|
1246
|
-
const chunkResults = await Promise.all(
|
|
1354
|
+
const chunkResults = await raceAbort(Promise.all(
|
|
1247
1355
|
chunk.map(([salt, target]) =>
|
|
1248
1356
|
pool.run(salt, target).then((nonce) => {
|
|
1249
1357
|
completed++;
|
|
@@ -1255,7 +1363,7 @@
|
|
|
1255
1363
|
return nonce;
|
|
1256
1364
|
}),
|
|
1257
1365
|
),
|
|
1258
|
-
);
|
|
1366
|
+
), signal);
|
|
1259
1367
|
results.push(...chunkResults);
|
|
1260
1368
|
}
|
|
1261
1369
|
} finally {
|
|
@@ -1552,16 +1660,17 @@
|
|
|
1552
1660
|
return;
|
|
1553
1661
|
}
|
|
1554
1662
|
|
|
1555
|
-
|
|
1556
|
-
|
|
1663
|
+
log.warn(
|
|
1664
|
+
T(),
|
|
1665
|
+
"inline `onxxx='…'` handlers are deprecated. use `addEventListener` callbacks instead.",
|
|
1557
1666
|
);
|
|
1558
1667
|
|
|
1559
1668
|
new Function("event", code).call(this, event);
|
|
1560
1669
|
}
|
|
1561
1670
|
|
|
1562
|
-
error(message = "Unknown error") {
|
|
1563
|
-
|
|
1564
|
-
this.dispatchEvent("error", { isCap: true, message });
|
|
1671
|
+
error(message = "Unknown error", code = "unknown") {
|
|
1672
|
+
log.error(T("solve"), `[${code}] ${message}`);
|
|
1673
|
+
this.dispatchEvent("error", { isCap: true, code, message });
|
|
1565
1674
|
}
|
|
1566
1675
|
|
|
1567
1676
|
dispatchEvent(eventName, detail = {}) {
|
|
@@ -1580,11 +1689,7 @@
|
|
|
1580
1689
|
}
|
|
1581
1690
|
this.token = null;
|
|
1582
1691
|
this.dispatchEvent("reset");
|
|
1583
|
-
|
|
1584
|
-
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
1585
|
-
if (this.querySelector(`input[name='${fieldName}']`)) {
|
|
1586
|
-
this.querySelector(`input[name='${fieldName}']`).value = "";
|
|
1587
|
-
}
|
|
1692
|
+
this.#setToken("");
|
|
1588
1693
|
}
|
|
1589
1694
|
|
|
1590
1695
|
get tokenValue() {
|
|
@@ -1592,6 +1697,7 @@
|
|
|
1592
1697
|
}
|
|
1593
1698
|
|
|
1594
1699
|
disconnectedCallback() {
|
|
1700
|
+
this.#abort?.abort();
|
|
1595
1701
|
this.removeEventListener("progress", this.boundHandleProgress);
|
|
1596
1702
|
this.removeEventListener("solve", this.boundHandleSolve);
|
|
1597
1703
|
this.removeEventListener("error", this.boundHandleError);
|
|
@@ -1679,8 +1785,9 @@
|
|
|
1679
1785
|
if (!customElements.get("cap-widget") && !window?.CAP_DONT_SKIP_REDEFINE) {
|
|
1680
1786
|
customElements.define("cap-widget", CapWidget);
|
|
1681
1787
|
} else if (customElements.get("cap-widget")) {
|
|
1682
|
-
|
|
1683
|
-
|
|
1788
|
+
log.warn(
|
|
1789
|
+
T(),
|
|
1790
|
+
"cap-widget custom element already defined, skipping re-define. set window.CAP_DONT_SKIP_REDEFINE = true to override",
|
|
1684
1791
|
);
|
|
1685
1792
|
}
|
|
1686
1793
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export const shipped = [
|
|
2
|
+
"zh-cn", "es", "hi", "ar", "pt", "ru", "ja", "de", "fr",
|
|
3
|
+
];
|
|
4
|
+
|
|
5
|
+
export const shippedKeys = [
|
|
6
|
+
"initial-state", "verifying-label", "solved-label", "error-label",
|
|
7
|
+
"required-label", "troubleshooting-label", "group-aria-label",
|
|
8
|
+
"verify-aria-label", "verifying-aria-label", "verified-aria-label",
|
|
9
|
+
"error-aria-label",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export const keys = [
|
|
13
|
+
"initial-state", // Verify you're human
|
|
14
|
+
"verifying-label", // Verifying...
|
|
15
|
+
"solved-label", // You're a human
|
|
16
|
+
"error-label", // Error. Try again.
|
|
17
|
+
"required-label", // Please verify you're human
|
|
18
|
+
"troubleshooting-label", // Troubleshoot
|
|
19
|
+
"group-aria-label", // Cap verification
|
|
20
|
+
"verify-aria-label", // Click to verify you're a human
|
|
21
|
+
"verifying-aria-label", // Verifying you're a human, please wait
|
|
22
|
+
"verified-aria-label", // We have verified you're a human, you may now continue
|
|
23
|
+
"error-aria-label", // An error occurred, please try again
|
|
24
|
+
"wasm-disabled", // Enable WASM for significantly faster solving
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export const translations = {
|
|
28
|
+
es: ["Verifica que eres humano","Verificando...","Eres humano","Error. Inténtalo de nuevo.","Verifica que eres humano","Solucionar problemas","Verificación de Cap","Haz clic para verificar que eres humano","Verificando que eres humano, espera","Hemos verificado que eres humano, ya puedes continuar","Se produjo un error, inténtalo de nuevo","Activa WASM para una resolución mucho más rápida"],
|
|
29
|
+
pt: ["Sou humano","Verificando...","Você é humano","Erro. Tente novamente.","Verifique que você é humano","Solução de problemas","Verificação Cap","Clique para verificar que você é humano","Verificando que você é humano, aguarde","Verificamos que você é humano, você pode continuar","Ocorreu um erro, tente novamente","Ative o WASM para resolver muito mais rápido"],
|
|
30
|
+
fr: ["Je suis humain","Vérification...","Vous êtes humain","Erreur. Réessayez.","Veuillez vérifier que vous êtes humain","Dépannage","Vérification Cap","Cliquez pour vérifier que vous êtes humain","Vérification que vous êtes humain, veuillez patienter","Nous avons vérifié que vous êtes humain, vous pouvez continuer","Une erreur s'est produite, veuillez réessayer","Activez WASM pour une résolution bien plus rapide"],
|
|
31
|
+
de: ["Ich bin ein Mensch","Wird überprüft...","Sie sind ein Mensch","Fehler. Erneut versuchen.","Bitte bestätigen Sie, dass Sie ein Mensch sind","Fehlerbehebung","Cap-Verifizierung","Klicken, um zu bestätigen, dass Sie ein Mensch sind","Überprüfung, ob Sie ein Mensch sind, bitte warten","Wir haben bestätigt, dass Sie ein Mensch sind, Sie können fortfahren","Ein Fehler ist aufgetreten, bitte erneut versuchen","Aktivieren Sie WASM für deutlich schnelleres Lösen"],
|
|
32
|
+
it: ["Verifica di essere umano","Verifica in corso...","Sei umano","Errore. Riprova.","Verifica di essere umano","Risoluzione dei problemi","Verifica Cap","Clicca per verificare di essere umano","Verifica che sei umano, attendi","Abbiamo verificato che sei umano, puoi continuare","Si è verificato un errore, riprova","Abilita WASM per una risoluzione molto più veloce"],
|
|
33
|
+
nl: ["Ik ben een mens","Verifiëren...","Je bent een mens","Fout. Probeer opnieuw.","Verifieer dat je een mens bent","Problemen oplossen","Cap-verificatie","Klik om te verifiëren dat je een mens bent","Verifiëren dat je een mens bent, even geduld","We hebben geverifieerd dat je een mens bent, je kunt doorgaan","Er is een fout opgetreden, probeer opnieuw","Schakel WASM in voor veel sneller oplossen"],
|
|
34
|
+
sv: ["Jag är människa","Verifierar...","Du är människa","Fel. Försök igen.","Verifiera att du är människa","Felsökning","Cap-verifiering","Klicka för att verifiera att du är människa","Verifierar att du är människa, vänta","Vi har verifierat att du är människa, du kan fortsätta","Ett fel uppstod, försök igen","Aktivera WASM för betydligt snabbare lösning"],
|
|
35
|
+
da: ["Jeg er et menneske","Bekræfter...","Du er et menneske","Fejl. Prøv igen.","Bekræft, at du er et menneske","Fejlfinding","Cap-bekræftelse","Klik for at bekræfte, at du er et menneske","Bekræfter, at du er et menneske, vent","Vi har bekræftet, at du er et menneske, du kan fortsætte","Der opstod en fejl, prøv igen","Aktivér WASM for betydeligt hurtigere løsning"],
|
|
36
|
+
nb: ["Jeg er et menneske","Bekrefter...","Du er et menneske","Feil. Prøv igjen.","Bekreft at du er et menneske","Feilsøking","Cap-bekreftelse","Klikk for å bekrefte at du er et menneske","Bekrefter at du er et menneske, vent","Vi har bekreftet at du er et menneske, du kan fortsette","Det oppstod en feil, prøv igjen","Aktiver WASM for betydelig raskere løsning"],
|
|
37
|
+
fi: ["Vahvista, että olet ihminen","Vahvistetaan...","Olet ihminen","Virhe. Yritä uudelleen.","Vahvista, että olet ihminen","Vianmääritys","Cap-vahvistus","Napsauta vahvistaaksesi, että olet ihminen","Vahvistetaan, että olet ihminen, odota","Olemme vahvistaneet, että olet ihminen, voit jatkaa","Tapahtui virhe, yritä uudelleen","Ota WASM käyttöön huomattavasti nopeampaa ratkaisua varten"],
|
|
38
|
+
pl: ["Jestem człowiekiem","Weryfikacja...","Jesteś człowiekiem","Błąd. Spróbuj ponownie.","Potwierdź, że jesteś człowiekiem","Rozwiązywanie problemów","Weryfikacja Cap","Kliknij, aby potwierdzić, że jesteś człowiekiem","Weryfikacja, że jesteś człowiekiem, czekaj","Potwierdziliśmy, że jesteś człowiekiem, możesz kontynuować","Wystąpił błąd, spróbuj ponownie","Włącz WASM, aby rozwiązywać znacznie szybciej"],
|
|
39
|
+
cs: ["Ověřte, že jste člověk","Ověřování...","Jste člověk","Chyba. Zkuste to znovu.","Ověřte, že jste člověk","Řešení potíží","Ověření Cap","Kliknutím ověřte, že jste člověk","Ověřujeme, že jste člověk, čekejte","Ověřili jsme, že jste člověk, můžete pokračovat","Došlo k chybě, zkuste to znovu","Povolte WASM pro výrazně rychlejší řešení"],
|
|
40
|
+
sk: ["Overte, že ste človek","Overovanie...","Ste človek","Chyba. Skúste znova.","Overte, že ste človek","Riešenie problémov","Overenie Cap","Kliknutím overte, že ste človek","Overujeme, že ste človek, čakajte","Overili sme, že ste človek, môžete pokračovať","Vyskytla sa chyba, skúste znova","Povoľte WASM pre výrazne rýchlejšie riešenie"],
|
|
41
|
+
ru: ["Я человек","Проверка...","Вы человек","Ошибка. Повторите.","Подтвердите, что вы человек","Устранение неполадок","Проверка Cap","Нажмите, чтобы подтвердить, что вы человек","Проверяем, что вы человек, подождите","Мы подтвердили, что вы человек, можете продолжить","Произошла ошибка, повторите попытку","Включите WASM для значительно более быстрого решения"],
|
|
42
|
+
uk: ["Я людина","Перевірка...","Ви людина","Помилка. Спробуйте.","Підтвердьте, що ви людина","Усунення несправностей","Перевірка Cap","Натисніть, щоб підтвердити, що ви людина","Перевіряємо, що ви людина, зачекайте","Ми підтвердили, що ви людина, можете продовжити","Сталася помилка, спробуйте ще раз","Увімкніть WASM для значно швидшого розв’язання"],
|
|
43
|
+
ca: ["Verifica que ets humà","Verificant...","Ets humà","Error. Torna-ho a provar.","Verifica que ets humà","Resolució de problemes","Verificació de Cap","Fes clic per verificar que ets humà","Verificant que ets humà, espera","Hem verificat que ets humà, ja pots continuar","S'ha produït un error, torna-ho a provar","Activa WASM per resoldre molt més ràpid"],
|
|
44
|
+
gl: ["Verifica que es humano","Verificando...","Es humano","Erro. Téntao de novo.","Verifica que es humano","Resolución de problemas","Verificación de Cap","Fai clic para verificar que es humano","Verificando que es humano, agarda","Verificamos que es humano, xa podes continuar","Produciuse un erro, téntao de novo","Activa WASM para resolver moito máis rápido"],
|
|
45
|
+
af: ["Bevestig dat jy 'n mens is","Verifieer tans...","Jy is 'n mens","Fout. Probeer weer.","Bevestig asseblief dat jy 'n mens is","Probleemoplossing","Cap-verifikasie","Klik om te bevestig dat jy 'n mens is","Bevestig tans dat jy 'n mens is, wag asseblief","Ons het bevestig dat jy 'n mens is, jy kan voortgaan","'n Fout het voorgekom, probeer weer","Aktiveer WASM vir aansienlik vinniger oplossing"],
|
|
46
|
+
id: ["Verifikasi Anda manusia","Memverifikasi...","Anda manusia","Kesalahan. Coba lagi.","Harap verifikasi Anda manusia","Pemecahan masalah","Verifikasi Cap","Klik untuk memverifikasi Anda manusia","Memverifikasi Anda manusia, harap tunggu","Kami telah memverifikasi Anda manusia, Anda dapat melanjutkan","Terjadi kesalahan, coba lagi","Aktifkan WASM untuk penyelesaian yang jauh lebih cepat"],
|
|
47
|
+
ms: ["Sahkan anda manusia","Mengesahkan...","Anda manusia","Ralat. Cuba lagi.","Sila sahkan anda manusia","Penyelesaian masalah","Pengesahan Cap","Klik untuk mengesahkan anda manusia","Mengesahkan anda manusia, sila tunggu","Kami telah mengesahkan anda manusia, anda boleh teruskan","Ralat berlaku, sila cuba lagi","Dayakan WASM untuk penyelesaian yang jauh lebih pantas"],
|
|
48
|
+
ro: ["Verificați că sunteți om","Se verifică...","Sunteți om","Eroare. Încercați din nou.","Verificați că sunteți om","Depanare","Verificare Cap","Faceți clic pentru a verifica că sunteți om","Verificăm că sunteți om, așteptați","Am verificat că sunteți om, puteți continua","A apărut o eroare, încercați din nou","Activați WASM pentru o rezolvare mult mai rapidă"],
|
|
49
|
+
hu: ["Igazolja, hogy ember","Ellenőrzés...","Ön ember","Hiba. Próbálja újra.","Igazolja, hogy ember","Hibaelhárítás","Cap-ellenőrzés","Kattintson az emberi voltának igazolásához","Ellenőrizzük, hogy ember-e, kérjük várjon","Igazoltuk, hogy ember, folytathatja","Hiba történt, próbálja újra","Engedélyezze a WASM-ot a sokkal gyorsabb megoldásért"],
|
|
50
|
+
el: ["Είμαι άνθρωπος","Επαλήθευση...","Είστε άνθρωπος","Σφάλμα. Δοκιμάστε ξανά.","Επιβεβαιώστε ότι είστε άνθρωπος","Αντιμετώπιση προβλημάτων","Επαλήθευση Cap","Κάντε κλικ για να επιβεβαιώσετε ότι είστε άνθρωπος","Επαληθεύουμε ότι είστε άνθρωπος, περιμένετε","Επιβεβαιώσαμε ότι είστε άνθρωπος, μπορείτε να συνεχίσετε","Παρουσιάστηκε σφάλμα, δοκιμάστε ξανά","Ενεργοποιήστε το WASM για πολύ ταχύτερη επίλυση"],
|
|
51
|
+
bg: ["Потвърдете, че сте човек","Проверка...","Вие сте човек","Грешка. Опитайте пак.","Потвърдете, че сте човек","Отстраняване на неизправности","Проверка Cap","Щракнете, за да потвърдите, че сте човек","Проверяваме, че сте човек, изчакайте","Потвърдихме, че сте човек, можете да продължите","Възникна грешка, опитайте отново","Активирайте WASM за значително по-бързо решаване"],
|
|
52
|
+
sr: ["Потврдите да сте човек","Провера...","Ви сте човек","Грешка. Покушајте опет.","Потврдите да сте човек","Решавање проблема","Cap провера","Кликните да потврдите да сте човек","Проверавамо да сте човек, сачекајте","Потврдили смо да сте човек, можете наставити","Дошло је до грешке, покушајте поново","Омогућите WASM за знатно брже решавање"],
|
|
53
|
+
hr: ["Potvrdite da ste čovjek","Provjera...","Vi ste čovjek","Greška. Pokušajte opet.","Potvrdite da ste čovjek","Rješavanje problema","Cap provjera","Kliknite da potvrdite da ste čovjek","Provjeravamo da ste čovjek, pričekajte","Potvrdili smo da ste čovjek, možete nastaviti","Došlo je do pogreške, pokušajte ponovno","Omogućite WASM za znatno brže rješavanje"],
|
|
54
|
+
sl: ["Potrdite, da ste človek","Preverjanje...","Ste človek","Napaka. Poskusite znova.","Potrdite, da ste človek","Odpravljanje težav","Preverjanje Cap","Kliknite za potrditev, da ste človek","Preverjamo, da ste človek, počakajte","Potrdili smo, da ste človek, lahko nadaljujete","Prišlo je do napake, poskusite znova","Omogočite WASM za bistveno hitrejše reševanje"],
|
|
55
|
+
et: ["Kinnitage, et olete inimene","Kontrollimine...","Olete inimene","Viga. Proovige uuesti.","Kinnitage, et olete inimene","Tõrkeotsing","Cap kontroll","Klõpsake, et kinnitada, et olete inimene","Kontrollime, et olete inimene, oodake","Kinnitasime, et olete inimene, võite jätkata","Ilmnes viga, proovige uuesti","Lubage WASM oluliselt kiiremaks lahendamiseks"],
|
|
56
|
+
lv: ["Esmu cilvēks","Pārbauda...","Jūs esat cilvēks","Kļūda. Mēģiniet vēlreiz.","Apstipriniet, ka esat cilvēks","Problēmu novēršana","Cap pārbaude","Noklikšķiniet, lai apstiprinātu, ka esat cilvēks","Pārbaudām, ka esat cilvēks, uzgaidiet","Mēs apstiprinājām, ka esat cilvēks, varat turpināt","Radās kļūda, mēģiniet vēlreiz","Iespējojiet WASM ievērojami ātrākai risināšanai"],
|
|
57
|
+
lt: ["Esu žmogus","Tikrinama...","Jūs esate žmogus","Klaida. Bandykite vėl.","Patvirtinkite, kad esate žmogus","Trikčių šalinimas","Cap patvirtinimas","Spustelėkite, kad patvirtintumėte, jog esate žmogus","Tikriname, ar esate žmogus, palaukite","Patvirtinome, kad esate žmogus, galite tęsti","Įvyko klaida, bandykite dar kartą","Įjunkite WASM, kad išspręstumėte daug greičiau"],
|
|
58
|
+
tr: ["Ben insanım","Doğrulanıyor...","İnsansınız","Hata. Tekrar deneyin.","Lütfen insan olduğunuzu doğrulayın","Sorun giderme","Cap doğrulaması","İnsan olduğunuzu doğrulamak için tıklayın","İnsan olduğunuz doğrulanıyor, lütfen bekleyin","İnsan olduğunuzu doğruladık, devam edebilirsiniz","Bir hata oluştu, tekrar deneyin","Çok daha hızlı çözüm için WASM'ı etkinleştirin"],
|
|
59
|
+
vi: ["Xác minh bạn là con người","Đang xác minh...","Bạn là con người","Lỗi. Thử lại.","Vui lòng xác minh bạn là con người","Khắc phục sự cố","Xác minh Cap","Nhấp để xác minh bạn là con người","Đang xác minh bạn là con người, vui lòng đợi","Chúng tôi đã xác minh bạn là con người, bạn có thể tiếp tục","Đã xảy ra lỗi, vui lòng thử lại","Bật WASM để giải nhanh hơn đáng kể"],
|
|
60
|
+
tl: ["Patunayan na ikaw ay tao","Bineberipika...","Ikaw ay tao","Error. Subukan ulit.","Pakipatunayan na ikaw ay tao","Pag-troubleshoot","Pagpapatunay ng Cap","I-click para patunayan na ikaw ay tao","Pinapatunayan na ikaw ay tao, maghintay","Napatunayan namin na ikaw ay tao, maaari nang magpatuloy","May naganap na error, subukan ulit","I-enable ang WASM para sa mas mabilis na paglutas"],
|
|
61
|
+
ar: ["تحقق من أنك إنسان","جارٍ التحقق...","أنت إنسان","خطأ. حاول مرة أخرى.","يرجى التحقق من أنك إنسان","استكشاف الأخطاء وإصلاحها","تحقق Cap","انقر للتحقق من أنك إنسان","جارٍ التحقق من أنك إنسان، يرجى الانتظار","لقد تحققنا من أنك إنسان، يمكنك المتابعة الآن","حدث خطأ، يرجى المحاولة مرة أخرى","فعّل WASM لحل أسرع بكثير"],
|
|
62
|
+
he: ["אמת שאתה אנושי","מאמת...","אתה אנושי","שגיאה. נסה שוב.","נא לאמת שאתה אנושי","פתרון בעיות","אימות Cap","לחץ כדי לאמת שאתה אנושי","מאמת שאתה אנושי, אנא המתן","אימתנו שאתה אנושי, אפשר להמשיך","אירעה שגיאה, נסה שוב","הפעל את WASM לפתרון מהיר בהרבה"],
|
|
63
|
+
fa: ["تأیید کنید که انسان هستید","در حال تأیید...","شما انسان هستید","خطا. دوباره تلاش کنید.","لطفاً تأیید کنید که انسان هستید","عیبیابی","تأیید Cap","برای تأیید اینکه انسان هستید کلیک کنید","در حال تأیید اینکه انسان هستید، لطفاً صبر کنید","تأیید کردیم که انسان هستید، میتوانید ادامه دهید","خطایی رخ داد، دوباره تلاش کنید","برای حل بسیار سریعتر، WASM را فعال کنید"],
|
|
64
|
+
"zh-cn": ["确认你是真人","正在验证...","你是真人","出错了。请重试。","请确认你是真人","故障排除","Cap 验证","点击以确认你是真人","正在验证你是真人,请稍候","我们已确认你是真人,你可以继续了","发生错误,请重试","启用 WASM 可大幅加快求解速度"],
|
|
65
|
+
"zh-tw": ["確認你是真人","正在驗證...","你是真人","發生錯誤。請重試。","請確認你是真人","疑難排解","Cap 驗證","點擊以確認你是真人","正在驗證你是真人,請稍候","我們已確認你是真人,你可以繼續了","發生錯誤,請重試","啟用 WASM 可大幅加快解算速度"],
|
|
66
|
+
ja: ["私は人間です","確認中...","あなたは人間です","エラー。再試行を。","あなたが人間であることを確認してください","トラブルシューティング","Cap 認証","クリックして人間であることを確認","あなたが人間であることを確認しています。お待ちください","あなたが人間であることを確認しました。続行できます","エラーが発生しました。もう一度お試しください","WASM を有効にすると大幅に高速化されます"],
|
|
67
|
+
ko: ["사람인지 확인하세요","확인 중...","당신은 사람입니다","오류. 다시 시도하세요.","사람인지 확인해 주세요","문제 해결","Cap 인증","클릭하여 사람인지 확인하세요","사람인지 확인 중입니다. 잠시 기다려 주세요","사람임을 확인했습니다. 계속할 수 있습니다","오류가 발생했습니다. 다시 시도하세요","훨씬 빠른 처리를 위해 WASM을 활성화하세요"],
|
|
68
|
+
az: ["Mən insanam","Yoxlanılır...","Siz insansınız","Xəta. Yenidən cəhd edin.","İnsan olduğunuzu təsdiqləyin","Problemlərin həlli","Cap yoxlaması","İnsan olduğunuzu təsdiqləmək üçün klikləyin","İnsan olduğunuz yoxlanılır, gözləyin","İnsan olduğunuzu təsdiqlədik, davam edə bilərsiniz","Xəta baş verdi, yenidən cəhd edin","Daha sürətli həll üçün WASM-ı aktivləşdirin"],
|
|
69
|
+
kk: ["Адам екеніңізді растаңыз","Тексерілуде...","Сіз адамсыз","Қате. Қайталап көріңіз.","Адам екеніңізді растаңыз","Ақаулықтарды жою","Cap растауы","Адам екеніңізді растау үшін басыңыз","Адам екеніңізді тексерудеміз, күтіңіз","Адам екеніңізді растадық, жалғастыра аласыз","Қате орын алды, қайталап көріңіз","Әлдеқайда жылдам шешу үшін WASM қосыңыз"],
|
|
70
|
+
ka: ["მე ადამიანი ვარ","მოწმდება...","თქვენ ადამიანი ხართ","შეცდომა. სცადეთ.","დაადასტურეთ, რომ ადამიანი ხართ","პრობლემის გადაჭრა","Cap-ის დადასტურება","დააწკაპუნეთ, რომ დაადასტუროთ, რომ ადამიანი ხართ","ვამოწმებთ, რომ ადამიანი ხართ, დაელოდეთ","დავადასტურეთ, რომ ადამიანი ხართ, შეგიძლიათ გააგრძელოთ","მოხდა შეცდომა, სცადეთ ხელახლა","ჩართეთ WASM მნიშვნელოვნად სწრაფი ამოხსნისთვის"],
|
|
71
|
+
hy: ["Հաստատեք, որ մարդ եք","Ստուգվում է...","Դուք մարդ եք","Սխալ. Կրկին փորձեք։","Հաստատեք, որ մարդ եք","Անսարքությունների վերացում","Cap ստուգում","Սեղմեք՝ հաստատելու, որ մարդ եք","Ստուգում ենք, որ մարդ եք, սպասեք","Մենք հաստատեցինք, որ մարդ եք, կարող եք շարունակել","Սխալ տեղի ունեցավ, կրկին փորձեք","Միացրեք WASM-ը զգալիորեն ավելի արագ լուծման համար"],
|
|
72
|
+
ur: ["تصدیق کریں کہ آپ انسان ہیں","تصدیق ہو رہی ہے...","آپ انسان ہیں","خرابی۔ دوبارہ کوشش کریں۔","براہ کرم تصدیق کریں کہ آپ انسان ہیں","مسئلہ حل کریں","Cap تصدیق","تصدیق کے لیے کلک کریں کہ آپ انسان ہیں","تصدیق ہو رہی ہے کہ آپ انسان ہیں، انتظار کریں","ہم نے تصدیق کر لی کہ آپ انسان ہیں، اب آپ جاری رکھ سکتے ہیں","ایک خرابی پیش آئی، دوبارہ کوشش کریں","نمایاں طور پر تیز حل کے لیے WASM فعال کریں"],
|
|
73
|
+
hi: ["पुष्टि करें कि आप मानव हैं","सत्यापित हो रहा है...","आप मानव हैं","त्रुटि। पुनः प्रयास करें।","कृपया पुष्टि करें कि आप मानव हैं","समस्या निवारण","Cap सत्यापन","पुष्टि करने के लिए क्लिक करें कि आप मानव हैं","सत्यापित किया जा रहा है कि आप मानव हैं, प्रतीक्षा करें","हमने पुष्टि कर दी है कि आप मानव हैं, अब आप जारी रख सकते हैं","एक त्रुटि हुई, पुनः प्रयास करें","काफी तेज़ समाधान के लिए WASM सक्षम करें"],
|
|
74
|
+
bn: ["আপনি মানুষ তা যাচাই করুন","যাচাই করা হচ্ছে...","আপনি মানুষ","ত্রুটি। আবার চেষ্টা করুন।","অনুগ্রহ করে যাচাই করুন যে আপনি মানুষ","সমস্যা সমাধান","Cap যাচাই","আপনি মানুষ তা যাচাই করতে ক্লিক করুন","আপনি মানুষ তা যাচাই করা হচ্ছে, অপেক্ষা করুন","আমরা যাচাই করেছি যে আপনি মানুষ, এখন চালিয়ে যেতে পারেন","একটি ত্রুটি ঘটেছে, আবার চেষ্টা করুন","অনেক দ্রুত সমাধানের জন্য WASM সক্ষম করুন"],
|
|
75
|
+
ta: ["நான் மனிதர்","சரிபார்க்கிறது...","நீங்கள் மனிதர்","பிழை. மீண்டும் முயலவும்.","நீங்கள் மனிதர் என்பதை உறுதிப்படுத்தவும்","சிக்கல் தீர்வு","Cap சரிபார்ப்பு","நீங்கள் மனிதர் என உறுதிப்படுத்த கிளிக் செய்யவும்","நீங்கள் மனிதர் என சரிபார்க்கிறது, காத்திருக்கவும்","நீங்கள் மனிதர் என உறுதிப்படுத்தினோம், தொடரலாம்","பிழை ஏற்பட்டது, மீண்டும் முயற்சிக்கவும்","மிக வேகமான தீர்வுக்கு WASM ஐ இயக்கவும்"],
|
|
76
|
+
te: ["నేను మనిషిని","ధృవీకరిస్తోంది...","మీరు మనిషి","లోపం. మళ్లీ ప్రయత్నించండి.","దయచేసి మీరు మనిషి అని ధృవీకరించండి","సమస్య పరిష్కారం","Cap ధృవీకరణ","మీరు మనిషి అని ధృవీకరించడానికి క్లిక్ చేయండి","మీరు మనిషి అని ధృవీకరిస్తోంది, వేచి ఉండండి","మీరు మనిషి అని మేము ధృవీకరించాము, ఇప్పుడు కొనసాగవచ్చు","లోపం సంభవించింది, మళ్లీ ప్రయత్నించండి","చాలా వేగవంతమైన పరిష్కారం కోసం WASM ప్రారంభించండి"],
|
|
77
|
+
mr: ["मी मानव आहे","पडताळणी होत आहे...","तुम्ही मानव आहात","त्रुटी. पुन्हा प्रयत्न करा.","कृपया तुम्ही मानव आहात याची पुष्टी करा","समस्यानिवारण","Cap पडताळणी","तुम्ही मानव आहात याची पुष्टी करण्यासाठी क्लिक करा","तुम्ही मानव आहात याची पडताळणी होत आहे, प्रतीक्षा करा","आम्ही पुष्टी केली की तुम्ही मानव आहात, आता पुढे जाऊ शकता","त्रुटी आली, पुन्हा प्रयत्न करा","खूप जलद सोडवण्यासाठी WASM सक्षम करा"],
|
|
78
|
+
gu: ["તમે માનવ છો તેની ખાતરી કરો","ચકાસણી થઈ રહી છે...","તમે માનવ છો","ભૂલ. ફરી પ્રયાસ કરો.","કૃપા કરીને ખાતરી કરો કે તમે માનવ છો","સમસ્યાનિવારણ","Cap ચકાસણી","તમે માનવ છો તેની ખાતરી કરવા ક્લિક કરો","તમે માનવ છો તેની ચકાસણી થઈ રહી છે, રાહ જુઓ","અમે ખાતરી કરી કે તમે માનવ છો, હવે ચાલુ રાખી શકો છો","ભૂલ આવી, ફરી પ્રયાસ કરો","ઘણા ઝડપી ઉકેલ માટે WASM સક્ષમ કરો"],
|
|
79
|
+
kn: ["ನಾನು ಮನುಷ್ಯ","ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ...","ನೀವು ಮನುಷ್ಯ","ದೋಷ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.","ದಯವಿಟ್ಟು ನೀವು ಮನುಷ್ಯ ಎಂದು ದೃಢೀಕರಿಸಿ","ಸಮಸ್ಯೆ ಪರಿಹಾರ","Cap ಪರಿಶೀಲನೆ","ನೀವು ಮನುಷ್ಯ ಎಂದು ದೃಢೀಕರಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ","ನೀವು ಮನುಷ್ಯ ಎಂದು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ, ನಿರೀಕ್ಷಿಸಿ","ನೀವು ಮನುಷ್ಯ ಎಂದು ದೃಢೀಕರಿಸಿದ್ದೇವೆ, ಮುಂದುವರಿಯಬಹುದು","ದೋಷ ಸಂಭವಿಸಿದೆ, ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ","ಬಹಳ ವೇಗದ ಪರಿಹಾರಕ್ಕಾಗಿ WASM ಸಕ್ರಿಯಗೊಳಿಸಿ"],
|
|
80
|
+
ml: ["ഞാൻ മനുഷ്യനാണ്","പരിശോധിക്കുന്നു...","നിങ്ങൾ മനുഷ്യനാണ്","പിശക്. വീണ്ടും ശ്രമിക്കുക.","ദയവായി നിങ്ങൾ മനുഷ്യനാണെന്ന് സ്ഥിരീകരിക്കുക","പ്രശ്നപരിഹാരം","Cap പരിശോധന","നിങ്ങൾ മനുഷ്യനാണെന്ന് സ്ഥിരീകരിക്കാൻ ക്ലിക്ക് ചെയ്യുക","നിങ്ങൾ മനുഷ്യനാണെന്ന് പരിശോധിക്കുന്നു, കാത്തിരിക്കുക","നിങ്ങൾ മനുഷ്യനാണെന്ന് ഞങ്ങൾ സ്ഥിരീകരിച്ചു, തുടരാം","ഒരു പിശക് സംഭവിച്ചു, വീണ്ടും ശ്രമിക്കുക","വളരെ വേഗത്തിലുള്ള പരിഹാരത്തിന് WASM പ്രവർത്തനക്ഷമമാക്കുക"],
|
|
81
|
+
pa: ["ਪੁਸ਼ਟੀ ਕਰੋ ਕਿ ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ","ਪੁਸ਼ਟੀ ਹੋ ਰਹੀ ਹੈ...","ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ","ਗਲਤੀ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।","ਕਿਰਪਾ ਕਰਕੇ ਪੁਸ਼ਟੀ ਕਰੋ ਕਿ ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ","ਸਮੱਸਿਆ ਹੱਲ","Cap ਪੁਸ਼ਟੀ","ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ ਕਿ ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ","ਪੁਸ਼ਟੀ ਹੋ ਰਹੀ ਹੈ ਕਿ ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ, ਉਡੀਕ ਕਰੋ","ਅਸੀਂ ਪੁਸ਼ਟੀ ਕਰ ਲਈ ਹੈ ਕਿ ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ, ਹੁਣ ਜਾਰੀ ਰੱਖ ਸਕਦੇ ਹੋ","ਇੱਕ ਗਲਤੀ ਆਈ, ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ","ਬਹੁਤ ਤੇਜ਼ ਹੱਲ ਲਈ WASM ਚਾਲੂ ਕਰੋ"],
|
|
82
|
+
th: ["ยืนยันว่าคุณเป็นมนุษย์","กำลังยืนยัน...","คุณเป็นมนุษย์","ข้อผิดพลาด ลองอีกครั้ง","โปรดยืนยันว่าคุณเป็นมนุษย์","การแก้ไขปัญหา","การยืนยัน Cap","คลิกเพื่อยืนยันว่าคุณเป็นมนุษย์","กำลังยืนยันว่าคุณเป็นมนุษย์ โปรดรอ","เรายืนยันแล้วว่าคุณเป็นมนุษย์ คุณดำเนินการต่อได้","เกิดข้อผิดพลาด โปรดลองอีกครั้ง","เปิดใช้งาน WASM เพื่อการแก้ปัญหาที่เร็วขึ้นมาก"],
|
|
83
|
+
sw: ["Mimi ni binadamu","Inathibitisha...","Wewe ni binadamu","Hitilafu. Jaribu tena.","Tafadhali thibitisha kuwa wewe ni binadamu","Utatuzi wa matatizo","Uthibitisho wa Cap","Bofya ili kuthibitisha kuwa wewe ni binadamu","Inathibitisha kuwa wewe ni binadamu, tafadhali subiri","Tumethibitisha kuwa wewe ni binadamu, unaweza kuendelea","Hitilafu imetokea, tafadhali jaribu tena","Washa WASM kwa utatuzi wa haraka zaidi"],
|
|
84
|
+
am: ["ሰው መሆንዎን ያረጋግጡ","በማረጋገጥ ላይ...","እርስዎ ሰው ነዎት","ስህተት። እንደገና ይሞክሩ።","እባክዎ ሰው መሆንዎን ያረጋግጡ","ችግር መፍታት","የCap ማረጋገጫ","ሰው መሆንዎን ለማረጋገጥ ጠቅ ያድርጉ","ሰው መሆንዎን በማረጋገጥ ላይ፣ እባክዎ ይጠብቁ","ሰው መሆንዎን አረጋግጠናል፣ መቀጠል ይችላሉ","ስህተት ተከስቷል፣ እባክዎ እንደገና ይሞክሩ","በጣም ፈጣን መፍትሄ ለማግኘት WASM ን ያንቁ"],
|
|
85
|
+
my: ["ကျွန်ုပ် လူသားဖြစ်သည်","အတည်ပြုနေသည်...","သင်သည် လူသားဖြစ်သည်","အမှား။ ထပ်ကြိုးစားပါ။","သင်သည် လူသားဖြစ်ကြောင်း အတည်ပြုပါ","ပြဿနာဖြေရှင်းခြင်း","Cap အတည်ပြုခြင်း","သင်သည် လူသားဖြစ်ကြောင်း အတည်ပြုရန် နှိပ်ပါ","သင်သည် လူသားဖြစ်ကြောင်း အတည်ပြုနေသည်၊ စောင့်ပါ","သင်သည် လူသားဖြစ်ကြောင်း ကျွန်ုပ်တို့ အတည်ပြုပြီးပါပြီ၊ ဆက်လက်လုပ်ဆောင်နိုင်ပါသည်","အမှားဖြစ်ပွားခဲ့သည်၊ ထပ်ကြိုးစားပါ","များစွာပိုမြန်သော ဖြေရှင်းမှုအတွက် WASM ကိုဖွင့်ပါ"],
|
|
86
|
+
km: ["បញ្ជាក់ថាអ្នកជាមនុស្ស","កំពុងផ្ទៀងផ្ទាត់...","អ្នកជាមនុស្ស","កំហុស។ សាកល្បងម្តងទៀត។","សូមបញ្ជាក់ថាអ្នកជាមនុស្ស","ការដោះស្រាយបញ្ហា","ការផ្ទៀងផ្ទាត់ Cap","ចុចដើម្បីបញ្ជាក់ថាអ្នកជាមនុស្ស","កំពុងផ្ទៀងផ្ទាត់ថាអ្នកជាមនុស្ស សូមរង់ចាំ","យើងបានផ្ទៀងផ្ទាត់ថាអ្នកជាមនុស្ស អ្នកអាចបន្តបាន","មានកំហុសកើតឡើង សូមសាកល្បងម្តងទៀត","បើក WASM សម្រាប់ការដោះស្រាយលឿនជាងមុនច្រើន"],
|
|
87
|
+
};
|
package/src/worker.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
(() => {
|
|
2
|
+
const wlog = (method, ...args) => {
|
|
3
|
+
if (!self.CAP_SILENT) console[method]("[cap worker]", ...args);
|
|
4
|
+
};
|
|
5
|
+
|
|
2
6
|
const solveFallback = async ({ salt, target }) => {
|
|
3
7
|
let nonce = 0;
|
|
4
8
|
const batchSize = 50000;
|
|
@@ -50,7 +54,7 @@
|
|
|
50
54
|
nonce++;
|
|
51
55
|
}
|
|
52
56
|
} catch (error) {
|
|
53
|
-
|
|
57
|
+
wlog("error","fallback solver crashed:", error.message || error);
|
|
54
58
|
self.postMessage({
|
|
55
59
|
found: false,
|
|
56
60
|
error: error.message,
|
|
@@ -79,9 +83,7 @@
|
|
|
79
83
|
};
|
|
80
84
|
|
|
81
85
|
if (typeof WebAssembly !== "object" || typeof WebAssembly?.instantiate !== "function") {
|
|
82
|
-
|
|
83
|
-
"[cap worker] wasm not supported, falling back to alternative solver. this will be significantly slower.",
|
|
84
|
-
);
|
|
86
|
+
wlog("warn","WebAssembly unavailable, using JS fallback solver (significantly slower)");
|
|
85
87
|
|
|
86
88
|
self.onmessage = async ({ data }) => {
|
|
87
89
|
if (data?.kind === "rsw") return solveRsw(data);
|
|
@@ -171,7 +173,7 @@
|
|
|
171
173
|
|
|
172
174
|
return true;
|
|
173
175
|
} catch (e) {
|
|
174
|
-
|
|
176
|
+
wlog("error","wasm init failed:", e.message || e);
|
|
175
177
|
return false;
|
|
176
178
|
}
|
|
177
179
|
};
|
|
@@ -182,13 +184,13 @@
|
|
|
182
184
|
if (wasmModule instanceof WebAssembly.Module && solve_pow_function === null) {
|
|
183
185
|
const ok = initFromModule(wasmModule);
|
|
184
186
|
if (!ok) {
|
|
185
|
-
|
|
187
|
+
wlog("warn","wasm init failed, falling back to JS solver");
|
|
186
188
|
return solveFallback({ salt, target });
|
|
187
189
|
}
|
|
188
190
|
}
|
|
189
191
|
|
|
190
192
|
if (solve_pow_function === null) {
|
|
191
|
-
|
|
193
|
+
wlog("warn","no wasm module provided, falling back to JS solver");
|
|
192
194
|
return solveFallback({ salt, target });
|
|
193
195
|
}
|
|
194
196
|
|
|
@@ -203,7 +205,7 @@
|
|
|
203
205
|
durationMs: (endTime - startTime).toFixed(2),
|
|
204
206
|
});
|
|
205
207
|
} catch (error) {
|
|
206
|
-
|
|
208
|
+
wlog("error","solve_pow threw:", error.message || error);
|
|
207
209
|
|
|
208
210
|
self.postMessage({
|
|
209
211
|
found: false,
|