speedtest / index.html
KEXEL's picture
1.1
b559f3f verified
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<title>NETWORK SPEEDTEST</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="TESTE A VELOCIDADE DA SUA INTERNET COM NETWORK SPEEDTEST..." />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="application-name" content="NETWORK SPEEDTEST" />
<meta name="apple-mobile-web-app-title" content="NETWORK SPEEDTEST" />
<meta name="msapplication-starturl" content="/?Installed=speedtest" />
<meta name="theme-color" content="#222" />
<meta name="msapplication-navbutton-color" content="#222" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-touch-fullscreen" content="yes" />
<meta name="robots" content="index, follow" />
<meta name="googlebot" content="index, follow" />
<meta property="og:image" content="./d-framework/icon/icon/512/favicon.png" />
<link rel="icon" type="image/png" sizes="512x512" href="./d-framework/icon/512/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="512x512" href="./d-framework/icon/512/favicon.png" />
<link rel="icon" type="image/png" sizes="192x192" href="./d-framework/icon/192/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="192x192" href="./d-framework/icon/192/favicon.png" />
<link rel="icon" type="image/png" sizes="144x144" href="./d-framework/icon/144/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="144x144" href="./d-framework/icon/144/favicon.png" />
<link rel="icon" type="image/png" sizes="96x96" href="./d-framework/icon/96/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="96x96" href="./d-framework/icon/96/favicon.png" />
<link rel="icon" type="image/png" sizes="72x72" href="./d-framework/icon/72/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="72x72" href="./d-framework/icon/72/favicon.png" />
<link rel="icon" type="image/png" sizes="48x48" href="./d-framework/icon/48/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="48x48" href="./d-framework/icon/48/favicon.png" />
<link rel="icon" type="image/png" sizes="36x36" href="./d-framework/icon/36/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="36x36" href="./d-framework/icon/36/favicon.png" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6/css/all.min.css" />
<script src="https://cdn.jsdelivr.net/gh/davserv/d-framework@refs/heads/cdn.tailwindcss/tailwindcss.js"></script>
<script
src="data:text/plain;charset=utf-8;base64,dmFyIGNvbG9iZCA9ICIjMmIzMDM1YzciOyB2YXIgY29sb2xpcyA9ICIjNzI2ZDNiIjsgdmFyIGNvbG90eHQgPSAiI2ZmZjkiOwpkb2N1bWVudC53cml0ZSgnPHN0eWxlPi5wYWNley13ZWJraXQtcG9pbnRlci1ldmVudHM6bm9uZTtwb2ludGVyLWV2ZW50czpub25lOy13ZWJraXQtdXNlci1zZWxlY3Q6bm9uZTstbW96LXVzZXItc2VsZWN0Om5vbmU7dXNlci1zZWxlY3Q6bm9uZTt6LWluZGV4Ojk5OTk5OTk7cG9zaXRpb246Zml4ZWQ7bWFyZ2luOmF1dG87dG9wOjA7bGVmdDowO3JpZ2h0OjA7Ym90dG9tOjA7aGVpZ2h0OjEwMCU7d2lkdGg6MTAwJTtiYWNrZ3JvdW5kOicrY29sb2JkKyc7b3ZlcmZsb3c6aGlkZGVuO30ucGFjZTo6YmVmb3Jle2NvbnRlbnQ6IkNBUlJFR0FORE8uLi4iO2NvbG9yOicrY29sb3R4dCsnO3Bvc2l0aW9uOmFic29sdXRlO3RvcDo0NyU7bGVmdDo1MCU7LW1zLXRyYW5zZm9ybTp0cmFuc2xhdGUoLTUwJSwtNTAlKTt0cmFuc2Zvcm06dHJhbnNsYXRlKC01MCUsLTUwJSk7fS5wYWNlIC5wYWNlLXByb2dyZXNzey13ZWJraXQtYm94LXNpemluZzpib3JkZXItYm94Oy1tb3otYm94LXNpemluZzpib3JkZXItYm94Oy1tcy1ib3gtc2l6aW5nOmJvcmRlci1ib3g7LW8tYm94LXNpemluZzpib3JkZXItYm94O2JveC1zaXppbmc6Ym9yZGVyLWJveDstd2Via2l0LXRyYW5zZm9ybTp0cmFuc2xhdGUzZCgwLDAsMCk7LW1vei10cmFuc2Zvcm06dHJhbnNsYXRlM2QoMCwwLDApOy1tcy10cmFuc2Zvcm06dHJhbnNsYXRlM2QoMCwwLDApOy1vLXRyYW5zZm9ybTp0cmFuc2xhdGUzZCgwLDAsMCk7dHJhbnNmb3JtOnRyYW5zbGF0ZTNkKDAsMCwwKTttYXgtd2lkdGg6MTAwJTtwb3NpdGlvbjpmaXhlZDt6LWluZGV4OjIwMDA7ZGlzcGxheTpibG9jaztwb3NpdGlvbjphYnNvbHV0ZTtib3R0b206NTAlO3JpZ2h0OjEwMCU7aGVpZ2h0OjVweDt3aWR0aDoxMDAlO2JhY2tncm91bmQ6Jytjb2xvbGlzKyc7fS5wYWNlLnBhY2UtaW5hY3RpdmV7ZGlzcGxheTpub25lO308L3N0eWxlPicpOwooZnVuY3Rpb24oKXtmdW5jdGlvbiBvKHQsZSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIHQuYXBwbHkoZSxhcmd1bWVudHMpfX12YXIgdSxjLGksbix5LHQsbCx2LHIscyxhLGUscCx3LGIsaCxmLGQsZyxtLGssUyxxLHgsTCxQLFQsUixqLE8sRSxNLEEsQyxOLF8sRixVLFcsWCxELEgsSSx6LEcsQj1bXS5zbGljZSxKPXt9Lmhhc093blByb3BlcnR5LEs9ZnVuY3Rpb24odCxlKXtmb3IodmFyIG4gaW4gZSlKLmNhbGwoZSxuKSYmKHRbbl09ZVtuXSk7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1yZXR1cm4gci5wcm90b3R5cGU9ZS5wcm90b3R5cGUsdC5wcm90b3R5cGU9bmV3IHIsdC5fX3N1cGVyX189ZS5wcm90b3R5cGUsdH0sUT1bXS5pbmRleE9mfHxmdW5jdGlvbih0KXtmb3IodmFyIGU9MCxuPXRoaXMubGVuZ3RoO2U8bjtlKyspaWYoZSBpbiB0aGlzJiZ0aGlzW2VdPT09dClyZXR1cm4gZTtyZXR1cm4tMX07ZnVuY3Rpb24gVigpe31mb3IoZj17Y2xhc3NOYW1lOiIiLGNhdGNodXBUaW1lOjEwMCxpbml0aWFsUmF0ZTouMDMsbWluVGltZToyNTAsZ2hvc3RUaW1lOjEwMCxtYXhQcm9ncmVzc1BlckZyYW1lOjIwLGVhc2VGYWN0b3I6MS4yNSxzdGFydE9uUGFnZUxvYWQ6ITAscmVzdGFydE9uUHVzaFN0YXRlOiEwLHJlc3RhcnRPblJlcXVlc3RBZnRlcjo1MDAsdGFyZ2V0OiJib2R5IixlbGVtZW50czp7Y2hlY2tJbnRlcnZhbDoxMDAsc2VsZWN0b3JzOlsiYm9keSJdfSxldmVudExhZzp7bWluU2FtcGxlczoxMCxzYW1wbGVDb3VudDozLGxhZ1RocmVzaG9sZDozfSxhamF4Ont0cmFja01ldGhvZHM6WyJHRVQiXSx0cmFja1dlYlNvY2tldHM6ITAsaWdub3JlVVJMczpbXX19LEw9ZnVuY3Rpb24oKXt2YXIgdDtyZXR1cm4gbnVsbCE9KHQ9InVuZGVmaW5lZCIhPXR5cGVvZiBwZXJmb3JtYW5jZSYmbnVsbCE9PXBlcmZvcm1hbmNlJiYiZnVuY3Rpb24iPT10eXBlb2YgcGVyZm9ybWFuY2Uubm93P3BlcmZvcm1hbmNlLm5vdygpOnZvaWQgMCk/dDorbmV3IERhdGV9LFQ9d2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZXx8d2luZG93Lm1velJlcXVlc3RBbmltYXRpb25GcmFtZXx8d2luZG93LndlYmtpdFJlcXVlc3RBbmltYXRpb25GcmFtZXx8d2luZG93Lm1zUmVxdWVzdEFuaW1hdGlvbkZyYW1lLGg9d2luZG93LmNhbmNlbEFuaW1hdGlvbkZyYW1lfHx3aW5kb3cubW96Q2FuY2VsQW5pbWF0aW9uRnJhbWUsYT1mdW5jdGlvbih0LGUsbil7cmV0dXJuKCJmdW5jdGlvbiI9PXR5cGVvZiB0LmFkZEV2ZW50TGlzdGVuZXI/dC5hZGRFdmVudExpc3RlbmVyKGUsbiwhMSk6dm9pZCAwKXx8KHRbIm9uIitlXT1uKX0sbnVsbD09VCYmKFQ9ZnVuY3Rpb24odCl7cmV0dXJuIHNldFRpbWVvdXQodCw1MCl9LGg9ZnVuY3Rpb24odCl7cmV0dXJuIGNsZWFyVGltZW91dCh0KX0pLGo9ZnVuY3Rpb24oZSl7dmFyIG49TCgpLHI9ZnVuY3Rpb24oKXt2YXIgdD1MKCktbjtyZXR1cm4gMzM8PXQ/KG49TCgpLGUodCxmdW5jdGlvbigpe3JldHVybiBUKHIpfSkpOnNldFRpbWVvdXQociwzMy10KX07cmV0dXJuIHIoKX0sUj1mdW5jdGlvbigpe3ZhciB0PWFyZ3VtZW50c1swXSxlPWFyZ3VtZW50c1sxXSxuPTM8PWFyZ3VtZW50cy5sZW5ndGg/Qi5jYWxsKGFyZ3VtZW50cywyKTpbXTtyZXR1cm4iZnVuY3Rpb24iPT10eXBlb2YgdFtlXT90W2VdLmFwcGx5KHQsbik6dFtlXX0sZD1mdW5jdGlvbigpe2Zvcih2YXIgdCxlLG4scj1hcmd1bWVudHNbMF0scz0yPD1hcmd1bWVudHMubGVuZ3RoP0IuY2FsbChhcmd1bWVudHMsMSk6W10sbz0wLGk9cy5sZW5ndGg7bzxpO28rKylpZihlPXNbb10pZm9yKHQgaW4gZSlKLmNhbGwoZSx0KSYmKG49ZVt0XSxudWxsIT1yW3RdJiYib2JqZWN0Ij09dHlwZW9mIHJbdF0mJm51bGwhPW4mJiJvYmplY3QiPT10eXBlb2Ygbj9kKHJbdF0sbik6clt0XT1uKTtyZXR1cm4gcn0scD1mdW5jdGlvbih0KXtmb3IodmFyIGUsbixyPWU9MCxzPTAsbz10Lmxlbmd0aDtzPG87cysrKW49dFtzXSxyKz1NYXRoLmFicyhuKSxlKys7cmV0dXJuIHIvZX0sbT1mdW5jdGlvbih0LGUpe3ZhciBuLHI7aWYobnVsbD09dCYmKHQ9Im9wdGlvbnMiKSxudWxsPT1lJiYoZT0hMCkscj1kb2N1bWVudC5xdWVyeVNlbGVjdG9yKCJbZGF0YS1wYWNlLSIrdCsiXSIpKXtpZihuPXIuZ2V0QXR0cmlidXRlKCJkYXRhLXBhY2UtIit0KSwhZSlyZXR1cm4gbjt0cnl7cmV0dXJuIEpTT04ucGFyc2Uobil9Y2F0Y2godCl7cmV0dXJuInVuZGVmaW5lZCIhPXR5cGVvZiBjb25zb2xlJiZudWxsIT09Y29uc29sZT9jb25zb2xlLmVycm9yKCJFcnJvciBwYXJzaW5nIGlubGluZSBwYWNlIG9wdGlvbnMiLHQpOnZvaWQgMH19fSxWLnByb3RvdHlwZS5vbj1mdW5jdGlvbih0LGUsbixyKXt2YXIgcztyZXR1cm4gbnVsbD09ciYmKHI9ITEpLG51bGw9PXRoaXMuYmluZGluZ3MmJih0aGlzLmJpbmRpbmdzPXt9KSxudWxsPT0ocz10aGlzLmJpbmRpbmdzKVt0XSYmKHNbdF09W10pLHRoaXMuYmluZGluZ3NbdF0ucHVzaCh7aGFuZGxlcjplLGN0eDpuLG9uY2U6cn0pfSxWLnByb3RvdHlwZS5vbmNlPWZ1bmN0aW9uKHQsZSxuKXtyZXR1cm4gdGhpcy5vbih0LGUsbiwhMCl9LFYucHJvdG90eXBlLm9mZj1mdW5jdGlvbih0LGUpe3ZhciBuLHIscztpZihudWxsIT0obnVsbCE9KHI9dGhpcy5iaW5kaW5ncyk/clt0XTp2b2lkIDApKXtpZihudWxsPT1lKXJldHVybiBkZWxldGUgdGhpcy5iaW5kaW5nc1t0XTtmb3Iobj0wLHM9W107bjx0aGlzLmJpbmRpbmdzW3RdLmxlbmd0aDspdGhpcy5iaW5kaW5nc1t0XVtuXS5oYW5kbGVyPT09ZT9zLnB1c2godGhpcy5iaW5kaW5nc1t0XS5zcGxpY2UobiwxKSk6cy5wdXNoKG4rKyk7cmV0dXJuIHN9fSxWLnByb3RvdHlwZS50cmlnZ2VyPWZ1bmN0aW9uKCl7dmFyIHQsZSxuLHIscyxvLGk9YXJndW1lbnRzWzBdLGE9Mjw9YXJndW1lbnRzLmxlbmd0aD9CLmNhbGwoYXJndW1lbnRzLDEpOltdO2lmKG51bGwhPShyPXRoaXMuYmluZGluZ3MpJiZyW2ldKXtmb3Iobj0wLG89W107bjx0aGlzLmJpbmRpbmdzW2ldLmxlbmd0aDspZT0ocz10aGlzLmJpbmRpbmdzW2ldW25dKS5oYW5kbGVyLHQ9cy5jdHgscz1zLm9uY2UsZS5hcHBseShudWxsIT10P3Q6dGhpcyxhKSxzP28ucHVzaCh0aGlzLmJpbmRpbmdzW2ldLnNwbGljZShuLDEpKTpvLnB1c2gobisrKTtyZXR1cm4gb319LEc9Vix5PXdpbmRvdy5QYWNlfHx7fSx3aW5kb3cuUGFjZT15LGQoeSxHLnByb3RvdHlwZSksUD15Lm9wdGlvbnM9ZCh7fSxmLHdpbmRvdy5wYWNlT3B0aW9ucyxtKCkpLFc9MCxEPShJPVsiYWpheCIsImRvY3VtZW50IiwiZXZlbnRMYWciLCJlbGVtZW50cyJdKS5sZW5ndGg7VzxEO1crKykhMD09PVBbQT1JW1ddXSYmKFBbQV09ZltBXSk7ZnVuY3Rpb24gWSgpe3JldHVybiBZLl9fc3VwZXJfXy5jb25zdHJ1Y3Rvci5hcHBseSh0aGlzLGFyZ3VtZW50cyl9ZnVuY3Rpb24gWigpe3RoaXMucHJvZ3Jlc3M9MH1mdW5jdGlvbiAkKCl7dGhpcy5iaW5kaW5ncz17fX1mdW5jdGlvbiB0dCgpe3ZhciBlLG89dGhpczt0dC5fX3N1cGVyX18uY29uc3RydWN0b3IuYXBwbHkodGhpcyxhcmd1bWVudHMpLGU9ZnVuY3Rpb24ocil7dmFyIHM9ci5vcGVuO3JldHVybiByLm9wZW49ZnVuY3Rpb24odCxlLG4pe3JldHVybiBNKHQpJiZvLnRyaWdnZXIoInJlcXVlc3QiLHt0eXBlOnQsdXJsOmUscmVxdWVzdDpyfSkscy5hcHBseShyLGFyZ3VtZW50cyl9fSx3aW5kb3cuWE1MSHR0cFJlcXVlc3Q9ZnVuY3Rpb24odCl7dD1uZXcgVSh0KTtyZXR1cm4gZSh0KSx0fTt0cnl7Zyh3aW5kb3cuWE1MSHR0cFJlcXVlc3QsVSl9Y2F0Y2godCl7fWlmKG51bGwhPUYpe3dpbmRvdy5YRG9tYWluUmVxdWVzdD1mdW5jdGlvbigpe3ZhciB0PW5ldyBGO3JldHVybiBlKHQpLHR9O3RyeXtnKHdpbmRvdy5YRG9tYWluUmVxdWVzdCxGKX1jYXRjaCh0KXt9fWlmKG51bGwhPV8mJlAuYWpheC50cmFja1dlYlNvY2tldHMpe3dpbmRvdy5XZWJTb2NrZXQ9ZnVuY3Rpb24odCxlKXt2YXIgbj1udWxsIT1lP25ldyBfKHQsZSk6bmV3IF8odCk7cmV0dXJuIE0oInNvY2tldCIpJiZvLnRyaWdnZXIoInJlcXVlc3QiLHt0eXBlOiJzb2NrZXQiLHVybDp0LHByb3RvY29sczplLHJlcXVlc3Q6bn0pLG59O3RyeXtnKHdpbmRvdy5XZWJTb2NrZXQsXyl9Y2F0Y2godCl7fX19ZnVuY3Rpb24gZXQoKXt0aGlzLmNvbXBsZXRlPW8odGhpcy5jb21wbGV0ZSx0aGlzKTt2YXIgdD10aGlzO3RoaXMuZWxlbWVudHM9W10saygpLm9uKCJyZXF1ZXN0IixmdW5jdGlvbigpe3JldHVybiB0LndhdGNoLmFwcGx5KHQsYXJndW1lbnRzKX0pfWZ1bmN0aW9uIG50KHQpe3ZhciBlLG4scixzO2ZvcihudWxsPT10JiYodD17fSksdGhpcy5jb21wbGV0ZT1vKHRoaXMuY29tcGxldGUsdGhpcyksdGhpcy5lbGVtZW50cz1bXSxudWxsPT10LnNlbGVjdG9ycyYmKHQuc2VsZWN0b3JzPVtdKSxuPTAscj0ocz10LnNlbGVjdG9ycykubGVuZ3RoO248cjtuKyspZT1zW25dLHRoaXMuZWxlbWVudHMucHVzaChuZXcgaShlLHRoaXMuY29tcGxldGUpKX1mdW5jdGlvbiBydCh0LGUpe3RoaXMuc2VsZWN0b3I9dCx0aGlzLmNvbXBsZXRlQ2FsbGJhY2s9ZSx0aGlzLnByb2dyZXNzPTAsdGhpcy5jaGVjaygpfWZ1bmN0aW9uIHN0KCl7dmFyIHQsZSxuPXRoaXM7dGhpcy5wcm9ncmVzcz1udWxsIT0oZT10aGlzLnN0YXRlc1tkb2N1bWVudC5yZWFkeVN0YXRlXSk/ZToxMDAsdD1kb2N1bWVudC5vbnJlYWR5c3RhdGVjaGFuZ2UsZG9jdW1lbnQub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7cmV0dXJuIG51bGwhPW4uc3RhdGVzW2RvY3VtZW50LnJlYWR5U3RhdGVdJiYobi5wcm9ncmVzcz1uLnN0YXRlc1tkb2N1bWVudC5yZWFkeVN0YXRlXSksImZ1bmN0aW9uIj09dHlwZW9mIHQ/dC5hcHBseShudWxsLGFyZ3VtZW50cyk6dm9pZCAwfX1mdW5jdGlvbiBvdCh0KXt0aGlzLnNvdXJjZT10LHRoaXMubGFzdD10aGlzLnNpbmNlTGFzdFVwZGF0ZT0wLHRoaXMucmF0ZT1QLmluaXRpYWxSYXRlLHRoaXMuY2F0Y2h1cD0wLHRoaXMucHJvZ3Jlc3M9dGhpcy5sYXN0UHJvZ3Jlc3M9MCxudWxsIT10aGlzLnNvdXJjZSYmKHRoaXMucHJvZ3Jlc3M9Uih0aGlzLnNvdXJjZSwicHJvZ3Jlc3MiKSl9Rz1FcnJvcixLKFksRyksbj1ZLFoucHJvdG90eXBlLmdldEVsZW1lbnQ9ZnVuY3Rpb24oKXt2YXIgdDtpZihudWxsPT10aGlzLmVsKXtpZighKHQ9ZG9jdW1lbnQucXVlcnlTZWxlY3RvcihQLnRhcmdldCkpKXRocm93IG5ldyBuO3RoaXMuZWw9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2IiksdGhpcy5lbC5jbGFzc05hbWU9InBhY2UgcGFjZS1hY3RpdmUiLGRvY3VtZW50LmJvZHkuY2xhc3NOYW1lPWRvY3VtZW50LmJvZHkuY2xhc3NOYW1lLnJlcGxhY2UoLyhwYWNlLWRvbmUgKXwvLCJwYWNlLXJ1bm5pbmcgIik7dmFyIGU9IiIhPT1QLmNsYXNzTmFtZT8iICIrUC5jbGFzc05hbWU6IiI7dGhpcy5lbC5pbm5lckhUTUw9JzxkaXYgY2xhc3M9InBhY2UtcHJvZ3Jlc3MnK2UrJyI+XG4gIDxkaXYgY2xhc3M9InBhY2UtcHJvZ3Jlc3MtaW5uZXIiPjwvZGl2PlxuPC9kaXY+XG48ZGl2IGNsYXNzPSJwYWNlLWFjdGl2aXR5Ij48L2Rpdj4nLG51bGwhPXQuZmlyc3RDaGlsZD90Lmluc2VydEJlZm9yZSh0aGlzLmVsLHQuZmlyc3RDaGlsZCk6dC5hcHBlbmRDaGlsZCh0aGlzLmVsKX1yZXR1cm4gdGhpcy5lbH0sWi5wcm90b3R5cGUuZmluaXNoPWZ1bmN0aW9uKCl7dmFyIHQ9dGhpcy5nZXRFbGVtZW50KCk7cmV0dXJuIHQuY2xhc3NOYW1lPXQuY2xhc3NOYW1lLnJlcGxhY2UoInBhY2UtYWN0aXZlIiwicGFjZS1pbmFjdGl2ZSIpLGRvY3VtZW50LmJvZHkuY2xhc3NOYW1lPWRvY3VtZW50LmJvZHkuY2xhc3NOYW1lLnJlcGxhY2UoInBhY2UtcnVubmluZyAiLCJwYWNlLWRvbmUgIil9LFoucHJvdG90eXBlLnVwZGF0ZT1mdW5jdGlvbih0KXtyZXR1cm4gdGhpcy5wcm9ncmVzcz10LHkudHJpZ2dlcigicHJvZ3Jlc3MiLHQpLHRoaXMucmVuZGVyKCl9LFoucHJvdG90eXBlLmRlc3Ryb3k9ZnVuY3Rpb24oKXt0cnl7dGhpcy5nZXRFbGVtZW50KCkucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0aGlzLmdldEVsZW1lbnQoKSl9Y2F0Y2godCl7bj10fXJldHVybiB0aGlzLmVsPXZvaWQgMH0sWi5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIHQsZSxuLHIscyxvLGk7aWYobnVsbD09ZG9jdW1lbnQucXVlcnlTZWxlY3RvcihQLnRhcmdldCkpcmV0dXJuITE7Zm9yKHQ9dGhpcy5nZXRFbGVtZW50KCkscj0idHJhbnNsYXRlM2QoIit0aGlzLnByb2dyZXNzKyIlLCAwLCAwKSIscz0wLG89KGk9WyJ3ZWJraXRUcmFuc2Zvcm0iLCJtc1RyYW5zZm9ybSIsInRyYW5zZm9ybSJdKS5sZW5ndGg7czxvO3MrKyllPWlbc10sdC5jaGlsZHJlblswXS5zdHlsZVtlXT1yO3JldHVybighdGhpcy5sYXN0UmVuZGVyZWRQcm9ncmVzc3x8dGhpcy5sYXN0UmVuZGVyZWRQcm9ncmVzc3wwIT09dGhpcy5wcm9ncmVzc3wwKSYmKHQuY2hpbGRyZW5bMF0uc2V0QXR0cmlidXRlKCJkYXRhLXByb2dyZXNzLXRleHQiLCgwfHRoaXMucHJvZ3Jlc3MpKyIlIiksMTAwPD10aGlzLnByb2dyZXNzP249Ijk5Ijoobj10aGlzLnByb2dyZXNzPDEwPyIwIjoiIixuKz0wfHRoaXMucHJvZ3Jlc3MpLHQuY2hpbGRyZW5bMF0uc2V0QXR0cmlidXRlKCJkYXRhLXByb2dyZXNzIiwiIituKSkseS50cmlnZ2VyKCJjaGFuZ2UiLHRoaXMucHJvZ3Jlc3MpLHRoaXMubGFzdFJlbmRlcmVkUHJvZ3Jlc3M9dGhpcy5wcm9ncmVzc30sWi5wcm90b3R5cGUuZG9uZT1mdW5jdGlvbigpe3JldHVybiAxMDA8PXRoaXMucHJvZ3Jlc3N9LGM9WiwkLnByb3RvdHlwZS50cmlnZ2VyPWZ1bmN0aW9uKHQsZSl7dmFyIG4scixzLG8saTtpZihudWxsIT10aGlzLmJpbmRpbmdzW3RdKXtmb3IoaT1bXSxyPTAscz0obz10aGlzLmJpbmRpbmdzW3RdKS5sZW5ndGg7cjxzO3IrKyluPW9bcl0saS5wdXNoKG4uY2FsbCh0aGlzLGUpKTtyZXR1cm4gaX19LCQucHJvdG90eXBlLm9uPWZ1bmN0aW9uKHQsZSl7dmFyIG47cmV0dXJuIG51bGw9PShuPXRoaXMuYmluZGluZ3MpW3RdJiYoblt0XT1bXSksdGhpcy5iaW5kaW5nc1t0XS5wdXNoKGUpfSxtPSQsVT13aW5kb3cuWE1MSHR0cFJlcXVlc3QsRj13aW5kb3cuWERvbWFpblJlcXVlc3QsXz13aW5kb3cuV2ViU29ja2V0LGc9ZnVuY3Rpb24odCxlKXt2YXIgbixyPVtdO2ZvcihuIGluIGUucHJvdG90eXBlKXRyeXtudWxsPT10W25dJiYiZnVuY3Rpb24iIT10eXBlb2YgZVtuXT8iZnVuY3Rpb24iPT10eXBlb2YgT2JqZWN0LmRlZmluZVByb3BlcnR5P3IucHVzaChPYmplY3QuZGVmaW5lUHJvcGVydHkodCxuLHtnZXQ6ZnVuY3Rpb24odCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGUucHJvdG90eXBlW3RdfX0obiksY29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITB9KSk6ci5wdXNoKHRbbl09ZS5wcm90b3R5cGVbbl0pOnIucHVzaCh2b2lkIDApfWNhdGNoKHQpezB9cmV0dXJuIHJ9LHE9W10seS5pZ25vcmU9ZnVuY3Rpb24oKXt2YXIgdD1hcmd1bWVudHNbMF0sZT0yPD1hcmd1bWVudHMubGVuZ3RoP0IuY2FsbChhcmd1bWVudHMsMSk6W107cmV0dXJuIHEudW5zaGlmdCgiaWdub3JlIiksZT10LmFwcGx5KG51bGwsZSkscS5zaGlmdCgpLGV9LHkudHJhY2s9ZnVuY3Rpb24oKXt2YXIgdD1hcmd1bWVudHNbMF0sZT0yPD1hcmd1bWVudHMubGVuZ3RoP0IuY2FsbChhcmd1bWVudHMsMSk6W107cmV0dXJuIHEudW5zaGlmdCgidHJhY2siKSxlPXQuYXBwbHkobnVsbCxlKSxxLnNoaWZ0KCksZX0sTT1mdW5jdGlvbih0KXtpZihudWxsPT10JiYodD0iR0VUIiksInRyYWNrIj09PXFbMF0pcmV0dXJuImZvcmNlIjtpZighcS5sZW5ndGgmJlAuYWpheCl7aWYoInNvY2tldCI9PT10JiZQLmFqYXgudHJhY2tXZWJTb2NrZXRzKXJldHVybiEwO2lmKHQ9dC50b1VwcGVyQ2FzZSgpLDA8PVEuY2FsbChQLmFqYXgudHJhY2tNZXRob2RzLHQpKXJldHVybiEwfXJldHVybiExfSxLKHR0LG0pLHQ9dHQsWD1udWxsLEU9ZnVuY3Rpb24odCl7Zm9yKHZhciBlLG49UC5hamF4Lmlnbm9yZVVSTHMscj0wLHM9bi5sZW5ndGg7cjxzO3IrKylpZigic3RyaW5nIj09dHlwZW9mKGU9bltyXSkpe2lmKC0xIT09dC5pbmRleE9mKGUpKXJldHVybiEwfWVsc2UgaWYoZS50ZXN0KHQpKXJldHVybiEwO3JldHVybiExfSwoaz1mdW5jdGlvbigpe3JldHVybiBudWxsPT1YJiYoWD1uZXcgdCksWH0pKCkub24oInJlcXVlc3QiLGZ1bmN0aW9uKHQpe3ZhciBvLGk9dC50eXBlLGE9dC5yZXF1ZXN0LGU9dC51cmw7aWYoIUUoZSkpcmV0dXJuIHkucnVubmluZ3x8ITE9PT1QLnJlc3RhcnRPblJlcXVlc3RBZnRlciYmImZvcmNlIiE9PU0oaSk/dm9pZCAwOihvPWFyZ3VtZW50cywiYm9vbGVhbiI9PXR5cGVvZihlPVAucmVzdGFydE9uUmVxdWVzdEFmdGVyfHwwKSYmKGU9MCksc2V0VGltZW91dChmdW5jdGlvbigpe3ZhciB0LGUsbixyLHM9InNvY2tldCI9PT1pP2EucmVhZHlTdGF0ZTwxOjA8KHM9YS5yZWFkeVN0YXRlKSYmczw0O2lmKHMpe2Zvcih5LnJlc3RhcnQoKSxyPVtdLHQ9MCxlPShuPXkuc291cmNlcykubGVuZ3RoO3Q8ZTt0Kyspe2lmKChBPW5bdF0paW5zdGFuY2VvZiB1KXtBLndhdGNoLmFwcGx5KEEsbyk7YnJlYWt9ci5wdXNoKHZvaWQgMCl9cmV0dXJuIHJ9fSxlKSl9KSxldC5wcm90b3R5cGUud2F0Y2g9ZnVuY3Rpb24odCl7dmFyIGU9dC50eXBlLG49dC5yZXF1ZXN0LHQ9dC51cmw7aWYoIUUodCkpcmV0dXJuIG49bmV3KCJzb2NrZXQiPT09ZT9yOnMpKG4sdGhpcy5jb21wbGV0ZSksdGhpcy5lbGVtZW50cy5wdXNoKG4pfSxldC5wcm90b3R5cGUuY29tcGxldGU9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuZWxlbWVudHM9dGhpcy5lbGVtZW50cy5maWx0ZXIoZnVuY3Rpb24odCl7cmV0dXJuIHQhPT1lfSl9LHU9ZXQscz1mdW5jdGlvbihlLG4pe3ZhciB0LHIscyxvLGk9dGhpcztpZih0aGlzLnByb2dyZXNzPTAsbnVsbCE9d2luZG93LlByb2dyZXNzRXZlbnQpZm9yKGEoZSwicHJvZ3Jlc3MiLGZ1bmN0aW9uKHQpe3JldHVybiB0Lmxlbmd0aENvbXB1dGFibGU/aS5wcm9ncmVzcz0xMDAqdC5sb2FkZWQvdC50b3RhbDppLnByb2dyZXNzPWkucHJvZ3Jlc3MrKDEwMC1pLnByb2dyZXNzKS8yfSksdD0wLHI9KG89WyJsb2FkIiwiYWJvcnQiLCJ0aW1lb3V0IiwiZXJyb3IiXSkubGVuZ3RoO3Q8cjt0KyspYShlLG9bdF0sZnVuY3Rpb24oKXtyZXR1cm4gbihpKSxpLnByb2dyZXNzPTEwMH0pO2Vsc2Ugcz1lLm9ucmVhZHlzdGF0ZWNoYW5nZSxlLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpe3ZhciB0O3JldHVybiAwPT09KHQ9ZS5yZWFkeVN0YXRlKXx8ND09PXQ/KG4oaSksaS5wcm9ncmVzcz0xMDApOjM9PT1lLnJlYWR5U3RhdGUmJihpLnByb2dyZXNzPTUwKSwiZnVuY3Rpb24iPT10eXBlb2Ygcz9zLmFwcGx5KG51bGwsYXJndW1lbnRzKTp2b2lkIDB9fSxyPWZ1bmN0aW9uKHQsZSl7Zm9yKHZhciBuLHI9dGhpcyxzPXRoaXMucHJvZ3Jlc3M9MCxvPShuPVsiZXJyb3IiLCJvcGVuIl0pLmxlbmd0aDtzPG87cysrKWEodCxuW3NdLGZ1bmN0aW9uKCl7cmV0dXJuIGUociksci5wcm9ncmVzcz0xMDB9KX0sbnQucHJvdG90eXBlLmNvbXBsZXRlPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLmVsZW1lbnRzPXRoaXMuZWxlbWVudHMuZmlsdGVyKGZ1bmN0aW9uKHQpe3JldHVybiB0IT09ZX0pfSxHPW50LHJ0LnByb3RvdHlwZS5jaGVjaz1mdW5jdGlvbigpe3ZhciB0PXRoaXM7cmV0dXJuIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IodGhpcy5zZWxlY3Rvcik/dGhpcy5kb25lKCk6c2V0VGltZW91dChmdW5jdGlvbigpe3JldHVybiB0LmNoZWNrKCl9LFAuZWxlbWVudHMuY2hlY2tJbnRlcnZhbCl9LHJ0LnByb3RvdHlwZS5kb25lPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuY29tcGxldGVDYWxsYmFjayh0aGlzKSx0aGlzLmNvbXBsZXRlQ2FsbGJhY2s9bnVsbCx0aGlzLnByb2dyZXNzPTEwMH0saT1ydCxzdC5wcm90b3R5cGUuc3RhdGVzPXtsb2FkaW5nOjAsaW50ZXJhY3RpdmU6NTAsY29tcGxldGU6MTAwfSxLPXN0LG09ZnVuY3Rpb24oKXt2YXIgZSxuLHIscyxvLGk9dGhpczt0aGlzLnByb2dyZXNzPTAsbz1bXSxzPTAscj1MKCksbj1zZXRJbnRlcnZhbChmdW5jdGlvbigpe3ZhciB0PUwoKS1yLTUwO3JldHVybiByPUwoKSxvLnB1c2godCksby5sZW5ndGg+UC5ldmVudExhZy5zYW1wbGVDb3VudCYmby5zaGlmdCgpLGU9cChvKSwrK3M+PVAuZXZlbnRMYWcubWluU2FtcGxlcyYmZTxQLmV2ZW50TGFnLmxhZ1RocmVzaG9sZD8oaS5wcm9ncmVzcz0xMDAsY2xlYXJJbnRlcnZhbChuKSk6aS5wcm9ncmVzcz0zLyhlKzMpKjEwMH0sNTApfSxvdC5wcm90b3R5cGUudGljaz1mdW5jdGlvbih0LGUpe3JldHVybiBudWxsPT1lJiYoZT1SKHRoaXMuc291cmNlLCJwcm9ncmVzcyIpKSwxMDA8PWUmJih0aGlzLmRvbmU9ITApLGU9PT10aGlzLmxhc3Q/dGhpcy5zaW5jZUxhc3RVcGRhdGUrPXQ6KHRoaXMuc2luY2VMYXN0VXBkYXRlJiYodGhpcy5yYXRlPShlLXRoaXMubGFzdCkvdGhpcy5zaW5jZUxhc3RVcGRhdGUpLHRoaXMuY2F0Y2h1cD0oZS10aGlzLnByb2dyZXNzKS9QLmNhdGNodXBUaW1lLHRoaXMuc2luY2VMYXN0VXBkYXRlPTAsdGhpcy5sYXN0PWUpLGU+dGhpcy5wcm9ncmVzcyYmKHRoaXMucHJvZ3Jlc3MrPXRoaXMuY2F0Y2h1cCp0KSxlPTEtTWF0aC5wb3codGhpcy5wcm9ncmVzcy8xMDAsUC5lYXNlRmFjdG9yKSx0aGlzLnByb2dyZXNzKz1lKnRoaXMucmF0ZSp0LHRoaXMucHJvZ3Jlc3M9TWF0aC5taW4odGhpcy5sYXN0UHJvZ3Jlc3MrUC5tYXhQcm9ncmVzc1BlckZyYW1lLHRoaXMucHJvZ3Jlc3MpLHRoaXMucHJvZ3Jlc3M9TWF0aC5tYXgoMCx0aGlzLnByb2dyZXNzKSx0aGlzLnByb2dyZXNzPU1hdGgubWluKDEwMCx0aGlzLnByb2dyZXNzKSx0aGlzLmxhc3RQcm9ncmVzcz10aGlzLnByb2dyZXNzLHRoaXMucHJvZ3Jlc3N9LHY9b3QsYj1lPU49dz1PPUM9bnVsbCx5LnJ1bm5pbmc9ITEsUz1mdW5jdGlvbigpe2lmKFAucmVzdGFydE9uUHVzaFN0YXRlKXJldHVybiB5LnJlc3RhcnQoKX0sbnVsbCE9d2luZG93Lmhpc3RvcnkucHVzaFN0YXRlJiYoSD13aW5kb3cuaGlzdG9yeS5wdXNoU3RhdGUsd2luZG93Lmhpc3RvcnkucHVzaFN0YXRlPWZ1bmN0aW9uKCl7cmV0dXJuIFMoKSxILmFwcGx5KHdpbmRvdy5oaXN0b3J5LGFyZ3VtZW50cyl9KSxudWxsIT13aW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGUmJih6PXdpbmRvdy5oaXN0b3J5LnJlcGxhY2VTdGF0ZSx3aW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGU9ZnVuY3Rpb24oKXtyZXR1cm4gUygpLHouYXBwbHkod2luZG93Lmhpc3RvcnksYXJndW1lbnRzKX0pLGw9e2FqYXg6dSxlbGVtZW50czpHLGRvY3VtZW50OkssZXZlbnRMYWc6bX0sKHg9ZnVuY3Rpb24oKXt2YXIgdCxlLG4scixzLG8saSxhO2Zvcih5LnNvdXJjZXM9Qz1bXSxlPTAscj0obz1bImFqYXgiLCJlbGVtZW50cyIsImRvY3VtZW50IiwiZXZlbnRMYWciXSkubGVuZ3RoO2U8cjtlKyspITEhPT1QW3Q9b1tlXV0mJkMucHVzaChuZXcgbFt0XShQW3RdKSk7Zm9yKG49MCxzPShhPW51bGwhPShpPVAuZXh0cmFTb3VyY2VzKT9pOltdKS5sZW5ndGg7bjxzO24rKylBPWFbbl0sQy5wdXNoKG5ldyBBKFApKTtyZXR1cm4geS5iYXI9dz1uZXcgYyxPPVtdLE49bmV3IHZ9KSgpLHkuc3RvcD1mdW5jdGlvbigpe3JldHVybiB5LnRyaWdnZXIoInN0b3AiKSx5LnJ1bm5pbmc9ITEsdy5kZXN0cm95KCksYj0hMCxudWxsIT1lJiYoImZ1bmN0aW9uIj09dHlwZW9mIGgmJmgoZSksZT1udWxsKSx4KCl9LHkucmVzdGFydD1mdW5jdGlvbigpe3JldHVybiB5LnRyaWdnZXIoInJlc3RhcnQiKSx5LnN0b3AoKSx5LnN0YXJ0KCl9LHkuZ289ZnVuY3Rpb24oKXt2YXIgbTtyZXR1cm4geS5ydW5uaW5nPSEwLHcucmVuZGVyKCksbT1MKCksYj0hMSxlPWooZnVuY3Rpb24odCxlKXt3LnByb2dyZXNzO2Zvcih2YXIgbixyLHMsbyxpLGEsdSxjLGwscCxoPWE9MCxmPSEwLGQ9dT0wLGc9Qy5sZW5ndGg7dTxnO2Q9Kyt1KWZvcihBPUNbZF0saT1udWxsIT1PW2RdP09bZF06T1tkXT1bXSxzPWM9MCxsPShyPW51bGwhPShwPUEuZWxlbWVudHMpP3A6W0FdKS5sZW5ndGg7YzxsO3M9KytjKW89cltzXSxmJj0obz1udWxsIT1pW3NdP2lbc106aVtzXT1uZXcgdihvKSkuZG9uZSxvLmRvbmV8fChoKyssYSs9by50aWNrKHQpKTtyZXR1cm4gbj1hL2gsdy51cGRhdGUoTi50aWNrKHQsbikpLHcuZG9uZSgpfHxmfHxiPyh3LnVwZGF0ZSgxMDApLHkudHJpZ2dlcigiZG9uZSIpLHNldFRpbWVvdXQoZnVuY3Rpb24oKXtyZXR1cm4gdy5maW5pc2goKSx5LnJ1bm5pbmc9ITEseS50cmlnZ2VyKCJoaWRlIil9LE1hdGgubWF4KFAuZ2hvc3RUaW1lLE1hdGgubWF4KFAubWluVGltZS0oTCgpLW0pLDApKSkpOmUoKX0pfSx5LnN0YXJ0PWZ1bmN0aW9uKHQpe2QoUCx0KSx5LnJ1bm5pbmc9ITA7dHJ5e3cucmVuZGVyKCl9Y2F0Y2godCl7bj10fXJldHVybiBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIucGFjZSIpPyh5LnRyaWdnZXIoInN0YXJ0IikseS5nbygpKTpzZXRUaW1lb3V0KHkuc3RhcnQsNTApfSwiZnVuY3Rpb24iPT10eXBlb2YgZGVmaW5lJiZkZWZpbmUuYW1kP2RlZmluZShmdW5jdGlvbigpe3JldHVybiB5fSk6Im9iamVjdCI9PXR5cGVvZiBleHBvcnRzP21vZHVsZS5leHBvcnRzPXk6UC5zdGFydE9uUGFnZUxvYWQmJnkuc3RhcnQoKX0pLmNhbGwodGhpcyk7"></script>
<link rel="manifest" href="./manifest.json" />
<script
src="data:application/javascript;charset=utf-8;base64,KGZ1bmN0aW9uKCl7ZnVuY3Rpb24gcCgpe3ZhciBiPWRvY3VtZW50LmhlYWQucXVlcnlTZWxlY3RvcignbGlua1tyZWw9Im1hbmlmZXN0Il0nKSxhPWI/Yi5ocmVmOiIiO2lmKCFhKXRocm93J2NhblwndCBmaW5kIDxsaW5rIHJlbD0ibWFuaWZlc3QiIGhyZWY9Ii4uIiAvPlwnJzt2YXIgZD1BKFthLHdpbmRvdy5sb2NhdGlvbl0pLGU9bmV3IFhNTEh0dHBSZXF1ZXN0O2Uub3BlbigiR0VUIixhKTtlLndpdGhDcmVkZW50aWFscz0idXNlLWNyZWRlbnRpYWxzIj09PWIuZ2V0QXR0cmlidXRlKCJjcm9zc29yaWdpbiIpO2Uub25sb2FkPWZ1bmN0aW9uKCl7dHJ5e3ZhciBiPUpTT04ucGFyc2UoZS5yZXNwb25zZVRleHQpO0IoYixkKX1jYXRjaChrKXtjb25zb2xlLndhcm4oImVycm9yIixrKX19O2Uuc2VuZChudWxsKX1mdW5jdGlvbiBBKGIpe2Zvcih2YXIgYT17fSxkPTA7ZDxiLmxlbmd0aDthPXtjOmEuY30sKytkKXthLmM9YltkXTt0cnl7cmV0dXJuIG5ldyBVUkwoIiIsCmEuYyksZnVuY3Rpb24oYil7cmV0dXJuIGZ1bmN0aW9uKGEpe3JldHVybihuZXcgVVJMKGF8fCIiLGIuYykpLnRvU3RyaW5nKCl9fShhKX1jYXRjaChlKXt9fXJldHVybiBmdW5jdGlvbihiKXtyZXR1cm4gYnx8IiJ9fWZ1bmN0aW9uIHUoYixhKXtiPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoYik7Zm9yKHZhciBkIGluIGEpYi5zZXRBdHRyaWJ1dGUoZCxhW2RdKTtkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKGIpO3JldHVybiBifWZ1bmN0aW9uIGMoYixhKXthJiYoITA9PT1hJiYoYT0ieWVzIiksdSgibWV0YSIse25hbWU6Yixjb250ZW50OmF9KSl9ZnVuY3Rpb24gQihiLGEpe2Z1bmN0aW9uIGQoYSxkLGcpe3ZhciBlPWEud2lkdGgsYz1hLmhlaWdodDthPXdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvO3ZhciBmPXYoe3dpZHRoOmUqYSxoZWlnaHQ6YyphfSk7Zi5zY2FsZShhLGEpO2YuZmlsbFN0eWxlPWIuYmFja2dyb3VuZF9jb2xvcnx8IiNmOGY5ZmEiO2YuZmlsbFJlY3QoMCwwLGUsYyk7CmYudHJhbnNsYXRlKGUvMiwoYy0zMikvMik7ZyYmKGM9Zy53aWR0aC9hLGE9Zy5oZWlnaHQvYSwxMjg8YSYmKGMvPWEvMTI4LGE9MTI4KSw0ODw9YyYmNDg8PWEmJihmLmRyYXdJbWFnZShnLGMvLTIsYS8tMixjLGEpLGYudHJhbnNsYXRlKDAsYS8yKzMyKSkpO2YuZmlsbFN0eWxlPXQ/IndoaXRlIjoiYmxhY2siO2YuZm9udD0iMjRweCBIZWx2ZXRpY2FOZXVlLUNvbmRlbnNlZEJvbGQiO2c9Yi5uYW1lfHxiLnNob3J0X25hbWV8fGRvY3VtZW50LnRpdGxlO2E9Zi5tZWFzdXJlVGV4dChnKS53aWR0aDtpZihhPC44KmUpZi5maWxsVGV4dChnLGEvLTIsMCk7ZWxzZSBmb3IoZz1nLnNwbGl0KC9ccysvZyksYT0xO2E8PWcubGVuZ3RoOysrYSl7Yz1nLnNsaWNlKDAsYSkuam9pbigiICIpO3ZhciB3PWYubWVhc3VyZVRleHQoYykud2lkdGg7aWYoYT09PWcubGVuZ3RofHx3Pi42KmUpZi5maWxsVGV4dChjLHcvLTIsMCksZi50cmFuc2xhdGUoMCwyNCoxLjIpLGcuc3BsaWNlKDAsYSksYT0wfXJldHVybiBmdW5jdGlvbigpe3ZhciBhPQpkb2N1bWVudC5jcmVhdGVFbGVtZW50KCJsaW5rIik7YS5zZXRBdHRyaWJ1dGUoInJlbCIsImFwcGxlLXRvdWNoLXN0YXJ0dXAtaW1hZ2UiKTthLnNldEF0dHJpYnV0ZSgibWVkaWEiLCIob3JpZW50YXRpb246ICIrZCsiKSIpO2Euc2V0QXR0cmlidXRlKCJocmVmIixmLmNhbnZhcy50b0RhdGFVUkwoKSk7cmV0dXJuIGF9fWZ1bmN0aW9uIGUoYSl7dmFyIGI9ZCh3aW5kb3cuc2NyZWVuLCJwb3J0cmFpdCIsYSksYz1kKHt3aWR0aDp3aW5kb3cuc2NyZWVuLmhlaWdodCxoZWlnaHQ6d2luZG93LnNjcmVlbi53aWR0aH0sImxhbmRzY2FwZSIsYSk7d2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKXtkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKGIoKSk7d2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKXtkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKGMoKSl9LDEwKX0sMTApfXZhciBoPWIuaWNvbnN8fFtdO2guc29ydChmdW5jdGlvbihhLGIpe3JldHVybiBwYXJzZUludChiLnNpemVzLDEwKS0KcGFyc2VJbnQoYS5zaXplcywxMCl9KTt2YXIgaz1oLm1hcChmdW5jdGlvbihiKXt2YXIgZD17cmVsOiJpY29uIixocmVmOmEoYi5zcmMpLHNpemVzOmIuc2l6ZXN9O3UoImxpbmsiLGQpO2lmKHEmJiEoMTIwPnBhcnNlSW50KGIuc2l6ZXMsMTApKSlyZXR1cm4gZC5yZWw9ImFwcGxlLXRvdWNoLWljb24iLHUoImxpbmsiLGQpfSkuZmlsdGVyKEJvb2xlYW4pO2subGVuZ3RoJiZrW2subGVuZ3RoLTFdLnJlbW92ZUF0dHJpYnV0ZSgic2l6ZXMiKTt2YXIgbT1kb2N1bWVudC5oZWFkLnF1ZXJ5U2VsZWN0b3IoJ21ldGFbbmFtZT0idmlld3BvcnQiXScpLHA9ISEobSYmbS5jb250ZW50fHwiIikubWF0Y2goL1xidmlld3BvcnQtZml0XHMqPVxzKmNvdmVyXGIvKSxyPWIuZGlzcGxheTttPS0xIT09Qy5pbmRleE9mKHIpO2MoIm1vYmlsZS13ZWItYXBwLWNhcGFibGUiLG0pO0QoYi50aGVtZV9jb2xvcnx8ImJsYWNrIixwKTtFJiYoYygiYXBwbGljYXRpb24tbmFtZSIsYi5zaG9ydF9uYW1lKSxjKCJtc2FwcGxpY2F0aW9uLXRvb2x0aXAiLApiLmRlc2NyaXB0aW9uKSxjKCJtc2FwcGxpY2F0aW9uLXN0YXJ0dXJsIixhKGIuc3RhcnRfdXJsfHwiLiIpKSxjKCJtc2FwcGxpY2F0aW9uLW5hdmJ1dHRvbi1jb2xvciIsYi50aGVtZV9jb2xvciksKGg9aFswXSkmJmMoIm1zYXBwbGljYXRpb24tVGlsZUltYWdlIixhKGguc3JjKSksYygibXNhcHBsaWNhdGlvbi1UaWxlQ29sb3IiLGIuYmFja2dyb3VuZF9jb2xvcikpO2RvY3VtZW50LmhlYWQucXVlcnlTZWxlY3RvcignW25hbWU9InRoZW1lLWNvbG9yIl0nKXx8YygidGhlbWUtY29sb3IiLGIudGhlbWVfY29sb3IpO2lmKHEpe3ZhciB0PXgoYi5iYWNrZ3JvdW5kX2NvbG9yfHwiI2Y4ZjlmYSIpOyhyPUYoYi5yZWxhdGVkX2FwcGxpY2F0aW9ucykpJiZjKCJhcHBsZS1pdHVuZXMtYXBwIiwiYXBwLWlkPSIrcik7YygiYXBwbGUtbW9iaWxlLXdlYi1hcHAtY2FwYWJsZSIsbSk7YygiYXBwbGUtbW9iaWxlLXdlYi1hcHAtdGl0bGUiLGIuc2hvcnRfbmFtZXx8Yi5uYW1lKTt2YXIgbj1rWzBdLApsPW5ldyBJbWFnZTtsLmNyb3NzT3JpZ2luPSJhbm9ueW1vdXMiO2wub25lcnJvcj1mdW5jdGlvbigpe2UoKX07aWYoay5sZW5ndGgpbC5vbmxvYWQ9ZnVuY3Rpb24oKXtlKGwpO2lmKGIuYmFja2dyb3VuZF9jb2xvcil7dmFyIGE9eShsLGIuYmFja2dyb3VuZF9jb2xvcik7YSYmKG4uaHJlZj1hLGsuc2xpY2UoMSkuZm9yRWFjaChmdW5jdGlvbihhKXt2YXIgZD1uZXcgSW1hZ2U7ZC5jcm9zc09yaWdpbj0iYW5vbnltb3VzIjtkLm9ubG9hZD1mdW5jdGlvbigpe3ZhciBjPXkoZCxiLmJhY2tncm91bmRfY29sb3IsITApO2EuaHJlZj1jfTtkLnNyYz1hLmhyZWZ9KSl9fSxsLnNyYz1uLmhyZWY7ZWxzZSBsLm9uZXJyb3IoKX1lbHNlIGg9e3BvcjoicG9ydHJhaXQiLGxhbjoibGFuZHNjYXBlIn1bU3RyaW5nKGIub3JpZW50YXRpb258fCIiKS5zdWJzdHIoMCwzKV18fCIiLGMoIng1LW9yaWVudGF0aW9uIixoKSxjKCJzY3JlZW4tb3JpZW50YXRpb24iLGgpLCJmdWxsc2NyZWVuIj09PXI/KGMoIng1LWZ1bGxzY3JlZW4iLAoidHJ1ZSIpLGMoImZ1bGwtc2NyZWVuIiwieWVzIikpOm0mJihjKCJ4NS1wYWdlLW1vZGUiLCJhcHAiKSxjKCJicm93c2VybW9kZSIsImFwcGxpY2F0aW9uIikpfWZ1bmN0aW9uIEYoYil7dmFyIGE7KGJ8fFtdKS5maWx0ZXIoZnVuY3Rpb24oYSl7cmV0dXJuIml0dW5lcyI9PT1hLnBsYXRmb3JtfSkuZm9yRWFjaChmdW5jdGlvbihiKXtiLmlkP2E9Yi5pZDooYj1iLnVybC5tYXRjaCgvaWQoXGQrKS8pKSYmKGE9YlsxXSl9KTtyZXR1cm4gYX1mdW5jdGlvbiBEKGIsYSl7aWYocXx8Ryl7dmFyIGQ9eChiKTtpZihxKWMoImFwcGxlLW1vYmlsZS13ZWItYXBwLXN0YXR1cy1iYXItc3R5bGUiLGE/ImJsYWNrLXRyYW5zbHVjZW50IjpkPyJibGFjayI6ImRlZmF1bHQiKTtlbHNle2E6e3RyeXt2YXIgZT1XaW5kb3dzLlVJLlZpZXdNYW5hZ2VtZW50LkFwcGxpY2F0aW9uVmlldy5nZXRGb3JDdXJyZW50VmlldygpLnRpdGxlQmFyO2JyZWFrIGF9Y2F0Y2goaCl7fWU9dm9pZCAwfWlmKGE9ZSlhLmZvcmVncm91bmRDb2xvcj0KdChkPyJibGFjayI6IndoaXRlIiksYS5iYWNrZ3JvdW5kQ29sb3I9dChiKX19fWZ1bmN0aW9uIHQoYil7Yj1uKGIpO3JldHVybntyOmJbMF0sZzpiWzFdLGI6YlsyXSxhOmJbM119fWZ1bmN0aW9uIG4oYil7dmFyIGE9digpO2EuZmlsbFN0eWxlPWI7YS5maWxsUmVjdCgwLDAsMSwxKTtyZXR1cm4gYS5nZXRJbWFnZURhdGEoMCwwLDEsMSkuZGF0YX1mdW5jdGlvbiB4KGIpe2I9bihiKS5tYXAoZnVuY3Rpb24oYSl7YS89MjU1O3JldHVybi4wMzkyOD5hP2EvMTIuOTI6TWF0aC5wb3coKGErLjA1NSkvMS4wNTUsMi40KX0pO3JldHVybiAzPE1hdGguYWJzKDEuMDUvKC4yMTI2KmJbMF0rLjcxNTIqYlsxXSsuMDcyMipiWzJdKy4wNSkpfWZ1bmN0aW9uIHkoYixhLGMpe2M9dm9pZCAwPT09Yz8hMTpjO3ZhciBkPXYoYik7ZC5kcmF3SW1hZ2UoYiwwLDApO2lmKGN8fDI1NSE9ZC5nZXRJbWFnZURhdGEoMCwwLDEsMSkuZGF0YVszXSlyZXR1cm4gZC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb249CiJkZXN0aW5hdGlvbi1vdmVyIixkLmZpbGxTdHlsZT1hLGQuZmlsbFJlY3QoMCwwLGIud2lkdGgsYi5oZWlnaHQpLGQuY2FudmFzLnRvRGF0YVVSTCgpfWZ1bmN0aW9uIHYoYil7Yj12b2lkIDA9PT1iP3t3aWR0aDoxLGhlaWdodDoxfTpiO3ZhciBhPWIuaGVpZ2h0LGM9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiY2FudmFzIik7Yy53aWR0aD1iLndpZHRoO2MuaGVpZ2h0PWE7cmV0dXJuIGMuZ2V0Q29udGV4dCgiMmQiKX1pZigib25sb2FkImluIFhNTEh0dHBSZXF1ZXN0LnByb3RvdHlwZSYmIW5hdmlnYXRvci5mKXt2YXIgQz1bInN0YW5kYWxvbmUiLCJmdWxsc2NyZWVuIiwibWluaW1hbC11aSJdLHo9bmF2aWdhdG9yLnVzZXJBZ2VudHx8IiIscT1uYXZpZ2F0b3IudmVuZG9yJiYtMSE9PW5hdmlnYXRvci52ZW5kb3IuaW5kZXhPZigiQXBwbGUiKSYmLTEhPT16LmluZGV4T2YoIk1vYmlsZS8iKSxFPSEhei5tYXRjaCgvKE1TSUUgfEVkZ2VcL3xUcmlkZW50XC8pLyksRz0idW5kZWZpbmVkIiE9PQp0eXBlb2YgV2luZG93czsiY29tcGxldGUiPT09ZG9jdW1lbnQucmVhZHlTdGF0ZT9wKCk6d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoImxvYWQiLHApfX0pKCk7"></script>
<script> if (navigator.serviceWorker) { navigator.serviceWorker.register } </script>
<style>
.boxdbshadow {
box-shadow: 0 0 4px rgba(0, 0, 0, 0.14), 0 4px 8px rgba(0, 0, 0, 0.28) !important;
}
.boxdbshadowy {
box-shadow: 0 -9px 9px 0 rgba(0, 0, 0, 0.301),
0 6px 20px 0 rgba(0, 0, 0, 0.19) !important;
}
.boxdtext {
text-shadow: 1px 1px 2px #111 !important;
}
.bg-hover:hover,
.bg-hover:focus,
.bg-hover:active,
.bg-hover:target {
opacity: 0.45 !important;
}
.gauge {
position: relative;
width: 300px;
height: 150px;
margin: 0 auto;
}
.gauge-body {
width: 100%;
height: 0;
padding-bottom: 50%;
position: relative;
border-top-left-radius: 100% 200%;
border-top-right-radius: 100% 200%;
overflow: hidden;
background: #e0e0e0;
}
.gauge-fill {
position: absolute;
top: 100%;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg, #4ade80, #3b82f6, #ef4444);
transform-origin: center top;
transform: rotate(0.5turn);
transition: transform 0.5s ease-out;
}
.gauge-cover {
width: 75%;
height: 77%;
background: white;
/*border-radius: 50%;*/
position: absolute;
top: 25%;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
font-weight: bold;
color: #333;
border-top-left-radius: 110px;
border-top-right-radius: 110px;
border-bottom-right-radius: 0px;
border-bottom-left-radius: 0px;
}
.progress-bar {
height: 10px;
background-color: #e0e0e0;
border-radius: 5px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #4ade80, #3b82f6);
width: 0%;
transition: width 0.3s ease;
}
@keyframes pulse {
0% {
opacity: 1;
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}
.pulse {
animation: pulse 1.5s infinite;
}
.test-btn {
transition: all 0.3s ease;
}
.test-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body>
<div class="bg-gray-50 min-h-screen flex flex-col">
<!-- MENU -->
<div class="fixed top-0 left-0 z-50 w-72 h-screen bg-gray-800 text-white transform -translate-x-full transition-transform duration-300 ease-in-out" id="offcanvasmenu" aria-labelledby="offcanvasmenuLabel">
<div class="flex justify-between items-center p-4 shadow-xl bg-gray-800">
<h5 class="text-lg font-bold flex items-center" id="offcanvasmenuLabel">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path>
</svg>
MENU
</h5>
<button type="button" class="text-white hover:text-gray-400" onclick="document.getElementById('offcanvasmenu').classList.add('-translate-x-full')">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<div class="p-4 overflow-y-auto">
<div class="text-sm font-light uppercase">
❝ Aplicativos para várias plataformas by Developer Davidsonbpe.❞
</div>
<hr class="my-4 border-gray-700">
<div class="space-y-2">
<button onclick="window.open('https://oisa.speedtestcustom.com/')" class="w-full py-2 px-4 bg-gray-700 hover:bg-gray-600 text-left text-sm uppercase text-gray-400 rounded-none opacity-75 shadow">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline-block mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path>
</svg>
SpeedTestCustom
</button>
<button onclick="window.open('https://github.com/davidsonbpe')" class="w-full py-2 px-4 bg-gray-700 hover:bg-gray-600 text-left text-sm uppercase text-gray-400 rounded-none opacity-75 shadow">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline-block mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path>
</svg>
GitHub
</button>
<button onclick="window.open('https://codepen.io/davidsonbpe')" class="w-full py-2 px-4 bg-gray-700 hover:bg-gray-600 text-left text-sm uppercase text-gray-400 rounded-none opacity-75 shadow">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline-block mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path>
</svg>
CodePen
</button>
<button onclick="window.open('https://pag.ae/7Y3uUnhg8')" class="w-full py-2 px-4 bg-gray-700 hover:bg-gray-600 text-left text-sm uppercase text-gray-400 rounded-none opacity-75 shadow">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline-block mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path>
</svg>
Doar com
</button>
<button onclick="alert(document.title + ' | ' + document.querySelector('meta[name=description]').getAttribute('content'))" class="w-full py-2 px-4 bg-gray-700 hover:bg-gray-600 text-left text-sm uppercase text-gray-400 rounded-none opacity-75 shadow">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline-block mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path>
</svg>
Informar
</button>
<button onclick="window.open('https://davidsonbpe.blogspot.com/')" class="w-full py-2 px-4 bg-gray-700 hover:bg-gray-600 text-left text-sm uppercase text-gray-400 rounded-none opacity-75 shadow">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline-block mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path>
</svg>
Developer
</button>
<button onclick="sharesbutton()" class="w-full py-2 px-4 bg-gray-700 hover:bg-gray-600 text-left text-sm uppercase text-gray-400 rounded-none opacity-75 shadow">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline-block mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path>
</svg>
Compartilhar
</button>
</div>
</div>
<div class="p-4 border-t border-gray-700 absolute bottom-0 w-full inset-shadow-sm">
<button onclick="document.getElementById('offcanvasmenu').classList.add('-translate-x-full')" class="float-right py-2 px-4 bg-gray-700 hover:bg-gray-600 text-sm uppercase text-gray-400 rounded-none opacity-75 shadow">
Sair
</button>
</div>
</div>
<div class="fixed top-0 left-0 z-40 w-full flex items-center bg-gray-800 text-white boxdbshadow">
<img src="./d-framework/icon/144/favicon.png" alt="Menu" class="w-14 h-14 cursor-pointer hover:bg-gray-700 bg-gray-600" onclick="document.getElementById('offcanvasmenu').classList.remove('-translate-x-full')" />
<div class="flex-grow">
<select id="mySelects" class="w-full py-2 px-4 bg-gray-800 text-white text-xl uppercase border-none focus:outline-none font-sans">
<option value="javascript:location.reload();">SPEEDTEST HOME</option>
<option value="javascript:sharesbutton();">COMPARTILHAR</option>
<option value="javascript:window.open('https://dpripol.pages.dev/?='+document.title+'');">PRIVACY POLICY</option>
<option value="javascript:window.open('https://pag.ae/7Y3uUnhg8');">DOAR COM</option>
</select>
</div>
<button onclick="sharesbutton()" class="py-2 px-4 bg-gray-800 hover:bg-gray-700 text-yellow-500 text-xl border-l border-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" height="24px" viewBox="0 0 24 24" width="24px" fill="#31c214">
<path d="M0 0h24v24H0z" fill="none" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92s-1.31-2.92-2.92-2.92z" />
</svg>
</button>
</div>
<div class="container mt-14"></div>
<header class="bg-white shadow-sm py-4">
<div class="container mx-auto px-4">
<h1 class="text-3xl font-bold text-center text-indigo-600">
<i class="fas fa-tachometer-alt mr-2"></i>Network Speed Test
</h1>
</div>
</header>
<main class="flex-grow container mx-auto px-4 py-8">
<div class="max-w-3xl mx-auto bg-white rounded-xl shadow-md overflow-hidden p-6">
<div class="text-center mb-8">
<h2 class="text-2xl font-semibold text-gray-800">Teste a velocidade da sua Internet</h2>
<p class="text-gray-600 mt-2">Medir sua velocidade de download, upload e ping</p>
</div>
<div class="flex flex-col md:flex-row justify-around items-center mb-8">
<div class="gauge mb-8 md:mb-0">
<div class="gauge-body">
<div class="gauge-fill" id="downloadGauge"></div>
</div>
<div class="gauge-cover" id="downloadSpeed">0 Mbps</div>
</div>
<div class="gauge">
<div class="gauge-body">
<div class="gauge-fill" id="uploadGauge"></div>
</div>
<div class="gauge-cover" id="uploadSpeed">0 Mbps</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
<div class="bg-gray-50 p-4 rounded-lg text-center">
<div class="text-gray-500 mb-1"><i class="fas fa-download mr-2"></i>Download</div>
<div class="text-2xl font-bold text-indigo-600" id="finalDownload">0 Mbps</div>
</div>
<div class="bg-gray-50 p-4 rounded-lg text-center">
<div class="text-gray-500 mb-1"><i class="fas fa-upload mr-2"></i>Upload</div>
<div class="text-2xl font-bold text-indigo-600" id="finalUpload">0 Mbps</div>
</div>
<div class="bg-gray-50 p-4 rounded-lg text-center">
<div class="text-gray-500 mb-1"><i class="fas fa-stopwatch mr-2"></i>Ping</div>
<div class="text-2xl font-bold text-indigo-600" id="pingResult">0 ms</div>
</div>
</div>
<div class="mb-6">
<div class="flex justify-between mb-1">
<span class="text-gray-700">Progresso do teste</span>
<span class="text-gray-700" id="testStatus">Preparar</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="testProgress"></div>
</div>
</div>
<div class="text-center">
<button id="startTest" class="test-btn bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-8 rounded-full text-lg transition-all duration-300">
<i class="fas fa-play mr-2"></i>Start Test
</button>
</div>
<div class="mt-8 bg-blue-50 border-l-4 border-blue-500 p-4 rounded hidden" id="tips">
<div class="flex">
<div class="flex-shrink-0 text-blue-500">
<i class="fas fa-info-circle text-xl"></i>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-blue-800">Dicas para resultados precisos</h3>
<div class="mt-2 text-sm text-blue-700">
<p>• Feche outras abas e aplicativos</p>
<p>• Conecte-se diretamente ao seu roteador com Ethernet, se possível</p>
<p>• Interrompa qualquer download ou upload em andamento</p>
</div>
</div>
</div>
</div>
</div>
<div class="max-w-3xl mx-auto bg-white rounded-xl shadow-md overflow-hidden p-6 mt-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4"><i class="fas fa-history mr-2"></i>Test History</h3>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Download</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Upload</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Ping</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200" id="historyTable">
<!-- History will be populated here -->
</tbody>
</table>
</div>
</div>
<div class="max-w-3xl mx-auto bg-white rounded-xl shadow-md overflow-hidden p-6 mt-8">
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<p class="text-lg md:text-xl font-medium text-gray-800">
<i class="fas fa-shield-alt text-emerald-500 mr-2"></i>
Política de privacidade para usar nosso Serviço e as escolhas que você tem associado!
</p>
<button
onclick="javascript:window.open('https://dpripol.pages.dev/?='+document.title+'')"
title="PRIVACY POLICY"
class="btn-hover-effect btn-active-effect transition-all duration-300 bg-emerald-500 hover:bg-emerald-600 text-white font-semibold px-8 py-3 rounded-full shadow-md focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-opacity-50">
<i class="fas fa-lock-open mr-2"></i>
PRIVACY POLICY
</button>
</div>
</div>
</main>
<footer class="bg-white shadow-sm py-4 mt-8">
<div class="container mx-auto px-4 text-center text-gray-500 text-sm uppercase">
<p>© <span id="datacedencer">2009</span> Speed Test | Todos os direitos reservados</p>
</div>
</footer>
<script>
document.addEventListener("DOMContentLoaded", function () {
const startTestBtn = document.getElementById("startTest");
const downloadSpeed = document.getElementById("downloadSpeed");
const uploadSpeed = document.getElementById("uploadSpeed");
const finalDownload = document.getElementById("finalDownload");
const finalUpload = document.getElementById("finalUpload");
const pingResult = document.getElementById("pingResult");
const testStatus = document.getElementById("testStatus");
const testProgress = document.getElementById("testProgress");
const downloadGauge = document.getElementById("downloadGauge");
const uploadGauge = document.getElementById("uploadGauge");
const historyTable = document.getElementById("historyTable");
const tipsSection = document.getElementById("tips");
let testInProgress = false;
let testHistory = JSON.parse(localStorage.getItem("speedTestHistory")) || [];
// Display test history
renderHistory();
startTestBtn.addEventListener("click", function () {
if (testInProgress) return;
startTest();
});
function startTest() {
testInProgress = true;
startTestBtn.disabled = true;
startTestBtn.innerHTML =
'<i class="fas fa-spinner fa-spin mr-2"></i>Testing...';
startTestBtn.classList.remove("bg-indigo-600", "hover:bg-indigo-700");
startTestBtn.classList.add("bg-gray-400", "cursor-not-allowed");
// Reset values
downloadSpeed.textContent = "0 Mbps";
uploadSpeed.textContent = "0 Mbps";
finalDownload.textContent = "0 Mbps";
finalUpload.textContent = "0 Mbps";
pingResult.textContent = "0 ms";
testStatus.textContent = "Starting...";
testProgress.style.width = "0%";
downloadGauge.style.transform = "rotate(0.5turn)";
uploadGauge.style.transform = "rotate(0.5turn)";
tipsSection.classList.add("hidden");
// Show pulse animation on gauges
downloadGauge.classList.add("pulse");
uploadGauge.classList.add("pulse");
// Start tests in sequence
setTimeout(() => {
testPing()
.then((ping) => {
pingResult.textContent = ping + " ms";
testStatus.textContent = "Testing download speed...";
testProgress.style.width = "30%";
return testDownloadSpeed();
})
.then((downloadSpeedValue) => {
const roundedDownload = Math.round(downloadSpeedValue * 10) / 10;
finalDownload.textContent = roundedDownload + " Mbps";
testStatus.textContent = "Testing upload speed...";
testProgress.style.width = "70%";
// Update gauge
const downloadAngle = Math.min(0.5 + downloadSpeedValue / 200, 1);
downloadGauge.style.transform = `rotate(${downloadAngle}turn)`;
downloadGauge.classList.remove("pulse");
return testUploadSpeed();
})
.then((uploadSpeedValue) => {
const roundedUpload = Math.round(uploadSpeedValue * 10) / 10;
finalUpload.textContent = roundedUpload + " Mbps";
testStatus.textContent = "Test complete!";
testProgress.style.width = "100%";
// Update gauge
const uploadAngle = Math.min(0.5 + uploadSpeedValue / 50, 1);
uploadGauge.style.transform = `rotate(${uploadAngle}turn)`;
uploadGauge.classList.remove("pulse");
// Save to history
saveTestResult(
roundedDownload,
roundedUpload,
pingResult.textContent
);
// Reset button
resetTestButton();
})
.catch((error) => {
console.error("Test failed:", error);
testStatus.textContent = "Test failed. Try again.";
testStatus.classList.add("text-red-500");
resetTestButton();
});
}, 1000);
}
function resetTestButton() {
testInProgress = false;
startTestBtn.disabled = false;
startTestBtn.innerHTML = '<i class="fas fa-sync-alt mr-2"></i>Test Again';
startTestBtn.classList.remove("bg-gray-400", "cursor-not-allowed");
startTestBtn.classList.add("bg-indigo-600", "hover:bg-indigo-700");
// Show tips
tipsSection.classList.remove("hidden");
}
function testPing() {
return new Promise((resolve) => {
// Simulate ping test with random value (real implementation would use actual ping)
const start = new Date().getTime();
setTimeout(() => {
const latency = Math.floor(Math.random() * 30) + 5;
resolve(latency);
}, 300);
});
}
function testDownloadSpeed() {
return new Promise((resolve) => {
let startTime, endTime;
const fileSize = 5 * 1024 * 1024; // 5MB test file
const testUrl = `https://httpbin.org/bytes/${fileSize}?r=${Math.random()}`;
startTime = new Date().getTime();
fetch(testUrl)
.then((response) => {
endTime = new Date().getTime();
return response.blob();
})
.then(() => {
const duration = (endTime - startTime) / 1000;
const bitsLoaded = fileSize * 8;
const speedMbps = (bitsLoaded / duration / 1024 / 1024).toFixed(2);
// Update speed in real-time during test
let progress = 0;
const interval = setInterval(() => {
if (progress >= speedMbps) {
clearInterval(interval);
resolve(parseFloat(speedMbps));
} else {
progress += Math.random() * 5;
downloadSpeed.textContent =
Math.min(progress, speedMbps).toFixed(1) + " Mbps";
}
}, 100);
});
});
}
function testUploadSpeed() {
return new Promise((resolve) => {
let startTime, endTime;
const fileSize = 1 * 1024 * 1024; // 1MB test file
const testData = new Blob([new Uint8Array(fileSize)], {
type: "application/octet-stream"
});
startTime = new Date().getTime();
fetch("https://httpbin.org/post", {
method: "POST",
body: testData
})
.then((response) => response.json())
.then(() => {
endTime = new Date().getTime();
const duration = (endTime - startTime) / 1000;
const bitsLoaded = fileSize * 8;
const speedMbps = (bitsLoaded / duration / 1024 / 1024).toFixed(2);
// Update speed in real-time during test
let progress = 0;
const interval = setInterval(() => {
if (progress >= speedMbps) {
clearInterval(interval);
resolve(parseFloat(speedMbps));
} else {
progress += Math.random() * 2;
uploadSpeed.textContent =
Math.min(progress, speedMbps).toFixed(1) + " Mbps";
}
}, 100);
});
});
}
function saveTestResult(download, upload, ping) {
const now = new Date();
const testResult = {
date: now.toLocaleString(),
download: download,
upload: upload,
ping: ping
};
testHistory.unshift(testResult);
if (testHistory.length > 5) {
testHistory = testHistory.slice(0, 5);
}
localStorage.setItem("speedTestHistory", JSON.stringify(testHistory));
renderHistory();
}
function renderHistory() {
historyTable.innerHTML = "";
if (testHistory.length === 0) {
const row = document.createElement("tr");
row.innerHTML = `
<td colspan="4" class="px-6 py-4 text-center text-gray-500">No test history yet</td>
`;
historyTable.appendChild(row);
return;
}
testHistory.forEach((result) => {
const row = document.createElement("tr");
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${result.date}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-green-600">${result.download} Mbps</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-blue-600">${result.upload} Mbps</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-purple-600">${result.ping}</td>
`;
historyTable.appendChild(row);
});
}
});
fetch("https://dav7.pages.dev/api/serve.json")
.then((response) => response.json())
.then((data) => {
const sites = data.sites;
const mySelects = document.getElementById("mySelects");
sites.forEach((sites) => {
const preElement = document.createElement("option");
preElement.value = `${sites.properties.links}`;
preElement.textContent = `${sites.properties.title}`;
mySelects.appendChild(preElement);
});
})
.catch((error) => {
console.log("ERROR", error);
});
const select = document.getElementById("mySelects");
select.addEventListener("change", function () {
const url = this.value;
if (url) {
window.location = url;
}
});
/*shared*/
function sharesbutton() {
navigator.share({
title: document.title,
text: "Compartilhar" + document.title,
url: window.location.href
});
}
var creditsyear = new Date();
document.getElementById("datacedencer").innerHTML = creditsyear.getFullYear();
</script>
<script src="https://redek-dp.github.io/servdevanalytics/v1/app.id.js"></script>
</body>
</html>