\n docs (apps, APIs, privacy, etc.) —\n mirror —\n stats ▼\n `,document.getElementById("outro").innerHTML=`\n What is an IP address?\n — Browse anonymously.\n
\n Plain text at\n 4.${mirror} (IPv4),\n 6.${mirror} (IPv6), &\n a.${mirror} (either).\n `,["v4","v6"].forEach(fetchIPData),(async()=>{const e=document.getElementById("headers"),t=document.getElementById("headers-loading");for(const a of mirrors)try{const n=await fetch(`https://${a}/headers`);if(!n.ok)continue;return e.classList.remove("loading"),e.innerHTML=await n.text(),void t.remove()}catch(e){console.error(`Failed to fetch headers from ${a}:`,e)}e.classList.remove("loading"),e.innerHTML="Failed to fetch headers",t.remove()})(),document.addEventListener("click",(async e=>{if(e.target.matches(".copy")){e.preventDefault();try{await navigator.clipboard.writeText(e.target.dataset.copy);const t=e.target.querySelector(".copy-icon");t.textContent="✅",setTimeout((()=>t.textContent="📋"),1e3)}catch(e){console.error("Failed to copy:",e)}}}));const showMapsCheckbox=document.getElementById("show-maps");function showGeolocateButton(){const e=document.getElementById("geolocate");e.style.display="block",e.onclick=()=>{getLocation(),e.remove()}}function setupCanvas(e){const t=window.devicePixelRatio||1,a=e.getBoundingClientRect();e.width=a.width*t,e.height=a.height*t;const n=e.getContext("2d");return n.scale(t,t),n}async function drawSparkline(e,t,a,n={}){const{color1:o="#4CAF50",color2:r="#2196F3",label1:s="reqs",label2:i="IPs",stacked:c=!1}=n,l=document.getElementById(e),d=setupCanvas(l),{width:m,height:h}=l.getBoundingClientRect();d.font="1em sans-serif";const u=d.measureText(`${s}: ${t[0].toLocaleString()}`),p=u.actualBoundingBoxAscent+u.actualBoundingBoxDescent,g=u.actualBoundingBoxAscent,f=2*(2+p),y=[];let w=null;function $(e,n,o,r=Math.max(...e),l=Math.min(...e)){const u=r-l;d.beginPath(),d.strokeStyle=n,d.lineWidth=2,e.forEach(((n,r)=>{const c=5+r*(m-10)/(e.length-1),p=h-5-(h-10)*(n-l)/u;y[r]||(y[r]={x:c}),y[r][s]=t[r],y[r][i]=a[r],y[r][o]=p,d[0===r?"moveTo":"lineTo"](c,p)})),d.stroke(),c&&(d.lineTo(m-5,h-5),d.lineTo(5,h-5),d.closePath(),d.fillStyle=`${n}33`,d.fill())}function v(){if(d.clearRect(0,0,m,h),c){const e=Math.max(...t.map(((e,t)=>e+a[t])));$(a,r,"y2",e,0),$(t.map(((e,t)=>e+a[t])),o,"y",e,0)}else $(t,o,"y"),$(a,r,"y2");if(w){d.font="1em sans-serif",d.textAlign="right",d.fillStyle="rgba(255, 255, 255, 0.5)";const e=d.measureText(`${s}: ${w[s].toLocaleString()}`).width+4;d.fillRect(m-e,2,e,f),[{label:s,color:o},{label:i,color:r}].forEach((({label:e,color:t},a)=>{d.fillStyle=t,d.fillText(`${e}: ${w[e].toLocaleString()}`,m-2,2+g+a*p)}))}}v(),l.addEventListener("mousemove",(e=>{const t=l.getBoundingClientRect(),a=e.clientX-t.left;w=y.reduce(((e,t)=>Math.abs(a-t.x){d.beginPath(),d.arc(w.x,e,4,0,2*Math.PI),d.fillStyle=t,d.fill()}))})),l.addEventListener("mouseleave",(()=>{w=null,v()}))}async function toggleStats(e){e&&e.preventDefault();const t=document.querySelector(".stats"),a=document.querySelector(".stats-link");!t.classList.contains("visible")?(a.classList.add("expanded"),t.classList.add("visible"),t.dataset.loaded||(await fetchAndDrawStats(),t.dataset.loaded="true")):(a.classList.remove("expanded"),t.classList.remove("visible"))}let resizeTimeout;async function fetchAndDrawStats(){const e=document.querySelector(".stats");try{const[t,a]=await Promise.all(mirrors.map((e=>fetch(`https://${e}/stats`).then((e=>e.json()))))),n=[t,a];e.innerHTML=[...mirrors.map((e=>`\n \n ${e} hourly
\n \n `)),...mirrors.map((e=>`\n \n ${e} daily
\n \n \n `)),...mirrors.map((e=>`\n \n ${e} user agents (sampled)
\n \n `))].join(""),await Promise.all(mirrors.flatMap(((e,t)=>[drawSparkline(`${e}-hourly`,n[t].hourly.reqs,n[t].hourly.ips),drawSparkline(`${e}-daily`,n[t].daily.reqs,n[t].daily.ips),drawSparkline(`${e}-daily-pertype`,n[t].daily.ipv4,n[t].daily.ipv6,{color1:"#E91E63",color2:"#9C27B0",label1:"IPv4",label2:"IPv6",stacked:!0})])));const o=e=>Object.entries(e).sort((([,e],[,t])=>t-e)).map((([e,t])=>`${escapeHTML(e)} (${t.toLocaleString()})`)).join(", ");mirrors.forEach(((e,t)=>{document.getElementById(`${e}-agents`).innerHTML=o(n[t].ua)}))}catch(t){console.error("Failed to load stats:",t),e.innerHTML='Failed to load stats
'}}function updateMaps(e){document.querySelectorAll(".map-container").forEach((t=>{if(e&&!t.querySelector("iframe")){const{lat:e,long:a}=t.dataset;t.innerHTML=createMapIframe(Number(e),Number(a))}else e||(t.innerHTML="")}))}async function getWebRTC(){const e=[];try{const t=new RTCPeerConnection({iceServers:[{urls:"stun:ident.me:3478"},{urls:"stun:tnedi.me:3478"}]});t.createDataChannel("");const a=await t.createOffer();await t.setLocalDescription(a),t.onicecandidate=({candidate:t})=>{if(!t)return;let a=t.address;a.startsWith("[")&&(a=a.slice(1,-1)),e.push(a),document.getElementById("webrtc").innerHTML=e.map((e=>`${e}
`)).join("")},setTimeout((()=>t.close()),1e4)}catch(e){document.getElementById("webrtc").innerHTML="Detection failed",console.error("WebRTC detection failed:",e)}}showMapsCheckbox.checked="true"===localStorage.getItem("showMaps"),showMapsCheckbox.addEventListener("change",(e=>{const t=e.target.checked;localStorage.setItem("showMaps",t),document.querySelectorAll(".map-container").forEach((e=>{e.innerHTML=t?createMapIframe(Number(e.dataset.lat),Number(e.dataset.long)):""}))})),"permissions"in navigator&&navigator.geolocation?navigator.permissions.query({name:"geolocation"}).then((e=>"granted"===e.state?getLocation():showGeolocateButton())):navigator.geolocation?showGeolocateButton():getLocation(),addEventListener("resize",(()=>{clearTimeout(resizeTimeout),resizeTimeout=setTimeout((()=>{document.querySelector(".stats").classList.contains("visible")&&fetchAndDrawStats()}),100)})),getWebRTC()