<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        <meta name="robots" content="noindex" />
        <title>Verifying</title>
        <style>
            :root {
                --bg: #f5f5f5;
                --text: #111;
                --surface: #ddd;
                --muted: #777;
                --link: #555;
                --error: #c00;
                --accent: {{ACCENT_COLOR}};
            }
            @media (prefers-color-scheme: dark) {
                :root {
                    --bg: #0a0a0a;
                    --text: #e0e0e0;
                    --surface: #222;
                    --muted: #555;
                    --link: #777;
                    --error: #f55;
                }
            }
            * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }
            body {
                font-family: system-ui, sans-serif;
                display: flex;
                justify-content: center;
                align-items: center;
                height: 100vh;
                background: var(--bg);
                color: var(--text);
            }
            .box {
                text-align: center;
                max-width: 420px;
                padding: 2rem;
            }
            h2 {
                margin-bottom: 1rem;
                font-weight: 500;
            }
            #status {
                color: var(--muted);
                margin-bottom: 1.5rem;
                font-size: 0.9rem;
            }
            #rounds {
                color: var(--muted);
                font-size: 0.75rem;
                margin-top: 0.4rem;
            }
            .bar {
                width: 100%;
                height: 4px;
                background: var(--surface);
                border-radius: 2px;
                overflow: hidden;
            }
            .fill {
                height: 100%;
                background: var(--accent);
                width: 0;
                transition: width 0.3s;
            }
            noscript {
                color: var(--error);
                display: block;
                margin-top: 1rem;
            }
            .branding {
                margin-top: 1.5rem;
                font-size: 0.7rem;
                color: var(--muted);
            }
            .branding a {
                color: var(--link);
                text-decoration: none;
            }
            .branding a:hover {
                text-decoration: underline;
            }
        </style>
    </head>
    <body>
        <div class="box">
            <h2>Checking your browser</h2>
            <p id="status">Connecting&#8230;</p>
            <div class="bar"><div class="fill" id="bar"></div></div>
            <p id="rounds"></p>
            <noscript>JavaScript is required.</noscript>
            {{BRANDING}}
        </div>
        <script>
            const SIGNAL_CATEGORIES = [
                'automation',
                'browser',
                'properties',
                'natives',
                'features',
                'navigator',
                'screen',
                'engine',
                'mediaQueries',
                'environment',
                'timing',
                'webgl',
                'canvas',
                'fonts',
                'headless',
                'vm',
                'consistency',
                'devtools',
                'cdp',
                'cssVersion',
                'voices',
                'performance',
                'prototype',
                'drawing',
            ];

            function safe(fn, fallback) {
                try {
                    return fn();
                } catch {
                    return fallback;
                }
            }

            function hasProp(object, prop) {
                try {
                    return prop in object;
                } catch {
                    return false;
                }
            }

            function isNative(fn) {
                try {
                    return Function.prototype.toString.call(fn).includes('[native code]');
                } catch {
                    return false;
                }
            }

            function getDescriptor(object, prop) {
                try {
                    return Object.getOwnPropertyDescriptor(object, prop);
                } catch {
                    return null;
                }
            }

            function collectAutomation() {
                const w = globalThis.window || {};
                const n = globalThis.navigator || {};
                const d = globalThis.document || {};

                let globals = 0;
                try {
                    if (n.webdriver) globals |= 1;
                } catch {}
                try {
                    if (w.__nightmare) globals |= 1 << 1;
                } catch {}
                try {
                    if (w._phantom || w.callPhantom) globals |= 1 << 2;
                } catch {}
                try {
                    if (w.__selenium_unwrapped) globals |= 1 << 3;
                } catch {}
                try {
                    if (w._Selenium_IDE_Recorder) globals |= 1 << 4;
                } catch {}
                try {
                    if (w.domAutomation) globals |= 1 << 5;
                } catch {}
                try {
                    if (w.domAutomationController) globals |= 1 << 6;
                } catch {}
                try {
                    if (d.__webdriver_evaluate || w.__webdriver_evaluate) globals |= 1 << 7;
                } catch {}
                try {
                    if (w.__selenium_evaluate) globals |= 1 << 8;
                } catch {}
                try {
                    if (w.__fxdriver_evaluate) globals |= 1 << 9;
                } catch {}
                try {
                    if (w.__webdriver_unwrapped) globals |= 1 << 10;
                } catch {}
                try {
                    if (w.__webdriver_script_fn) globals |= 1 << 11;
                } catch {}
                try {
                    if (w.Cypress || w.__cypress) globals |= 1 << 12;
                } catch {}
                try {
                    if (w.__playwright_evaluate || w.__playwright_resume || w.playwright)
                        globals |= 1 << 13;
                } catch {}
                try {
                    if (w.__playwright__binding__ || w.__pwInitScripts) globals |= 1 << 14;
                } catch {}
                try {
                    const ua = n.userAgent || '';
                    if (ua.includes('HeadlessChrome')) globals |= 1 << 15;
                } catch {}
                try {
                    const ua = (n.userAgent || '').toLowerCase();
                    if (w._headless || ua.includes('headless')) globals |= 1 << 16;
                } catch {}
                try {
                    if (w.Buffer && typeof w.Buffer === 'function') globals |= 1 << 17;
                } catch {}

                let enhanced = 0;
                try {
                    const desc = getDescriptor(n, 'webdriver');
                    if (desc) {
                        enhanced |= 1;
                        if (typeof desc.get === 'function') enhanced |= 1 << 1;
                        if ('value' in desc) enhanced |= 1 << 2;
                        if (desc.configurable) enhanced |= 1 << 3;
                        if (desc.enumerable) enhanced |= 1 << 4;
                    }
                } catch {}
                try {
                    const cdcPattern = /^cdc_|^\$cdc_|_Array$|_Promise$|_Symbol$|_Object$|_Proxy$/;
                    if (Object.keys(w).some((k) => cdcPattern.test(k))) enhanced |= 1 << 5;
                } catch {}
                try {
                    if (w.__cdp_binding__ || w.__chromeSendMessage) enhanced |= 1 << 6;
                } catch {}
                try {
                    throw new Error('x');
                } catch (error) {
                    try {
                        const stack = error.stack || '';
                        if (/selenium|webdriver|puppeteer|playwright|cypress/i.test(stack))
                            enhanced |= 1 << 7;
                    } catch {}
                }
                try {
                    const proto = Object.getPrototypeOf(n);
                    const desc = getDescriptor(proto, 'webdriver');
                    if (desc?.get && !isNative(desc.get)) enhanced |= 1 << 9;
                } catch {}
                try {
                    if (d.querySelector('[selenium],[webdriver],[driver]')) enhanced |= 1 << 10;
                } catch {}
                try {
                    const fnToString = Function.prototype.toString.call(
                        Function.prototype.toString
                    );
                    if (!fnToString.includes('[native code]')) enhanced |= 1 << 11;
                } catch {}
                try {
                    const attr = d.documentElement?.getAttribute('webdriver');
                    if (attr) enhanced |= 1 << 13;
                } catch {}
                try {
                    if (Object.getOwnPropertyNames(n).includes('webdriver')) enhanced |= 1 << 15;
                } catch {}

                let extra = 0;
                try {
                    if (w.awesomium) extra |= 1;
                } catch {}
                try {
                    if (w.RunPerfTest) extra |= 1 << 1;
                } catch {}
                try {
                    if (w.CefSharp) extra |= 1 << 2;
                } catch {}
                try {
                    if (w.emit && typeof w.emit === 'function') extra |= 1 << 3;
                } catch {}
                try {
                    if (w.fmget_targets) extra |= 1 << 4;
                } catch {}
                try {
                    if (w.geb) extra |= 1 << 5;
                } catch {}
                try {
                    if (w.__phantomas) extra |= 1 << 6;
                } catch {}
                try {
                    if (w.spawn) extra |= 1 << 7;
                } catch {}
                try {
                    if (w.wdioElectron) extra |= 1 << 8;
                } catch {}
                try {
                    if (w._selenium || w.calledSelenium) extra |= 1 << 9;
                } catch {}
                try {
                    if (w._WEBDRIVER_ELEM_CACHE || w.ChromeDriverw) extra |= 1 << 10;
                } catch {}
                try {
                    if (d.__driver_evaluate || d.__driver_unwrapped) extra |= 1 << 11;
                } catch {}
                try {
                    if (
                        d.__webdriver_script_func ||
                        w.$chrome_asyncScriptInfo ||
                        w.__$webdriverAsyncExecutor
                    )
                        extra |= 1 << 12;
                } catch {}
                try {
                    if (
                        w.process &&
                        (w.process.type === 'renderer' || w.process.versions?.electron)
                    )
                        extra |= 1 << 13;
                } catch {}
                try {
                    if (w.external && /Sequentum/i.test(String(w.external))) extra |= 1 << 14;
                } catch {}
                try {
                    const pattern = /^([a-z]){3}_.*_(Array|Promise|Symbol)$/;
                    if (Object.keys(w).some((k) => pattern.test(k))) extra |= 1 << 15;
                } catch {}
                try {
                    if (/Headless|Electron|SlimerJS/i.test(n.appVersion || '')) extra |= 1 << 16;
                } catch {}

                return { globals, enhanced, extra };
            }

            function collectBrowserAPIs() {
                const w = globalThis.window || {};
                const n = globalThis.navigator || {};
                const d = globalThis.document || {};
                const ua = safe(() => n.userAgent || '', '');

                let selenium = 0;
                try {
                    if (Object.keys(w).some((k) => k.startsWith('$cdc_') || k.startsWith('cdc_')))
                        selenium |= 1;
                } catch {}
                try {
                    if (hasProp(w, '__selenium_unwrapped') || hasProp(w, '__selenium_evaluate'))
                        selenium |= 1 << 1;
                } catch {}
                try {
                    if (n.plugins) {
                        if (n.plugins.length === 0 && !/mobile|android/i.test(ua))
                            selenium |= 1 << 2;
                        if (Object.prototype.toString.call(n.plugins) !== '[object PluginArray]')
                            selenium |= 1 << 3;
                        if (typeof n.plugins.refresh !== 'function') selenium |= 1 << 4;
                    }
                } catch {}
                try {
                    if (Object.prototype.toString.call(n.mimeTypes) !== '[object MimeTypeArray]')
                        selenium |= 1 << 5;
                } catch {}
                try {
                    if (n.permissions?.query && !isNative(n.permissions.query)) selenium |= 1 << 6;
                } catch {}
                try {
                    if (w.chrome) {
                        const hasCsi = typeof w.chrome.csi === 'function';
                        const hasLoadTimes = typeof w.chrome.loadTimes === 'function';
                        if (w.chrome.runtime && !hasCsi && !hasLoadTimes) selenium |= 1 << 7;
                    }
                } catch {}
                try {
                    if (w.outerWidth === 0 || w.outerHeight === 0) selenium |= 1 << 10;
                } catch {}
                try {
                    if (!hasProp(w, 'speechSynthesis') && /Chrome/.test(ua)) selenium |= 1 << 11;
                } catch {}
                try {
                    const canvas = d.createElement('canvas');
                    const gl =
                        canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
                    if (gl) {
                        const dbg = gl.getExtension('WEBGL_debug_renderer_info');
                        if (dbg) {
                            const renderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) || '';
                            if (/SwiftShader|llvmpipe|softpipe/i.test(renderer))
                                selenium |= 1 << 12;
                        }
                    }
                } catch {}

                let stealth = 0;
                try {
                    if (Object.getOwnPropertyNames(n).includes('webdriver')) stealth |= 1 << 1;
                } catch {}
                try {
                    const stack = new Error().stack || '';
                    if (/pptr:|__puppeteer_evaluation_script__/.test(stack)) stealth |= 1 << 2;
                } catch {}
                try {
                    const timestamps = [];
                    for (let i = 0; i < 10; i++) timestamps.push(performance.now());
                    const diffs = [];
                    for (let j = 1; j < timestamps.length; j++)
                        diffs.push(timestamps[j] - timestamps[j - 1]);
                    if (diffs.every((x) => x === diffs[0]) && diffs[0] > 0) stealth |= 1 << 3;
                } catch {}
                try {
                    if (!hasProp(w, 'PerformanceObserver') && /Chrome/.test(ua)) stealth |= 1 << 4;
                } catch {}
                try {
                    if (!n.mediaDevices && /Chrome/.test(ua) && !/Android/.test(ua))
                        stealth |= 1 << 6;
                } catch {}
                try {
                    if (n.connection?.rtt === 0) stealth |= 1 << 7;
                } catch {}
                try {
                    if (/Chrome/.test(ua) && w.chrome && !w.chrome.app) stealth |= 1 << 8;
                } catch {}
                try {
                    if (Object.keys(d).some((k) => k.includes('cdc') || k.includes('selenium')))
                        stealth |= 1 << 9;
                } catch {}
                try {
                    const proto = Object.getPrototypeOf(n);
                    const desc = getDescriptor(proto, 'webdriver');
                    if (desc?.get) {
                        const src = desc.get.toString();
                        if (src.length < 30 || /return\s*(false|!1)/.test(src)) stealth |= 1 << 10;
                    }
                } catch {}
                try {
                    if (!w.clientInformation && /Chrome/.test(ua)) stealth |= 1 << 12;
                } catch {}
                try {
                    if (hasProp(n, 'deviceMemory')) {
                        const valid = [0.25, 0.5, 1, 2, 4, 8, 16, 32, 64];
                        if (!valid.includes(n.deviceMemory)) stealth |= 1 << 14;
                    }
                } catch {}

                let advanced = 0;
                try {
                    const proto = Object.getPrototypeOf(n);
                    const desc = getDescriptor(proto, 'webdriver');
                    if (desc?.get && desc.get.call(n) === undefined) advanced |= 1;
                } catch {}
                try {
                    const mq = w.matchMedia?.('(pointer: fine)');
                    if (mq && !mq.matches && !hasProp(w, 'ontouchstart')) advanced |= 1 << 2;
                } catch {}
                try {
                    if (hasProp(w, 'Notification') && !isNative(w.Notification)) advanced |= 1 << 3;
                } catch {}
                try {
                    const entries = performance.getEntriesByType('navigation');
                    if (entries.length > 0) {
                        if (entries[0].domContentLoadedEventStart === 0) advanced |= 1 << 4;
                        if (entries[0].loadEventStart === 0 && d.readyState === 'complete')
                            advanced |= 1 << 5;
                    }
                } catch {}
                try {
                    const cdcProps = Object.getOwnPropertyNames(w).filter((p) =>
                        /cdc|_selenium|_webdriver|\$cdc|domAutomation/.test(p)
                    );
                    if (cdcProps.length > 0) advanced |= 1 << 7;
                } catch {}
                try {
                    if (!hasProp(w, 'SharedWorker') && /Chrome/.test(ua)) advanced |= 1 << 10;
                } catch {}
                try {
                    const chromeVersionPattern = /Chrome\/[89]\d|Chrome\/1[0-2]\d/;
                    if (!hasProp(n, 'usb') && chromeVersionPattern.test(ua)) advanced |= 1 << 12;
                    if (!hasProp(n, 'serial') && chromeVersionPattern.test(ua)) advanced |= 1 << 13;
                    if (!hasProp(n, 'hid') && chromeVersionPattern.test(ua)) advanced |= 1 << 14;
                } catch {}

                let apis = 0;
                try {
                    apis |= hasProp(w, 'chrome') ? 1 : 0;
                } catch {}
                try {
                    apis |= (hasProp(n, 'permissions') ? 1 : 0) << 1;
                } catch {}
                try {
                    apis |= (n.languages && n.languages.length > 0 ? 1 : 0) << 2;
                } catch {}
                try {
                    apis |= (n.connection ? 1 : 0) << 3;
                } catch {}
                try {
                    apis |= (hasProp(n, 'getBattery') ? 1 : 0) << 4;
                } catch {}
                try {
                    apis |= (hasProp(n, 'bluetooth') ? 1 : 0) << 5;
                } catch {}
                try {
                    apis |= (hasProp(n, 'usb') ? 1 : 0) << 6;
                } catch {}
                try {
                    apis |= (hasProp(n, 'serial') ? 1 : 0) << 7;
                } catch {}

                return { apis, selenium, stealth, advanced };
            }

            function collectPropertyIntegrity() {
                const n = globalThis.navigator || {};
                let integrity = 0;
                let overrides = 0;
                let protoInconsistency = 0;

                try {
                    integrity |= isNative(Object.defineProperty) ? 1 : 0;
                } catch {}
                try {
                    integrity |= (isNative(Object.getOwnPropertyDescriptor) ? 1 : 0) << 1;
                } catch {}
                try {
                    if (typeof Reflect !== 'undefined')
                        integrity |= (isNative(Reflect.get) ? 1 : 0) << 2;
                } catch {}
                try {
                    integrity |= (n.toString() !== '[object Navigator]' ? 1 : 0) << 10;
                } catch {
                    integrity |= 1 << 11;
                }
                try {
                    integrity |= (n[Symbol.toStringTag] !== 'Navigator' ? 1 : 0) << 13;
                } catch {}
                try {
                    const props = ['userAgent', 'platform', 'languages', 'plugins', 'webdriver'];
                    const proto = Object.getPrototypeOf(n);
                    for (const prop of props) {
                        const desc = getDescriptor(proto, prop);
                        if (desc?.get && !isNative(desc.get)) {
                            integrity |= 1 << 14;
                            break;
                        }
                    }
                } catch {}
                try {
                    if (typeof Reflect !== 'undefined')
                        integrity |= (!isNative(Reflect.get) ? 1 : 0) << 15;
                } catch {}

                try {
                    const proto = Object.getPrototypeOf(n);
                    if (proto.constructor.name !== 'Navigator') protoInconsistency++;
                } catch {}

                const checkProps = ['webdriver', 'plugins', 'languages', 'platform', 'userAgent'];
                for (const prop of checkProps) {
                    try {
                        const desc = getDescriptor(n, prop);
                        if (desc) {
                            if (desc.get && !isNative(desc.get)) overrides++;
                            else if ('value' in desc) overrides++;
                        }
                    } catch {}
                }

                return { integrity, overrides, protoInconsistency };
            }

            function collectNativeFunctions() {
                const w = globalThis.window || {};
                let bitmap = 0;
                const targets = [
                    [Function.prototype.toString, 0],
                    [w.setTimeout, 1],
                    [w.setInterval, 2],
                    [Date.now, 3],
                    [Math.random, 4],
                    [Array.prototype.push, 5],
                    [JSON.stringify, 6],
                    [Object.keys, 7],
                    [Promise.resolve, 8],
                    [Array.from, 9],
                ];
                try {
                    targets.push([Reflect.get, 10]);
                } catch {}
                try {
                    targets.push([console.log, 11]);
                } catch {}

                for (const [fn, bit] of targets) {
                    try {
                        bitmap |= (isNative(fn) ? 1 : 0) << bit;
                    } catch {}
                }
                return bitmap;
            }

            function collectFeatures() {
                const w = globalThis.window || {};
                let bits = 0;
                const features = [
                    ['localStorage', 0],
                    ['sessionStorage', 1],
                    ['WebSocket', 2],
                    ['WebGLRenderingContext', 3],
                    ['WebGL2RenderingContext', 4],
                    ['indexedDB', 6],
                    ['Notification', 7],
                    ['fetch', 8],
                    ['Promise', 9],
                    ['Intl', 10],
                    ['SharedArrayBuffer', 11],
                    ['SharedWorker', 12],
                    ['BroadcastChannel', 13],
                    ['PerformanceObserver', 14],
                    ['IntersectionObserver', 15],
                ];
                for (const [name, bit] of features) {
                    bits |= (hasProp(w, name) ? 1 : 0) << bit;
                }
                try {
                    bits |= (typeof WebAssembly === 'object' ? 1 : 0) << 5;
                } catch {}
                return bits;
            }

            function collectNavigatorProps() {
                const n = globalThis.navigator || {};
                const result = {
                    ua: safe(() => n.userAgent || '', ''),
                    platform: safe(() => n.platform || '', ''),
                    pluginCount: safe(() => n.plugins?.length ?? 0, 0),
                    languageCount: safe(() => n.languages?.length ?? 0, 0),
                    languages: safe(() => (n.languages ? Array.from(n.languages) : []), []),
                    cookieEnabled: safe(() => !!n.cookieEnabled, false),
                    doNotTrack: safe(() => n.doNotTrack || '', ''),
                    hardwareConcurrency: safe(() => n.hardwareConcurrency || 0, 0),
                    deviceMemory: safe(() => n.deviceMemory, undefined),
                    rtt: safe(() => n.connection?.rtt, undefined),
                    downlink: safe(() => n.connection?.downlink, undefined),
                    effectiveType: safe(() => n.connection?.effectiveType, undefined),
                    maxTouchPoints: safe(() => n.maxTouchPoints || 0, 0),
                    pdfViewerEnabled: safe(() => !!n.pdfViewerEnabled, false),
                    vendor: safe(() => n.vendor || '', ''),
                    productSub: safe(() => n.productSub || '', ''),
                    appVersion: safe(() => n.appVersion || '', ''),
                    uadBrands: safe(
                        () => n.userAgentData?.brands?.map((b) => `${b.brand}/${b.version}`) ?? [],
                        []
                    ),
                    uadMobile: safe(() => n.userAgentData?.mobile, undefined),
                    uadPlatform: safe(() => n.userAgentData?.platform, undefined),
                };
                return result;
            }

            function collectScreenProps() {
                const s = globalThis.screen || {};
                const w = globalThis.window || {};
                return {
                    width: safe(() => s.width || 0, 0),
                    height: safe(() => s.height || 0, 0),
                    availWidth: safe(() => s.availWidth || 0, 0),
                    availHeight: safe(() => s.availHeight || 0, 0),
                    colorDepth: safe(() => s.colorDepth || 0, 0),
                    pixelDepth: safe(() => s.pixelDepth || 0, 0),
                    devicePixelRatio: safe(() => w.devicePixelRatio || 0, 0),
                    orientation: safe(() => s.orientation?.type || '', ''),
                    isExtended: safe(() => s.isExtended, undefined),
                };
            }

            function collectEngineFingerprint() {
                let evalLength = -1;
                try {
                    evalLength = eval.toString().length;
                } catch {}

                let stackStyle = 'unknown';
                try {
                    throw new Error('detect');
                } catch (error) {
                    const stack = error.stack || '';
                    if (stack.includes(' at ')) stackStyle = 'v8';
                    else if (stack.includes('@')) stackStyle = 'spidermonkey';
                    else if (stack.includes('global code')) stackStyle = 'jsc';
                }

                const mathTan = safe(() => Math.tan(-1e308), 0);
                const mathAcosh = safe(() => Math.acosh(1e308), 0);
                const bindNative = safe(() => (isNative(Function.prototype.bind) ? 1 : 0), -1);
                const externalType = safe(() => typeof globalThis.window?.external, undefined);

                return {
                    evalLength,
                    stackStyle,
                    mathTan,
                    mathAcosh,
                    bindNative,
                    externalType,
                };
            }

            function collectMediaQueries() {
                const mm = globalThis.window?.matchMedia;
                if (!mm) return null;

                function query(q) {
                    try {
                        return mm(q).matches;
                    } catch {
                        return false;
                    }
                }

                return {
                    hover: query('(hover: hover)'),
                    anyHover: query('(any-hover: hover)'),
                    pointerFine: query('(pointer: fine)'),
                    pointerCoarse: query('(pointer: coarse)'),
                    darkMode: query('(prefers-color-scheme: dark)'),
                    reducedMotion: query('(prefers-reduced-motion: reduce)'),
                    highContrast: query('(prefers-contrast: more)'),
                    forcedColors: query('(forced-colors: active)'),
                    colorGamutP3: query('(color-gamut: p3)'),
                    colorGamutSrgb: query('(color-gamut: srgb)'),
                    touch: safe(() => 'ontouchstart' in globalThis.window, false),
                };
            }

            function collectEnvironment() {
                const w = globalThis.window || {};
                const n = globalThis.navigator || {};
                const d = globalThis.document || {};

                return {
                    timezoneOffset: safe(() => new Date().getTimezoneOffset(), 0),
                    timezoneName: safe(
                        () => Intl.DateTimeFormat().resolvedOptions().timeZone || '',
                        ''
                    ),
                    touch:
                        safe(() => ('ontouchstart' in w ? 1 : 0), 0) |
                        (safe(() => (n.maxTouchPoints > 0 ? 1 : 0), 0) << 1),
                    document:
                        safe(() => (d.hidden ? 1 : 0), 0) |
                        (safe(() => (d.hasFocus?.() ? 1 : 0), 0) << 1) |
                        (safe(() => (d.visibilityState === 'visible' ? 1 : 0), 0) << 2),
                    online: safe(() => n.onLine, undefined),
                    batteryApi: safe(() => (typeof n.getBattery === 'function' ? 1 : 0), 0),
                };
            }

            function collectTiming() {
                let perfNowIdentical = false;
                try {
                    const timestamps = [];
                    for (let i = 0; i < 10; i++) timestamps.push(performance.now());
                    const diffs = [];
                    for (let j = 1; j < timestamps.length; j++)
                        diffs.push(timestamps[j] - timestamps[j - 1]);
                    perfNowIdentical =
                        diffs.length > 1 && diffs.every((d) => d === diffs[0]) && diffs[0] > 0;
                } catch {}
                return { perfNowIdentical };
            }

            function collectWebGL() {
                const d = globalThis.document;
                if (!d) return null;
                try {
                    const canvas = d.createElement('canvas');
                    const gl =
                        canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
                    if (!gl) return null;
                    const result = {
                        vendor: '',
                        renderer: '',
                        maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
                        maxVertexAttribs: gl.getParameter(gl.MAX_VERTEX_ATTRIBS),
                        extensionCount: gl.getSupportedExtensions()?.length ?? 0,
                    };
                    const dbg = gl.getExtension('WEBGL_debug_renderer_info');
                    if (dbg) {
                        result.vendor = gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL) || '';
                        result.renderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) || '';
                    }
                    return result;
                } catch {
                    return null;
                }
            }

            function collectCanvas() {
                const d = globalThis.document;
                if (!d) return { hash: 'err', tampering: null };

                let hash = 'err';
                try {
                    const canvas = d.createElement('canvas');
                    canvas.width = 240;
                    canvas.height = 60;
                    const ctx = canvas.getContext('2d');
                    ctx.textBaseline = 'alphabetic';
                    ctx.fillStyle = '#f60';
                    ctx.fillRect(100, 1, 62, 20);
                    ctx.fillStyle = '#069';
                    ctx.font = '11pt Arial';
                    ctx.fillText('vigilus,\ud83d\ude03', 2, 15);
                    ctx.fillStyle = 'rgba(102,204,0,0.7)';
                    ctx.font = '18pt Arial';
                    ctx.fillText('vigilus,\ud83d\ude03', 4, 45);
                    const dataUrl = canvas.toDataURL();
                    let h = 0;
                    for (let i = 0; i < dataUrl.length; i++) {
                        h = ((h << 5) - h + dataUrl.charCodeAt(i)) | 0;
                    }
                    hash = h.toString(16);
                } catch {}

                let tampering = null;
                try {
                    const canvas = d.createElement('canvas');
                    canvas.width = 64;
                    canvas.height = 16;
                    const ctx = canvas.getContext('2d');
                    ctx.fillStyle = '#f00';
                    ctx.fillRect(0, 0, 64, 16);
                    ctx.fillStyle = '#0f0';
                    ctx.font = '12px Arial';
                    ctx.fillText('test', 2, 12);
                    const d1 = canvas.toDataURL();

                    ctx.fillStyle = '#f00';
                    ctx.fillRect(0, 0, 64, 16);
                    ctx.fillStyle = '#0f0';
                    ctx.font = '12px Arial';
                    ctx.fillText('test', 2, 12);
                    const d2 = canvas.toDataURL();

                    const imageData = ctx.getImageData(0, 0, 64, 16);
                    let allZero = true;
                    for (let i = 0; i < imageData.data.length; i += 4) {
                        if (imageData.data[i] || imageData.data[i + 1] || imageData.data[i + 2]) {
                            allZero = false;
                            break;
                        }
                    }

                    tampering = {
                        random: d1 !== d2 ? 1 : 0,
                        error: 0,
                        inconsistent: d1.length > 100 && allZero ? 1 : 0,
                        dataLength: d1.length,
                    };
                } catch {
                    tampering = { random: 0, error: 1, inconsistent: 0, dataLength: 0 };
                }

                return { hash, tampering };
            }

            function collectFonts() {
                const d = globalThis.document;
                if (!d) return { widths: [], count: 0 };
                try {
                    const canvas = d.createElement('canvas');
                    const ctx = canvas.getContext('2d');
                    if (!ctx) return { widths: [], count: 0 };

                    const baseFont = '72px monospace';
                    const testString = 'mmmmmmmmlli';
                    ctx.font = baseFont;
                    const baseWidth = ctx.measureText(testString).width;

                    const fonts = [
                        'Arial',
                        'Verdana',
                        'Times New Roman',
                        'Courier New',
                        'Georgia',
                        'Palatino',
                        'Garamond',
                        'Comic Sans MS',
                        'Impact',
                        'Lucida Console',
                        'Tahoma',
                        'Trebuchet MS',
                        'Helvetica',
                        'Segoe UI',
                        'Roboto',
                        'Ubuntu',
                        'Consolas',
                        'Menlo',
                        'Monaco',
                        'Liberation Mono',
                    ];

                    const widths = [];
                    let count = 0;
                    for (const font of fonts) {
                        ctx.font = `72px "${font}",monospace`;
                        const width = ctx.measureText(testString).width;
                        widths.push(Math.round(width * 100) / 100);
                        if (width !== baseWidth) count++;
                    }
                    return { widths, count };
                } catch {
                    return { widths: [], count: 0 };
                }
            }

            function collectHeadlessHeuristics() {
                const w = globalThis.window || {};
                const n = globalThis.navigator || {};
                const d = globalThis.document || {};
                const s = w.screen || {};
                const mm = w.matchMedia;

                const pdfOff = safe(() => (n.pdfViewerEnabled === false ? 1 : 0), 0);
                const noTaskbar = safe(
                    () => (s.height === s.availHeight && s.width === s.availWidth ? 1 : 0),
                    0
                );
                const viewportMatch = safe(
                    () =>
                        w.visualViewport
                            ? w.visualViewport.width === s.width &&
                              w.visualViewport.height === s.height
                                ? 1
                                : 0
                            : 0,
                    0
                );
                const noShare = safe(
                    () => (/Chrome/.test(n.userAgent || '') && !('share' in n) ? 1 : 0),
                    0
                );

                let activeTextRed = 0;
                try {
                    const div = d.createElement('div');
                    div.style.display = 'none';
                    div.style.color = 'ActiveText';
                    d.body.appendChild(div);
                    const color = getComputedStyle(div).color;
                    d.body.removeChild(div);
                    activeTextRed = color === 'rgb(255, 0, 0)' ? 1 : 0;
                } catch {}

                const uadBlank = safe(() => (n.userAgentData?.platform === '' ? 1 : 0), 0);

                let chromeKeyPosition = 0;
                try {
                    const keys = Object.keys(w);
                    const idx = keys.indexOf('chrome');
                    chromeKeyPosition = idx > keys.length - 50 && idx !== -1 ? 1 : 0;
                } catch {}

                let runtimeConstructable = 0;
                try {
                    const fn = w.chrome?.runtime?.sendMessage;
                    if (fn) {
                        runtimeConstructable = 'prototype' in fn ? 1 : 0;
                    }
                } catch {}

                let iframeProxy = 0;
                try {
                    const iframe = d.createElement('iframe');
                    iframe.srcdoc = '';
                    iframeProxy = iframe.contentWindow ? 1 : 0;
                } catch {}

                let pluginsNotArray = 0;
                try {
                    pluginsNotArray = n.plugins instanceof PluginArray ? 0 : 1;
                } catch {}

                let mesa = 0;
                try {
                    const canvas = d.createElement('canvas');
                    const gl = canvas.getContext('webgl');
                    if (gl) {
                        const dbg = gl.getExtension('WEBGL_debug_renderer_info');
                        if (dbg) {
                            const vendor = gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL) || '';
                            const renderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) || '';
                            if (vendor === 'Brian Paul' && /Mesa OffScreen/i.test(renderer))
                                mesa = 1;
                        }
                    }
                } catch {}

                return {
                    pdfOff,
                    noTaskbar,
                    viewportMatch,
                    noShare,
                    activeTextRed,
                    uadBlank,
                    chromeKeyPosition,
                    runtimeConstructable,
                    iframeProxy,
                    pluginsNotArray,
                    mesa,
                };
            }

            function collectVMIndicators() {
                const w = globalThis.window || {};
                const n = globalThis.navigator || {};
                const s = w.screen || {};
                const d = globalThis.document;

                let softwareGL = 0;
                try {
                    if (d) {
                        const canvas = d.createElement('canvas');
                        const gl = canvas.getContext('webgl');
                        if (gl) {
                            const dbg = gl.getExtension('WEBGL_debug_renderer_info');
                            if (dbg) {
                                const renderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) || '';
                                const vendor = gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL) || '';
                                if (
                                    /llvmpipe|softpipe|SwiftShader|SVGA3D|VirtualBox|VMware|Parallels|QEMU|Mesa DRI|Chromium|Microsoft Basic Render/i.test(
                                        renderer
                                    ) ||
                                    /Brian Paul/i.test(vendor)
                                )
                                    softwareGL = 1;
                            }
                        }
                    }
                } catch {}

                let lowHardware = 0;
                try {
                    if (n.hardwareConcurrency <= 2 && (!n.deviceMemory || n.deviceMemory <= 2))
                        lowHardware = 1;
                } catch {}

                let vmResolution = 0;
                try {
                    const vmResolutions = [
                        [800, 600],
                        [1024, 768],
                        [1280, 720],
                        [1280, 800],
                        [1280, 1024],
                    ];
                    for (const [rw, rh] of vmResolutions) {
                        if (s.width === rw && s.height === rh && s.availHeight === s.height) {
                            vmResolution = 1;
                            break;
                        }
                    }
                } catch {}

                let vmAudio = 0;
                try {
                    const AudioCtx = w.AudioContext || w.webkitAudioContext;
                    if (AudioCtx) {
                        const ctx = new AudioCtx();
                        vmAudio = ctx.destination.maxChannelCount === 0 ? 1 : 0;
                        ctx.close();
                    }
                } catch {}

                return { softwareGL, lowHardware, vmResolution, vmAudio };
            }

            function collectConsistency() {
                const n = globalThis.navigator || {};
                const w = globalThis.window || {};
                const s = w.screen || {};
                const mm = w.matchMedia;
                const ua = safe(() => n.userAgent || '', '');

                let clientHints = {
                    hasUAData: false,
                    mobileMismatch: false,
                    platformMismatch: false,
                };
                try {
                    if (n.userAgentData) {
                        clientHints.hasUAData = true;
                        clientHints.mobileMismatch =
                            n.userAgentData.mobile !==
                            (n.maxTouchPoints > 0 && /mobile|android/i.test(ua));
                        if (n.userAgentData.platform) {
                            const plat = n.userAgentData.platform.toLowerCase();
                            const np = n.platform.toLowerCase();
                            clientHints.platformMismatch = !(
                                (plat.includes('win') && np.includes('win')) ||
                                (plat.includes('mac') && np.includes('mac')) ||
                                (plat.includes('linux') && np.includes('linux')) ||
                                (plat.includes('android') && np.includes('linux')) ||
                                plat === np
                            );
                        }
                    }
                } catch {}

                let screenConsistency = {
                    dimensionLie: 0,
                    alwaysLight: 0,
                };
                try {
                    if (mm) {
                        const query =
                            `(device-width:${s.width}px)` + ` and (device-height:${s.height}px)`;
                        screenConsistency.dimensionLie = !mm(query).matches ? 1 : 0;
                    }
                } catch {}
                try {
                    if (mm) {
                        screenConsistency.alwaysLight =
                            mm('(prefers-color-scheme: light)').matches &&
                            !mm('(prefers-color-scheme: dark)').matches
                                ? 1
                                : 0;
                    }
                } catch {}

                let locale = { languagePrefix: 0, localeLie: 0 };
                try {
                    const lang = n.language;
                    const langs = n.languages;
                    locale.languagePrefix =
                        langs && langs.length > 0 && !langs[0].startsWith(lang.split('-')[0])
                            ? 1
                            : 0;
                } catch {}
                try {
                    const f1 = (1000).toLocaleString();
                    const f2 = (1000).toLocaleString(n.language);
                    locale.localeLie = f1 !== f2 ? 1 : 0;
                } catch {}

                return { clientHints, screen: screenConsistency, locale };
            }

            function collectDevtools() {
                const w = globalThis.window || {};
                const widthDiff = safe(() => w.outerWidth - w.innerWidth, 0);
                const heightDiff = safe(() => w.outerHeight - w.innerHeight, 0);
                let sizeAnomaly = 0;
                if (widthDiff > 160 || heightDiff > 160) sizeAnomaly = 1;

                return {
                    sizeAnomaly,
                    widthDiff,
                    heightDiff,
                };
            }

            function collectCDP() {
                let result = 0;
                try {
                    const error = new Error();
                    let triggered = false;
                    Object.defineProperty(error, 'stack', {
                        get() {
                            triggered = true;
                            return '';
                        },
                    });
                    console.log(error);
                    console.clear?.();
                    if (triggered) result = 1;
                } catch {}
                return result;
            }

            function collectCSSVersion() {
                const w = globalThis.window || {};
                if (!w.CSS?.supports) return 0;
                const checks = [
                    [115, 'scroll-timeline-axis:block'],
                    [105, ':has(*)'],
                    [100, 'text-emphasis-color:initial'],
                    [95, 'accent-color:initial'],
                    [89, 'border-end-end-radius:initial'],
                    [88, 'aspect-ratio:initial'],
                    [84, 'appearance:initial'],
                    [81, 'color-scheme:initial'],
                ];
                for (const [version, rule] of checks) {
                    try {
                        if (w.CSS.supports(rule)) return version;
                    } catch {}
                }
                return 0;
            }

            function collectVoicesAndMedia() {
                const w = globalThis.window || {};
                const n = globalThis.navigator || {};

                let voiceCount = -1;
                try {
                    if (w.speechSynthesis) {
                        const voices = w.speechSynthesis.getVoices();
                        voiceCount = voices?.length ?? 0;
                    }
                } catch {}

                const mediaDevices = safe(() => (n.mediaDevices?.enumerateDevices ? 1 : 0), 0);
                const webrtc = safe(
                    () => (w.RTCPeerConnection || w.webkitRTCPeerConnection ? 1 : 0),
                    0
                );

                return { voiceCount, mediaDevices, webrtc };
            }

            function collectPerformance() {
                try {
                    const mem = globalThis.performance?.memory;
                    if (!mem) return {};
                    return {
                        jsHeapSizeLimit: mem.jsHeapSizeLimit,
                        totalJSHeapSize: mem.totalJSHeapSize,
                        usedJSHeapSize: mem.usedJSHeapSize,
                    };
                } catch {
                    return {};
                }
            }

            function collectPrototypeLies() {
                let lieCount = 0;

                function checkSetPrototype(fn) {
                    try {
                        Object.setPrototypeOf(fn, fn);
                        return true;
                    } catch (error) {
                        return !/chain cycle|Cyclic __proto__/.test(error.message);
                    }
                }

                const targets = [
                    ['CanvasRenderingContext2D', 'getImageData'],
                    ['CanvasRenderingContext2D', 'measureText'],
                    ['HTMLCanvasElement', 'toDataURL'],
                    ['HTMLCanvasElement', 'getContext'],
                    ['Element', 'getBoundingClientRect'],
                    ['Document', 'createElement'],
                    ['Navigator', 'hardwareConcurrency'],
                    ['Screen', 'width'],
                    ['Screen', 'height'],
                    ['Screen', 'colorDepth'],
                    ['WebGLRenderingContext', 'getParameter'],
                ];

                const w = globalThis.window || {};
                for (const [className, propName] of targets) {
                    try {
                        const cls = w[className];
                        if (!cls?.prototype) continue;
                        const desc = getDescriptor(cls.prototype, propName);
                        if (!desc) continue;
                        const fn = desc.get || desc.value;
                        if (!fn) continue;
                        if (!isNative(fn)) lieCount++;
                        else if (checkSetPrototype(fn)) lieCount++;
                    } catch {}
                }

                let mimeTypeProto = 0;
                try {
                    const mt = globalThis.navigator?.mimeTypes;
                    mimeTypeProto = Object.getPrototypeOf(mt) === MimeTypeArray.prototype ? 0 : 1;
                } catch {}

                return { lieCount, mimeTypeProto };
            }

            function collectDrawing() {
                const d = globalThis.document;
                if (!d) {
                    return {
                        emojiWidth: 0,
                        emojiHeight: 0,
                        textWidth: 0,
                        textAscent: 0,
                        textDescent: 0,
                    };
                }

                let emojiWidth = 0;
                let emojiHeight = 0;
                try {
                    const span = d.createElement('span');
                    span.textContent = '\u{1F600}\u{1F44D}\u{1F3FD}';
                    span.style.cssText = 'position:absolute;left:-9999px;font:16px sans-serif';
                    d.body.appendChild(span);
                    const rect = span.getBoundingClientRect();
                    emojiWidth = rect.width;
                    emojiHeight = rect.height;
                    d.body.removeChild(span);
                } catch {}

                let textWidth = 0;
                let textAscent = 0;
                let textDescent = 0;
                try {
                    const canvas = d.createElement('canvas');
                    const ctx = canvas.getContext('2d');
                    if (ctx) {
                        ctx.font = '16px monospace';
                        const metrics = ctx.measureText('Vigilus');
                        textWidth = metrics.width;
                        if (metrics.actualBoundingBoxAscent !== undefined) {
                            textAscent = metrics.actualBoundingBoxAscent;
                            textDescent = metrics.actualBoundingBoxDescent;
                        }
                    }
                } catch {}

                return {
                    emojiWidth,
                    emojiHeight,
                    textWidth,
                    textAscent,
                    textDescent,
                };
            }

            const collectors = {
                automation: collectAutomation,
                browser: collectBrowserAPIs,
                properties: collectPropertyIntegrity,
                natives: collectNativeFunctions,
                features: collectFeatures,
                navigator: collectNavigatorProps,
                screen: collectScreenProps,
                engine: collectEngineFingerprint,
                mediaQueries: collectMediaQueries,
                environment: collectEnvironment,
                timing: collectTiming,
                webgl: collectWebGL,
                canvas: collectCanvas,
                fonts: collectFonts,
                headless: collectHeadlessHeuristics,
                vm: collectVMIndicators,
                consistency: collectConsistency,
                devtools: collectDevtools,
                cdp: collectCDP,
                cssVersion: collectCSSVersion,
                voices: collectVoicesAndMedia,
                performance: collectPerformance,
                prototype: collectPrototypeLies,
                drawing: collectDrawing,
            };

            function collectSignals(categories) {
                const selected = categories || SIGNAL_CATEGORIES;
                const signals = {};
                const startTime =
                    typeof performance !== 'undefined' ? performance.now() : Date.now();

                for (const category of selected) {
                    const collector = collectors[category];
                    if (collector) signals[category] = collector();
                }

                const endTime = typeof performance !== 'undefined' ? performance.now() : Date.now();
                signals.meta = {
                    collectedAt: Date.now(),
                    elapsed: endTime - startTime,
                };
                return signals;
            }

            function serializeSignals(signals) {
                return JSON.stringify(signals);
            }

            function deserializeSignals(json) {
                return JSON.parse(json);
            }
        </script>
        <script>
            (function () {
                var C = JSON.parse('{{CHALLENGE_DATA}}');
                var bar = document.getElementById('bar');
                var rounds = document.getElementById('rounds');
                var status = document.getElementById('status');
                var wsOpened = false;

                function setProgress(current, total) {
                    bar.style.width = (current / total) * 100 + '%';
                    rounds.textContent = 'Round ' + current + ' of ' + total;
                }

                function setError(msg) {
                    status.textContent = msg;
                    status.style.color = 'var(--error)';
                }

                function finish(token) {
                    setProgress(1, 1);
                    status.textContent = 'Verified!';
                    var f = document.createElement('form');
                    f.method = 'POST';
                    f.action = C.verifyPath;
                    [
                        ['id', C.id],
                        ['nonce', token],
                        ['redirect', C.redirect],
                    ].forEach(function (p) {
                        var inp = document.createElement('input');
                        inp.type = 'hidden';
                        inp.name = p[0];
                        inp.value = p[1];
                        f.appendChild(inp);
                    });
                    document.body.appendChild(f);
                    f.submit();
                }

                function handleMsg(msg) {
                    if (msg.type === 'challenge') {
                        setProgress(msg.round, msg.totalRounds);
                        status.textContent =
                            'Collecting signals (' + msg.round + '/' + msg.totalRounds + ')\u2026';
                        return collectSignals(msg.checks);
                    }
                    if (msg.type === 'result') {
                        finish(msg.token);
                        return null;
                    }
                    if (msg.type === 'error') {
                        setError('Verification failed: ' + (msg.reason || 'unknown'));
                        return null;
                    }
                    return null;
                }

                function startPoll() {
                    status.textContent = 'Analyzing browser signals\u2026';
                    function step(body) {
                        fetch(C.verifyPath, {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/json' },
                            body: JSON.stringify(body),
                        })
                            .then(function (r) {
                                return r.json();
                            })
                            .then(function (msg) {
                                var signals = handleMsg(msg);
                                if (signals && msg.type === 'challenge') {
                                    step({
                                        id: C.id,
                                        nonce: msg.nonce,
                                        round: msg.round,
                                        signals: signals,
                                    });
                                }
                            })
                            .catch(function () {
                                setError('Connection error');
                            });
                    }
                    step({ id: C.id, init: true });
                }

                if (typeof WebSocket === 'undefined') {
                    startPoll();
                    return;
                }

                var proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
                var ws = new WebSocket(proto + '//' + location.host + C.verifyPath + '?id=' + C.id);

                ws.onopen = function () {
                    wsOpened = true;
                    status.textContent = 'Analyzing browser signals\u2026';
                };

                ws.onmessage = function (event) {
                    try {
                        var msg = JSON.parse(event.data);
                        var signals = handleMsg(msg);
                        if (signals && msg.type === 'challenge') {
                            ws.send(
                                JSON.stringify({
                                    nonce: msg.nonce,
                                    round: msg.round,
                                    signals: signals,
                                })
                            );
                        }
                    } catch (e) {
                        setError('Unexpected error');
                    }
                };

                ws.onerror = function () {
                    if (!wsOpened) startPoll();
                    else setError('Connection error');
                };
                ws.onclose = function (ev) {
                    if (ev.code >= 4000) setError('Session error (' + ev.code + ')');
                };
            })();
        </script>
    </body>
</html>
