{"id":8974,"date":"2026-01-25T01:50:13","date_gmt":"2026-01-24T22:50:13","guid":{"rendered":"https:\/\/1.cbm.ua\/?p=8974"},"modified":"2026-01-25T19:12:53","modified_gmt":"2026-01-25T16:12:53","slug":"%d0%ba%d0%b0%d0%ba%d0%be%d0%b5-%d1%83-%d0%b2%d0%b0%d1%81-%d1%83%d1%81%d1%82%d1%80%d0%be%d0%b9%d1%81%d1%82%d0%b2%d0%be-%d1%81-%d0%ba%d0%be%d1%82%d0%be%d1%80%d0%be%d0%b3%d0%be-%d0%b2%d1%8b-%d0%be%d1%82","status":"publish","type":"post","link":"https:\/\/1.cbm.ua\/?p=8974","title":{"rendered":"\u041a\u0430\u043a \u0432\u0430\u0441 \u0432\u0438\u0434\u044f\u0442 \u0441\u0430\u0439\u0442\u044b. (\u041a\u0430\u043a\u043e\u0435 \u0443 \u0432\u0430\u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u044b \u043e\u0442\u043a\u0440\u044b\u043b\u0438 \u044d\u0442\u0443 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.)"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<!DOCTYPE html>\n<html lang=\"ru\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>\u041a\u0430\u043a \u0432\u0430\u0441 \u0432\u0438\u0434\u044f\u0442 \u0441\u0430\u0439\u0442\u044b | Device Intelligence<\/title>\n    <style>\n        :root {\n            --accent: #00ff88; --accent-dim: #00cc6a; --bg: #0a0a0a;\n            --card: #151515; --border: #252525; --text: #e0e0e0;\n            --text-dim: #888; --warning: #ff5555; --info: #5588ff;\n        }\n        * { box-sizing: border-box; }\n        body { font-family: 'Segoe UI', -apple-system, sans-serif; background: var(--bg); color: var(--text); padding: 20px; line-height: 1.6; margin: 0; }\n        .container { max-width: 1100px; margin: 0 auto; }\n        header { text-align: center; margin-bottom: 25px; padding: 20px 0; border-bottom: 1px solid var(--border); }\n        header h1 { margin: 0; font-size: 1.8rem; background: linear-gradient(135deg, var(--accent), var(--info)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }\n        header p { color: var(--text-dim); margin-top: 8px; font-size: 0.9rem; }\n        .section-title { color: var(--accent); border-bottom: 2px solid var(--border); padding-bottom: 8px; margin: 25px 0 12px; font-size: 1.1rem; }\n        .info-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; }\n        .card { background: var(--card); padding: 15px; border-radius: 10px; border: 1px solid var(--border); }\n        .card h3 { margin: 0 0 10px; color: var(--accent); font-size: 0.9rem; }\n        .data-row { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid var(--border); }\n        .data-row:last-child { border-bottom: none; }\n        .data-label { color: var(--text-dim); font-size: 0.8rem; }\n        .data-value { color: #fff; font-weight: 600; font-family: monospace; font-size: 0.8rem; text-align: right; max-width: 60%; word-break: break-word; }\n        .data-value.small { font-size: 0.7rem; }\n        .badge { display: inline-block; padding: 2px 7px; border-radius: 10px; font-size: 0.65rem; font-weight: 600; }\n        .badge-yes { background: rgba(0,255,136,0.2); color: var(--accent); }\n        .badge-no { background: rgba(255,85,85,0.2); color: var(--warning); }\n        .badge-info { background: rgba(85,136,255,0.2); color: var(--info); }\n        .loading-dots::after { content: ''; animation: dots 1.5s infinite; }\n        @keyframes dots { 0%,20%{content:'.';} 40%{content:'..';} 60%,100%{content:'...';} }\n        \n        .deep-scan-section { background: linear-gradient(135deg, #1a1a2e, #16213e); border: 2px solid var(--info); border-radius: 12px; padding: 18px; margin-bottom: 25px; }\n        .deep-scan-section h2 { color: var(--info); margin: 0 0 12px; font-size: 1rem; }\n        .deep-scan-section .description { color: var(--text-dim); font-size: 0.85rem; margin-bottom: 12px; }\n        .btn { background: linear-gradient(135deg, var(--accent), var(--accent-dim)); color: #000; border: none; padding: 10px 25px; border-radius: 20px; cursor: pointer; font-weight: 700; font-size: 0.9rem; transition: all 0.3s; }\n        .btn:hover { box-shadow: 0 0 20px rgba(0,255,136,0.4); transform: scale(1.02); }\n        .btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none !important; }\n        .warning-text { color: var(--warning); font-size: 0.7rem; margin-top: 8px; }\n        \n        .scan-progress { margin: 15px 0; }\n        .progress-header { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 0.8rem; }\n        #progress-status { color: var(--accent); }\n        #progress-percent { font-family: monospace; }\n        .progress-bar { height: 8px; background: var(--bg); border-radius: 4px; overflow: hidden; border: 1px solid var(--border); }\n        .progress-fill { height: 100%; width: 0%; background: linear-gradient(90deg, var(--accent), var(--info)); border-radius: 4px; transition: width 0.3s; position: relative; }\n        .progress-fill.animated::after { content: ''; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); animation: shimmer 1.5s infinite; }\n        @keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }\n        .progress-steps { margin-top: 12px; font-size: 0.75rem; }\n        .step-item { display: flex; align-items: center; gap: 8px; padding: 5px 0; border-bottom: 1px solid rgba(255,255,255,0.1); opacity: 0.4; transition: opacity 0.3s; }\n        .step-item:last-child { border-bottom: none; }\n        .step-item.active, .step-item.completed, .step-item.error { opacity: 1; }\n        .step-icon { width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.65rem; }\n        .step-item.pending .step-icon { background: var(--border); color: var(--text-dim); }\n        .step-item.active .step-icon { background: var(--info); color: #fff; animation: pulse 1s infinite; }\n        .step-item.completed .step-icon { background: var(--accent); color: #000; }\n        .step-item.error .step-icon { background: var(--warning); color: #fff; }\n        @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.15); } }\n        .step-item.active .step-text { color: var(--info); }\n        .step-item.completed .step-text { color: var(--accent); }\n        .step-item.error .step-text { color: var(--warning); }\n        .step-detail { font-size: 0.65rem; color: var(--text-dim); margin-left: 28px; margin-top: -3px; }\n        .hidden { display: none; }\n        \n        .ua-block { background: var(--card); padding: 12px; border-radius: 8px; border: 1px solid var(--border); margin-top: 12px; }\n        .ua-block .label { color: var(--text-dim); font-size: 0.8rem; margin-bottom: 6px; }\n        .ua-block .value { font-family: monospace; font-size: 0.7rem; color: var(--text); word-break: break-all; background: var(--bg); padding: 10px; border-radius: 5px; }\n        .fingerprint-box { background: linear-gradient(135deg, #1a1a2e, #16213e); padding: 15px; border-radius: 10px; text-align: center; margin-top: 12px; border: 1px solid var(--border); }\n        .fingerprint-box h4 { margin: 0 0 10px; color: var(--info); font-size: 0.85rem; }\n        .fingerprint-hash { font-family: monospace; font-size: 0.95rem; color: var(--accent); background: var(--bg); padding: 10px; border-radius: 5px; }\n        .privacy-meter { margin-top: 12px; padding: 12px; background: var(--card); border-radius: 8px; border: 1px solid var(--border); }\n        .privacy-meter h4 { margin: 0 0 8px; color: var(--warning); font-size: 0.85rem; }\n        .meter-bar { height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; margin: 6px 0; }\n        .meter-fill { height: 100%; background: linear-gradient(90deg, var(--accent), var(--warning)); border-radius: 3px; transition: width 0.5s; }\n        .meter-label { display: flex; justify-content: space-between; font-size: 0.7rem; color: var(--text-dim); }\n        .fonts-list { max-height: 100px; overflow-y: auto; font-size: 0.7rem; color: var(--text-dim); margin-top: 5px; }\n        footer { text-align: center; margin-top: 30px; padding: 12px; color: var(--text-dim); font-size: 0.75rem; border-top: 1px solid var(--border); }\n        @media (max-width: 600px) { .info-grid { grid-template-columns: 1fr; } header h1 { font-size: 1.4rem; } .data-row { flex-direction: column; gap: 3px; } .data-value { text-align: left; max-width: 100%; } }\n    <\/style>\n<\/head>\n<body>\n<div class=\"container\">\n    <header>\n        <h1>\ud83d\udd0d \u041a\u0430\u043a \u0432\u0430\u0441 \u0432\u0438\u0434\u044f\u0442 \u0441\u0430\u0439\u0442\u044b<\/h1>\n        <p>\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0432\u0430\u0448\u0435\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442<\/p>\n    <\/header>\n\n    <div class=\"deep-scan-section\">\n        <h2>\ud83d\udd13 \u0413\u043b\u0443\u0431\u043e\u043a\u043e\u0435 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h2>\n        <p class=\"description\">GPS, \u043a\u0430\u043c\u0435\u0440\u044b \u0438 \u043c\u0438\u043a\u0440\u043e\u0444\u043e\u043d\u044b \u2014 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u0430\u0448\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435.<\/p>\n        <div id=\"scan-progress\" class=\"scan-progress hidden\">\n            <div class=\"progress-header\">\n                <span id=\"progress-status\">\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f&#8230;<\/span>\n                <span id=\"progress-percent\">0%<\/span>\n            <\/div>\n            <div class=\"progress-bar\"><div class=\"progress-fill\" id=\"progress-fill\"><\/div><\/div>\n            <div class=\"progress-steps\" id=\"progress-steps\"><\/div>\n        <\/div>\n        <div id=\"scan-buttons\">\n            <button class=\"btn\" id=\"scan-btn\" onclick=\"activateDeepScan()\">\ud83d\ude80 \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0433\u043b\u0443\u0431\u043e\u043a\u0438\u0439 \u0441\u043a\u0430\u043d<\/button>\n            <p class=\"warning-text\">* \u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0433\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u0438 \u0438 \u043c\u0435\u0434\u0438\u0430<\/p>\n        <\/div>\n        <div id=\"deep-results\" class=\"hidden\" style=\"margin-top: 15px;\">\n            <div class=\"info-grid\">\n                <div class=\"card\" style=\"background: rgba(0,0,0,0.3);\"><h3>\ud83d\udccd \u0413\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u044f<\/h3><div id=\"geo-data\">\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435&#8230;<\/div><\/div>\n                <div class=\"card\" style=\"background: rgba(0,0,0,0.3);\"><h3>\ud83c\udfa5 \u041a\u0430\u043c\u0435\u0440\u044b\/\u041c\u0438\u043a\u0440\u043e\u0444\u043e\u043d\u044b<\/h3><div id=\"media-data\">\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435&#8230;<\/div><\/div>\n                <div class=\"card\" style=\"background: rgba(0,0,0,0.3);\"><h3>\ud83d\udd0a \u0410\u0443\u0434\u0438\u043e<\/h3><div id=\"audio-data\">\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435&#8230;<\/div><\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <!-- IP \u0418 \u0421\u0415\u0422\u042c -->\n    <h2 class=\"section-title\">\ud83c\udf0d IP \u0438 \u0441\u0435\u0442\u044c<\/h2>\n    <div class=\"info-grid\">\n        <div class=\"card\"><h3>\ud83d\udd17 IP \u0430\u0434\u0440\u0435\u0441<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u041f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 IP<\/span><span class=\"data-value\" id=\"ip-addr\"><span class=\"loading-dots\">\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430<\/span><\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0412\u0435\u0440\u0441\u0438\u044f<\/span><span class=\"data-value\" id=\"ip-version\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u041f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 (ISP)<\/span><span class=\"data-value small\" id=\"ip-isp\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u041e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044f<\/span><span class=\"data-value small\" id=\"ip-org\">&#8230;<\/span><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83d\udccd \u041b\u043e\u043a\u0430\u0446\u0438\u044f \u043f\u043e IP<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u0421\u0442\u0440\u0430\u043d\u0430<\/span><span class=\"data-value\" id=\"ip-country\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0420\u0435\u0433\u0438\u043e\u043d<\/span><span class=\"data-value\" id=\"ip-region\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0413\u043e\u0440\u043e\u0434<\/span><span class=\"data-value\" id=\"ip-city\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u041f\u043e\u0447\u0442\u043e\u0432\u044b\u0439 \u043a\u043e\u0434<\/span><span class=\"data-value\" id=\"ip-zip\">&#8230;<\/span><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83d\udce1 \u0421\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u0422\u0438\u043f<\/span><span class=\"data-value\" id=\"conn-type\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c<\/span><span class=\"data-value\" id=\"conn-speed\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">RTT<\/span><span class=\"data-value\" id=\"conn-rtt\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u041e\u043d\u043b\u0430\u0439\u043d<\/span><span class=\"data-value\" id=\"online\">&#8230;<\/span><\/div>\n        <\/div>\n    <\/div>\n\n    <h2 class=\"section-title\">\ud83d\udcbb \u0421\u0438\u0441\u0442\u0435\u043c\u0430<\/h2>\n    <div class=\"info-grid\">\n        <div class=\"card\"><h3>\ud83d\udda5\ufe0f \u041e\u0421<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u041e\u0421<\/span><span class=\"data-value\" id=\"os-name\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u041f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430<\/span><span class=\"data-value\" id=\"platform\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/span><span class=\"data-value\" id=\"arch\">&#8230;<\/span><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\u26a1 CPU\/RAM<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u042f\u0434\u0440\u0430 CPU<\/span><span class=\"data-value\" id=\"cpu-cores\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">RAM<\/span><span class=\"data-value\" id=\"ram\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0411\u0430\u0442\u0430\u0440\u0435\u044f<\/span><span class=\"data-value\" id=\"battery\">&#8230;<\/span><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83c\udfae GPU<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u0420\u0435\u043d\u0434\u0435\u0440\u0435\u0440<\/span><span class=\"data-value small\" id=\"gpu-renderer\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0412\u0435\u043d\u0434\u043e\u0440<\/span><span class=\"data-value\" id=\"gpu-vendor\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">Max Texture<\/span><span class=\"data-value\" id=\"gpu-texture\">&#8230;<\/span><\/div>\n        <\/div>\n    <\/div>\n\n    <h2 class=\"section-title\">\ud83d\uddbc\ufe0f \u042d\u043a\u0440\u0430\u043d<\/h2>\n    <div class=\"info-grid\">\n        <div class=\"card\"><h3>\ud83d\udcd0 \u0420\u0430\u0437\u043c\u0435\u0440\u044b<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/span><span class=\"data-value\" id=\"screen-res\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u043e<\/span><span class=\"data-value\" id=\"screen-avail\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u041e\u043a\u043d\u043e<\/span><span class=\"data-value\" id=\"window-size\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">DPR<\/span><span class=\"data-value\" id=\"dpr\">&#8230;<\/span><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83c\udfa8 \u0426\u0432\u0435\u0442<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u0413\u043b\u0443\u0431\u0438\u043d\u0430<\/span><span class=\"data-value\" id=\"color-depth\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0422\u0435\u043c\u0430<\/span><span class=\"data-value\" id=\"color-scheme\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u041e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/span><span class=\"data-value\" id=\"orientation\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">HDR<\/span><span class=\"data-value\" id=\"hdr\">&#8230;<\/span><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83d\udc46 \u0412\u0432\u043e\u0434<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u0422\u0430\u0447\u0441\u043a\u0440\u0438\u043d<\/span><span class=\"data-value\" id=\"touch\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">Touch points<\/span><span class=\"data-value\" id=\"touch-points\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0423\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c<\/span><span class=\"data-value\" id=\"pointer-type\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">Gamepad<\/span><span class=\"data-value\" id=\"gamepad\">&#8230;<\/span><\/div>\n        <\/div>\n    <\/div>\n\n    <h2 class=\"section-title\">\ud83c\udf10 \u0411\u0440\u0430\u0443\u0437\u0435\u0440<\/h2>\n    <div class=\"info-grid\">\n        <div class=\"card\"><h3>\ud83d\udd24 \u041b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u042f\u0437\u044b\u043a<\/span><span class=\"data-value\" id=\"lang-primary\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0412\u0441\u0435 \u044f\u0437\u044b\u043a\u0438<\/span><span class=\"data-value small\" id=\"lang-all\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u0427\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441<\/span><span class=\"data-value\" id=\"timezone\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">UTC \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435<\/span><span class=\"data-value\" id=\"tz-offset\">&#8230;<\/span><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83d\udd27 \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">Cookies<\/span><span class=\"data-value\" id=\"cookies\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">LocalStorage<\/span><span class=\"data-value\" id=\"localstorage\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">IndexedDB<\/span><span class=\"data-value\" id=\"indexeddb\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">Service Worker<\/span><span class=\"data-value\" id=\"sw\">&#8230;<\/span><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83d\udee1\ufe0f \u041f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0441\u0442\u044c<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">Do Not Track<\/span><span class=\"data-value\" id=\"dnt\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">WebRTC Leak<\/span><span class=\"data-value\" id=\"webrtc\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">Incognito<\/span><span class=\"data-value\" id=\"incognito\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">AdBlock<\/span><span class=\"data-value\" id=\"adblock\">&#8230;<\/span><\/div>\n        <\/div>\n    <\/div>\n\n    <h2 class=\"section-title\">\ud83c\udfb5 \u041c\u0435\u0434\u0438\u0430 \u0438 \u043a\u043e\u0434\u0435\u043a\u0438<\/h2>\n    <div class=\"info-grid\">\n        <div class=\"card\"><h3>\ud83c\udfac \u0412\u0438\u0434\u0435\u043e \u043a\u043e\u0434\u0435\u043a\u0438<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">H.264<\/span><span class=\"data-value\" id=\"codec-h264\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">H.265\/HEVC<\/span><span class=\"data-value\" id=\"codec-h265\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">VP8<\/span><span class=\"data-value\" id=\"codec-vp8\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">VP9<\/span><span class=\"data-value\" id=\"codec-vp9\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">AV1<\/span><span class=\"data-value\" id=\"codec-av1\">&#8230;<\/span><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83d\udd0a \u0410\u0443\u0434\u0438\u043e \u043a\u043e\u0434\u0435\u043a\u0438<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">AAC<\/span><span class=\"data-value\" id=\"codec-aac\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">MP3<\/span><span class=\"data-value\" id=\"codec-mp3\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">Opus<\/span><span class=\"data-value\" id=\"codec-opus\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">FLAC<\/span><span class=\"data-value\" id=\"codec-flac\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">WebM Audio<\/span><span class=\"data-value\" id=\"codec-webm\">&#8230;<\/span><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83d\udde3\ufe0f \u0413\u043e\u043b\u043e\u0441\u0430 TTS<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u041a\u043e\u043b-\u0432\u043e \u0433\u043e\u043b\u043e\u0441\u043e\u0432<\/span><span class=\"data-value\" id=\"voices-count\">&#8230;<\/span><\/div>\n            <div id=\"voices-list\" class=\"fonts-list\"><\/div>\n        <\/div>\n    <\/div>\n\n    <h2 class=\"section-title\">\ud83d\udd20 \u0428\u0440\u0438\u0444\u0442\u044b \u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u044b<\/h2>\n    <div class=\"info-grid\">\n        <div class=\"card\"><h3>\ud83d\udcdd \u041e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0435 \u0448\u0440\u0438\u0444\u0442\u044b<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u041d\u0430\u0439\u0434\u0435\u043d\u043e<\/span><span class=\"data-value\" id=\"fonts-count\">&#8230;<\/span><\/div>\n            <div id=\"fonts-list\" class=\"fonts-list\"><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83d\udd0c \u041f\u043b\u0430\u0433\u0438\u043d\u044b<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">PDF Viewer<\/span><span class=\"data-value\" id=\"pdf-viewer\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">Plugins<\/span><span class=\"data-value\" id=\"plugins-count\">&#8230;<\/span><\/div>\n            <div id=\"plugins-list\" class=\"fonts-list\"><\/div>\n        <\/div>\n        <div class=\"card\"><h3>\ud83d\udcca \u0418\u0441\u0442\u043e\u0440\u0438\u044f<\/h3>\n            <div class=\"data-row\"><span class=\"data-label\">\u0414\u043b\u0438\u043d\u0430 \u0438\u0441\u0442\u043e\u0440\u0438\u0438<\/span><span class=\"data-value\" id=\"history-len\">&#8230;<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">Referrer<\/span><span class=\"data-value small\" id=\"referrer\">&#8230;<\/span><\/div>\n        <\/div>\n    <\/div>\n\n    <div class=\"ua-block\">\n        <div class=\"label\">\ud83d\udd0e User-Agent:<\/div>\n        <div class=\"value\" id=\"user-agent\">&#8230;<\/div>\n    <\/div>\n\n    <div class=\"fingerprint-box\">\n        <h4>\ud83d\udd10 \u0423\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u043f\u0435\u0447\u0430\u0442\u043e\u043a \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430<\/h4>\n        <div class=\"fingerprint-hash\" id=\"fingerprint\">\u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f&#8230;<\/div>\n        <p style=\"color:var(--text-dim);font-size:0.7rem;margin-top:8px\">\u041a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f: Canvas + WebGL + Audio + Fonts<\/p>\n    <\/div>\n\n    <div class=\"privacy-meter\">\n        <h4>\u26a0\ufe0f \u0423\u0440\u043e\u0432\u0435\u043d\u044c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438<\/h4>\n        <div class=\"meter-bar\"><div class=\"meter-fill\" id=\"privacy-fill\" style=\"width: 0%\"><\/div><\/div>\n        <div class=\"meter-label\"><span>\u0410\u043d\u043e\u043d\u0438\u043c\u043d\u044b\u0439<\/span><span id=\"privacy-score\">0%<\/span><span>\u0423\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439<\/span><\/div>\n    <\/div>\n\n    <footer><p>\u0414\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u2022 Device Intelligence v5.0<\/p><\/footer>\n<\/div>\n\n<script>\nconst $ = id => document.getElementById(id);\nconst badge = (v, t='info') => `<span class=\"badge badge-${t}\">${v}<\/span>`;\n\n\/\/ === IP INFO ===\nasync function getIPInfo() {\n    try {\n        \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e API \u0434\u043b\u044f \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0441\u0442\u0438\n        const apis = [\n            'https:\/\/ipapi.co\/json\/',\n            'https:\/\/ip-api.com\/json\/?fields=status,message,country,countryCode,region,regionName,city,zip,isp,org,as,query'\n        ];\n        \n        let data = null;\n        for (const api of apis) {\n            try {\n                const r = await fetch(api);\n                data = await r.json();\n                if (data.ip || data.query) break;\n            } catch(e) { continue; }\n        }\n        \n        if (data) {\n            const ip = data.ip || data.query;\n            $('ip-addr').textContent = ip;\n            $('ip-version').textContent = ip.includes(':') ? 'IPv6' : 'IPv4';\n            $('ip-isp').textContent = data.isp || data.org || 'N\/A';\n            $('ip-org').textContent = data.org || data.as || 'N\/A';\n            $('ip-country').textContent = `${data.country_name || data.country} ${data.country_code || data.countryCode || ''}`;\n            $('ip-region').textContent = data.region || data.regionName || 'N\/A';\n            $('ip-city').textContent = data.city || 'N\/A';\n            $('ip-zip').textContent = data.postal || data.zip || 'N\/A';\n        }\n    } catch(e) {\n        $('ip-addr').textContent = '\u041e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438';\n        $('ip-addr').style.color = 'var(--warning)';\n    }\n}\n\n\/\/ === OS DETECTION ===\nfunction detectOS(ua) {\n    if (\/CrOS\/.test(ua)) return {name:'Chrome OS',icon:'\ud83d\udcbb'};\n    if (\/Android\/.test(ua)) { const v=ua.match(\/Android\\s([\\d.]+)\/); return {name:`Android ${v?v[1]:''}`,icon:'\ud83e\udd16'}; }\n    if (\/iPhone|iPad|iPod\/.test(ua)) { const v=ua.match(\/OS\\s([\\d_]+)\/); return {name:`iOS ${v?v[1].replace(\/_\/g,'.') :''}`,icon:'\ud83c\udf4e'}; }\n    if (\/Mac OS X|macOS\/.test(ua)) { const v=ua.match(\/Mac OS X\\s([\\d_]+)\/); return {name:`macOS ${v?v[1].replace(\/_\/g,'.'):''}`,icon:'\ud83c\udf4e'}; }\n    if (\/Windows NT 10\/.test(ua)) return {name:'Windows 10\/11',icon:'\ud83e\ude9f'};\n    if (\/Windows\/.test(ua)) return {name:'Windows',icon:'\ud83e\ude9f'};\n    if (\/Linux\/.test(ua)) return {name:'Linux',icon:'\ud83d\udc27'};\n    return {name:'\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e',icon:'\u2753'};\n}\n\nfunction detectArch() {\n    const ua=navigator.userAgent, p=navigator.platform;\n    if (\/arm64|aarch64\/i.test(ua)||\/arm\/i.test(p)) return 'ARM64';\n    if (\/x86_64|x64|amd64|Win64|WOW64\/i.test(ua)) return 'x86_64';\n    if (\/i[3-6]86|x86\/i.test(ua)) return 'x86';\n    return p||'N\/A';\n}\n\n\/\/ === GPU ===\nfunction getGPU() {\n    const c=document.createElement('canvas');\n    let gl=c.getContext('webgl2')||c.getContext('webgl');\n    if (!gl) return {renderer:'N\/A',vendor:'N\/A',maxTexture:'N\/A'};\n    const d=gl.getExtension('WEBGL_debug_renderer_info');\n    const r=d?{\n        renderer:gl.getParameter(d.UNMASKED_RENDERER_WEBGL),\n        vendor:gl.getParameter(d.UNMASKED_VENDOR_WEBGL),\n        maxTexture:gl.getParameter(gl.MAX_TEXTURE_SIZE)\n    }:{\n        renderer:gl.getParameter(gl.RENDERER),\n        vendor:gl.getParameter(gl.VENDOR),\n        maxTexture:gl.getParameter(gl.MAX_TEXTURE_SIZE)\n    };\n    const e=gl.getExtension('WEBGL_lose_context'); if(e) e.loseContext();\n    return r;\n}\n\n\/\/ === CANVAS FINGERPRINT ===\nfunction getCanvasFP() {\n    const c=document.createElement('canvas'),x=c.getContext('2d');\n    c.width=200;c.height=50;\n    x.textBaseline='top';x.font='14px Arial';x.fillStyle='#f60';x.fillRect(125,1,62,20);\n    x.fillStyle='#069';x.fillText('DevIntel\ud83d\udd0d',2,15);x.fillStyle='rgba(102,204,0,0.7)';x.fillText('DevIntel\ud83d\udd0d',4,17);\n    const d=c.toDataURL();let h=0;\n    for(let i=0;i<d.length;i++){h=((h<<5)-h)+d.charCodeAt(i);h=h&h;}\n    return Math.abs(h).toString(16).toUpperCase().padStart(8,'0');\n}\n\n\/\/ === AUDIO FINGERPRINT ===\nfunction getAudioFP() {\n    try {\n        const ctx = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(1, 44100, 44100);\n        const oscillator = ctx.createOscillator();\n        oscillator.type = 'triangle';\n        oscillator.frequency.value = 10000;\n        const compressor = ctx.createDynamicsCompressor();\n        oscillator.connect(compressor);\n        compressor.connect(ctx.destination);\n        oscillator.start(0);\n        ctx.startRendering();\n        return ctx.oncomplete = (e) => {\n            let fp = 0;\n            const d = e.renderedBuffer.getChannelData(0);\n            for(let i=4500;i<5000;i++) fp += Math.abs(d[i]);\n            return fp.toString().slice(0,8);\n        };\n    } catch(e) { return '00000000'; }\n}\n\n\/\/ === WEBRTC CHECK ===\nasync function checkWebRTC() {\n    return new Promise(r=>{\n        try {\n            const pc=new RTCPeerConnection({iceServers:[]});\n            pc.createDataChannel('');\n            let found = false;\n            pc.onicecandidate=e=>{\n                if(!e.candidate) return;\n                const ip=e.candidate.candidate.match(\/([0-9]{1,3}\\.){3}[0-9]{1,3}\/);\n                if(ip && !found) {found=true; pc.close(); r(badge('\u0423\u0442\u0435\u0447\u043a\u0430: '+ip[0],'no'));}\n            };\n            pc.createOffer().then(o=>pc.setLocalDescription(o));\n            setTimeout(()=>{if(!found){pc.close();r(badge('\u0417\u0430\u0449\u0438\u0449\u0435\u043d\u043e','yes'));}},1500);\n        } catch(e){r(badge('\u0411\u043b\u043e\u043a','yes'));}\n    });\n}\n\n\/\/ === INCOGNITO CHECK ===\nasync function checkIncognito() {\n    return new Promise(r => {\n        if ('storage' in navigator && 'estimate' in navigator.storage) {\n            navigator.storage.estimate().then(({quota}) => {\n                r(quota < 120000000 ? badge('\u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e','info') : badge('\u041d\u0435\u0442','yes'));\n            }).catch(() => r(badge('N\/A','info')));\n        } else r(badge('N\/A','info'));\n    });\n}\n\n\/\/ === ADBLOCK CHECK ===\nasync function checkAdBlock() {\n    return new Promise(r => {\n        const ad = document.createElement('div');\n        ad.innerHTML = '&nbsp;';\n        ad.className = 'adsbox ad-banner ad_banner textAd text_ad';\n        ad.style.cssText = 'position:absolute;left:-9999px;';\n        document.body.appendChild(ad);\n        setTimeout(() => {\n            const blocked = ad.offsetHeight === 0 || !ad.clientHeight;\n            document.body.removeChild(ad);\n            r(blocked ? badge('\u0414\u0430','yes') : badge('\u041d\u0435\u0442','no'));\n        }, 100);\n    });\n}\n\n\/\/ === FONTS DETECTION ===\nfunction detectFonts() {\n    const baseFonts = ['monospace', 'sans-serif', 'serif'];\n    const testFonts = [\n        'Arial', 'Arial Black', 'Calibri', 'Cambria', 'Comic Sans MS', 'Consolas',\n        'Courier New', 'Georgia', 'Helvetica', 'Impact', 'Lucida Console',\n        'Palatino', 'Segoe UI', 'Tahoma', 'Times New Roman', 'Trebuchet MS',\n        'Verdana', 'Monaco', 'Menlo', 'Ubuntu', 'Roboto', 'Open Sans',\n        'Fira Code', 'Source Code Pro', 'JetBrains Mono'\n    ];\n    \n    const canvas = document.createElement('canvas');\n    const ctx = canvas.getContext('2d');\n    const testStr = 'mmmmmmmmmmlli';\n    const testSize = '72px';\n    \n    const baseWidths = {};\n    baseFonts.forEach(f => {\n        ctx.font = `${testSize} ${f}`;\n        baseWidths[f] = ctx.measureText(testStr).width;\n    });\n    \n    const detected = [];\n    testFonts.forEach(font => {\n        for (const base of baseFonts) {\n            ctx.font = `${testSize} \"${font}\", ${base}`;\n            if (ctx.measureText(testStr).width !== baseWidths[base]) {\n                detected.push(font);\n                break;\n            }\n        }\n    });\n    \n    return detected;\n}\n\n\/\/ === CODECS ===\nfunction checkCodec(type) {\n    const v = document.createElement('video');\n    const codecs = {\n        'h264': 'video\/mp4; codecs=\"avc1.42E01E\"',\n        'h265': 'video\/mp4; codecs=\"hev1.1.6.L93.B0\"',\n        'vp8': 'video\/webm; codecs=\"vp8\"',\n        'vp9': 'video\/webm; codecs=\"vp9\"',\n        'av1': 'video\/mp4; codecs=\"av01.0.00M.08\"',\n        'aac': 'audio\/mp4; codecs=\"mp4a.40.2\"',\n        'mp3': 'audio\/mpeg',\n        'opus': 'audio\/ogg; codecs=\"opus\"',\n        'flac': 'audio\/flac',\n        'webm': 'audio\/webm; codecs=\"vorbis\"'\n    };\n    const r = v.canPlayType(codecs[type]);\n    if (r === 'probably') return badge('\u0414\u0430','yes');\n    if (r === 'maybe') return badge('\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e','info');\n    return badge('\u041d\u0435\u0442','no');\n}\n\n\/\/ === TTS VOICES ===\nfunction getVoices() {\n    return new Promise(r => {\n        let voices = speechSynthesis.getVoices();\n        if (voices.length) return r(voices);\n        speechSynthesis.onvoiceschanged = () => r(speechSynthesis.getVoices());\n        setTimeout(() => r([]), 1000);\n    });\n}\n\n\/\/ === MAIN COLLECT ===\nasync function collectPassiveData() {\n    const ua = navigator.userAgent;\n    \n    \/\/ IP (async)\n    getIPInfo();\n    \n    \/\/ OS\n    const os = detectOS(ua);\n    $('os-name').innerHTML = `${os.icon} ${os.name}`;\n    $('platform').textContent = navigator.platform || 'N\/A';\n    $('arch').textContent = detectArch();\n    \n    \/\/ CPU\/RAM\n    $('cpu-cores').textContent = navigator.hardwareConcurrency ? `${navigator.hardwareConcurrency} \u044f\u0434\u0435\u0440` : '\u0421\u043a\u0440\u044b\u0442\u043e';\n    $('ram').textContent = navigator.deviceMemory ? `~${navigator.deviceMemory} GB` : '\u0421\u043a\u0440\u044b\u0442\u043e';\n    \n    \/\/ GPU\n    const gpu = getGPU();\n    $('gpu-renderer').textContent = gpu.renderer;\n    $('gpu-vendor').textContent = gpu.vendor;\n    $('gpu-texture').textContent = gpu.maxTexture + 'px';\n    \n    \/\/ Screen\n    $('screen-res').textContent = `${screen.width}\u00d7${screen.height}`;\n    $('screen-avail').textContent = `${screen.availWidth}\u00d7${screen.availHeight}`;\n    $('window-size').textContent = `${innerWidth}\u00d7${innerHeight}`;\n    $('dpr').textContent = devicePixelRatio.toFixed(2);\n    $('color-depth').textContent = `${screen.colorDepth}-bit`;\n    $('color-scheme').innerHTML = matchMedia('(prefers-color-scheme:dark)').matches ? badge('\u0422\u0451\u043c\u043d\u0430\u044f','info') : badge('\u0421\u0432\u0435\u0442\u043b\u0430\u044f','info');\n    $('orientation').textContent = innerWidth > innerHeight ? '\ud83d\udda5\ufe0f \u0410\u043b\u044c\u0431\u043e\u043c\u043d\u0430\u044f' : '\ud83d\udcf1 \u041f\u043e\u0440\u0442\u0440\u0435\u0442\u043d\u0430\u044f';\n    $('hdr').innerHTML = matchMedia('(dynamic-range:high)').matches ? badge('\u0414\u0430','yes') : badge('\u041d\u0435\u0442','no');\n    \n    \/\/ Input\n    const touch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n    $('touch').innerHTML = touch ? badge('\u0414\u0430','yes') : badge('\u041d\u0435\u0442','no');\n    $('touch-points').textContent = navigator.maxTouchPoints || 0;\n    $('pointer-type').textContent = matchMedia('(pointer:coarse)').matches ? '\ud83d\udc46 \u0422\u0430\u0447' : '\ud83d\uddb1\ufe0f \u041c\u044b\u0448\u044c';\n    $('gamepad').innerHTML = 'getGamepads' in navigator ? badge('API \u0435\u0441\u0442\u044c','info') : badge('\u041d\u0435\u0442','no');\n    \n    \/\/ Locale\n    $('lang-primary').textContent = navigator.language;\n    $('lang-all').textContent = navigator.languages?.join(', ') || navigator.language;\n    $('timezone').textContent = Intl.DateTimeFormat().resolvedOptions().timeZone;\n    const offset = new Date().getTimezoneOffset();\n    $('tz-offset').textContent = `UTC${offset<=0?'+':''}${-offset\/60}`;\n    \n    \/\/ Storage\n    $('cookies').innerHTML = navigator.cookieEnabled ? badge('\u0414\u0430','yes') : badge('\u041d\u0435\u0442','no');\n    try { localStorage.setItem('t','t'); localStorage.removeItem('t'); $('localstorage').innerHTML = badge('\u0414\u0430','yes'); } catch { $('localstorage').innerHTML = badge('\u041d\u0435\u0442','no'); }\n    $('indexeddb').innerHTML = window.indexedDB ? badge('\u0414\u0430','yes') : badge('\u041d\u0435\u0442','no');\n    $('sw').innerHTML = 'serviceWorker' in navigator ? badge('\u0414\u0430','yes') : badge('\u041d\u0435\u0442','no');\n    \n    \/\/ Privacy\n    $('dnt').innerHTML = navigator.doNotTrack === '1' ? badge('\u0412\u043a\u043b','yes') : badge('\u0412\u044b\u043a\u043b','no');\n    $('webrtc').innerHTML = await checkWebRTC();\n    $('incognito').innerHTML = await checkIncognito();\n    $('adblock').innerHTML = await checkAdBlock();\n    \n    \/\/ Network\n    const cn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;\n    if (cn) {\n        $('conn-type').textContent = cn.effectiveType?.toUpperCase() || 'N\/A';\n        $('conn-speed').textContent = cn.downlink ? `${cn.downlink} Mbps` : 'N\/A';\n        $('conn-rtt').textContent = cn.rtt ? `${cn.rtt} ms` : 'N\/A';\n    } else {\n        $('conn-type').textContent = $('conn-speed').textContent = $('conn-rtt').textContent = 'N\/A';\n    }\n    $('online').innerHTML = navigator.onLine ? badge('\u0414\u0430','yes') : badge('\u041d\u0435\u0442','no');\n    \n    \/\/ Codecs\n    $('codec-h264').innerHTML = checkCodec('h264');\n    $('codec-h265').innerHTML = checkCodec('h265');\n    $('codec-vp8').innerHTML = checkCodec('vp8');\n    $('codec-vp9').innerHTML = checkCodec('vp9');\n    $('codec-av1').innerHTML = checkCodec('av1');\n    $('codec-aac').innerHTML = checkCodec('aac');\n    $('codec-mp3').innerHTML = checkCodec('mp3');\n    $('codec-opus').innerHTML = checkCodec('opus');\n    $('codec-flac').innerHTML = checkCodec('flac');\n    $('codec-webm').innerHTML = checkCodec('webm');\n    \n    \/\/ Voices\n    const voices = await getVoices();\n    $('voices-count').textContent = voices.length;\n    $('voices-list').innerHTML = voices.slice(0,10).map(v => v.name).join('<br>') + (voices.length > 10 ? '<br>...' : '');\n    \n    \/\/ Fonts\n    const fonts = detectFonts();\n    $('fonts-count').textContent = fonts.length;\n    $('fonts-list').innerHTML = fonts.join(', ');\n    \n    \/\/ Plugins\n    $('pdf-viewer').innerHTML = navigator.pdfViewerEnabled !== undefined \n        ? (navigator.pdfViewerEnabled ? badge('\u0414\u0430','yes') : badge('\u041d\u0435\u0442','no'))\n        : badge('N\/A','info');\n    $('plugins-count').textContent = navigator.plugins?.length || 0;\n    $('plugins-list').innerHTML = Array.from(navigator.plugins || []).map(p => p.name).join('<br>') || '\u041d\u0435\u0442';\n    \n    \/\/ History\n    $('history-len').textContent = history.length;\n    $('referrer').textContent = document.referrer || '\u041f\u0440\u044f\u043c\u043e\u0439 \u0437\u0430\u0445\u043e\u0434';\n    \n    \/\/ UA\n    $('user-agent').textContent = ua;\n    \n    \/\/ Battery\n    if ('getBattery' in navigator) {\n        try {\n            const b = await navigator.getBattery();\n            const update = () => $('battery').textContent = `${Math.round(b.level*100)}% ${b.charging?'\u26a1':''}`;\n            update();\n            b.onlevelchange = b.onchargingchange = update;\n        } catch { $('battery').textContent = 'N\/A'; }\n    } else { $('battery').textContent = 'N\/A'; }\n    \n    \/\/ Fingerprint\n    const canvasFP = getCanvasFP();\n    $('fingerprint').textContent = `${canvasFP}-${navigator.hardwareConcurrency||'X'}-${fonts.length}-${voices.length}`;\n    \n    \/\/ Privacy score\n    let score = 0;\n    if (navigator.hardwareConcurrency) score += 8;\n    if (navigator.deviceMemory) score += 10;\n    if (devicePixelRatio !== 1) score += 8;\n    if (navigator.languages?.length > 1) score += 5;\n    if (navigator.maxTouchPoints > 0) score += 5;\n    if (gpu.renderer && !gpu.renderer.includes('Generic')) score += 20;\n    score += Math.min(fonts.length * 2, 20);\n    score += Math.min(voices.length, 10);\n    score += 14; \/\/ canvas\n    score = Math.min(score, 100);\n    $('privacy-fill').style.width = score + '%';\n    $('privacy-score').textContent = score + '%';\n}\n\n\/\/ === DEEP SCAN ===\nconst scanSteps = [{id:'init',name:'\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f'},{id:'geo',name:'\u0413\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u044f'},{id:'media',name:'\u041a\u0430\u043c\u0435\u0440\u044b\/\u041c\u0438\u043a\u0440\u043e\u0444\u043e\u043d\u044b'},{id:'audio',name:'\u0410\u0443\u0434\u0438\u043e'},{id:'done',name:'\u0413\u043e\u0442\u043e\u0432\u043e'}];\n\nfunction initProgress() {\n    $('progress-steps').innerHTML = scanSteps.map((s,i) => `<div class=\"step-item pending\" id=\"step-${s.id}\"><div class=\"step-icon\">${i+1}<\/div><div class=\"step-text\">${s.name}<\/div><\/div><div class=\"step-detail\" id=\"detail-${s.id}\"><\/div>`).join('');\n}\n\nfunction updateStep(id, status, detail='') {\n    const idx = scanSteps.findIndex(s => s.id === id);\n    const pct = Math.round(((idx+1) \/ scanSteps.length) * 100);\n    $('progress-fill').style.width = pct + '%';\n    $('progress-percent').textContent = pct + '%';\n    $('progress-status').textContent = scanSteps[idx].name + (status === 'active' ? '...' : '');\n    const el = $(`step-${id}`);\n    if (el) {\n        el.className = 'step-item ' + status;\n        el.querySelector('.step-icon').textContent = status === 'completed' ? '\u2713' : status === 'error' ? '\u2715' : (idx+1);\n    }\n    if (detail) $(`detail-${id}`).textContent = detail;\n}\n\nconst delay = ms => new Promise(r => setTimeout(r, ms));\n\nasync function activateDeepScan() {\n    const btn = $('scan-btn');\n    btn.disabled = true;\n    btn.textContent = '\u23f3 \u0421\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435...';\n    $('scan-progress').classList.remove('hidden');\n    $('deep-results').classList.remove('hidden');\n    $('progress-fill').classList.add('animated');\n    initProgress();\n    \n    updateStep('init', 'active');\n    await delay(300);\n    updateStep('init', 'completed', 'OK');\n    \n    updateStep('geo', 'active', '\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f...');\n    await new Promise(r => {\n        if ('geolocation' in navigator) {\n            const t = setTimeout(() => { updateStep('geo','error','\u0422\u0430\u0439\u043c\u0430\u0443\u0442'); $('geo-data').innerHTML = '<span style=\"color:var(--warning)\">\u274c \u0422\u0430\u0439\u043c\u0430\u0443\u0442<\/span>'; r(); }, 12000);\n            navigator.geolocation.getCurrentPosition(p => {\n                clearTimeout(t);\n                const {latitude:lat, longitude:lon, accuracy:acc, altitude:alt, speed:spd} = p.coords;\n                updateStep('geo', 'completed', `${lat.toFixed(4)}, ${lon.toFixed(4)}`);\n                $('geo-data').innerHTML = `\n                    <div class=\"data-row\"><span class=\"data-label\">\u0428\u0438\u0440\u043e\u0442\u0430<\/span><span class=\"data-value\">${lat.toFixed(6)}\u00b0<\/span><\/div>\n                    <div class=\"data-row\"><span class=\"data-label\">\u0414\u043e\u043b\u0433\u043e\u0442\u0430<\/span><span class=\"data-value\">${lon.toFixed(6)}\u00b0<\/span><\/div>\n                    <div class=\"data-row\"><span class=\"data-label\">\u0422\u043e\u0447\u043d\u043e\u0441\u0442\u044c<\/span><span class=\"data-value\">\u00b1${Math.round(acc)}\u043c<\/span><\/div>\n                    ${alt !== null ? `<div class=\"data-row\"><span class=\"data-label\">\u0412\u044b\u0441\u043e\u0442\u0430<\/span><span class=\"data-value\">${Math.round(alt)}\u043c<\/span><\/div>` : ''}\n                    ${spd !== null && spd > 0 ? `<div class=\"data-row\"><span class=\"data-label\">\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c<\/span><span class=\"data-value\">${(spd*3.6).toFixed(1)} \u043a\u043c\/\u0447<\/span><\/div>` : ''}\n                    <div style=\"margin-top:10px\"><a href=\"https:\/\/maps.google.com?q=${lat},${lon}\" target=\"_blank\" style=\"color:var(--accent)\">\ud83d\udccd \u041a\u0430\u0440\u0442\u0430 \u2192<\/a><\/div>`;\n                r();\n            }, e => {\n                clearTimeout(t);\n                const m = {1:'\u041e\u0442\u043a\u0430\u0437\u0430\u043d\u043e',2:'\u041d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e',3:'\u0422\u0430\u0439\u043c\u0430\u0443\u0442'};\n                updateStep('geo', 'error', m[e.code] || e.message);\n                $('geo-data').innerHTML = `<span style=\"color:var(--warning)\">\u274c ${m[e.code] || e.message}<\/span>`;\n                r();\n            }, {enableHighAccuracy:true, timeout:10000});\n        } else {\n            updateStep('geo', 'error', '\u041d\u0435\u0442 API');\n            $('geo-data').innerHTML = '<span style=\"color:var(--warning)\">\u041d\u0435\u0442 API<\/span>';\n            r();\n        }\n    });\n    await delay(200);\n    \n    updateStep('media', 'active', '\u0417\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u0430...');\n    await new Promise(async r => {\n        if ('mediaDevices' in navigator) {\n            try {\n                const s = await navigator.mediaDevices.getUserMedia({audio:true, video:true});\n                const d = await navigator.mediaDevices.enumerateDevices();\n                const g = {audioinput:[], videoinput:[], audiooutput:[]};\n                d.forEach(x => { if(g[x.kind]) g[x.kind].push(x); });\n                updateStep('media', 'completed', `${g.videoinput.length + g.audioinput.length} \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432`);\n                let h = '';\n                if (g.videoinput.length) { h += '<b>\ud83c\udfa5 \u041a\u0430\u043c\u0435\u0440\u044b:<\/b><br>'; g.videoinput.forEach((x,i) => h += `<div class=\"data-row\"><span class=\"data-label\">${i+1}<\/span><span class=\"data-value small\">${x.label||'\u0411\u0435\u0437 \u0438\u043c\u0435\u043d\u0438'}<\/span><\/div>`); }\n                if (g.audioinput.length) { h += '<b style=\"display:block;margin-top:8px\">\ud83c\udfa4 \u041c\u0438\u043a\u0440\u043e\u0444\u043e\u043d\u044b:<\/b>'; g.audioinput.forEach((x,i) => h += `<div class=\"data-row\"><span class=\"data-label\">${i+1}<\/span><span class=\"data-value small\">${x.label||'\u0411\u0435\u0437 \u0438\u043c\u0435\u043d\u0438'}<\/span><\/div>`); }\n                if (g.audiooutput.length) { h += '<b style=\"display:block;margin-top:8px\">\ud83d\udd0a \u0412\u044b\u0445\u043e\u0434\u044b:<\/b>'; g.audiooutput.forEach((x,i) => h += `<div class=\"data-row\"><span class=\"data-label\">${i+1}<\/span><span class=\"data-value small\">${x.label||'\u0411\u0435\u0437 \u0438\u043c\u0435\u043d\u0438'}<\/span><\/div>`); }\n                $('media-data').innerHTML = h || '\u041d\u0435\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432';\n                s.getTracks().forEach(t => t.stop());\n            } catch(e) { updateStep('media','error',e.name); $('media-data').innerHTML = `<span style=\"color:var(--warning)\">\u274c ${e.name}<\/span>`; }\n        } else { updateStep('media','error','\u041d\u0435\u0442 API'); $('media-data').innerHTML = '<span style=\"color:var(--warning)\">\u041d\u0435\u0442 API<\/span>'; }\n        r();\n    });\n    await delay(200);\n    \n    updateStep('audio', 'active');\n    try {\n        const a = new (window.AudioContext || window.webkitAudioContext)();\n        $('audio-data').innerHTML = `\n            <div class=\"data-row\"><span class=\"data-label\">Sample Rate<\/span><span class=\"data-value\">${a.sampleRate} Hz<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">\u041a\u0430\u043d\u0430\u043b\u044b<\/span><span class=\"data-value\">${a.destination.maxChannelCount}<\/span><\/div>\n            <div class=\"data-row\"><span class=\"data-label\">Latency<\/span><span class=\"data-value\">${a.baseLatency ? (a.baseLatency*1000).toFixed(2)+'ms' : 'N\/A'}<\/span><\/div>`;\n        updateStep('audio', 'completed', `${a.sampleRate} Hz`);\n        a.close();\n    } catch { updateStep('audio','error'); $('audio-data').innerHTML = '<span style=\"color:var(--warning)\">\u041d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d<\/span>'; }\n    await delay(200);\n    \n    updateStep('done', 'completed', '\u0412\u0441\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u044b');\n    $('progress-status').textContent = '\u2705 \u0413\u043e\u0442\u043e\u0432\u043e!';\n    $('progress-fill').classList.remove('animated');\n    btn.disabled = false;\n    btn.textContent = '\ud83d\udd04 \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c';\n}\n\n\/\/ === EVENTS ===\nwindow.addEventListener('resize', () => {\n    $('window-size').textContent = `${innerWidth}\u00d7${innerHeight}`;\n    $('orientation').textContent = innerWidth > innerHeight ? '\ud83d\udda5\ufe0f \u0410\u043b\u044c\u0431\u043e\u043c\u043d\u0430\u044f' : '\ud83d\udcf1 \u041f\u043e\u0440\u0442\u0440\u0435\u0442\u043d\u0430\u044f';\n});\nwindow.addEventListener('online', () => $('online').innerHTML = badge('\u0414\u0430','yes'));\nwindow.addEventListener('offline', () => $('online').innerHTML = badge('\u041d\u0435\u0442','no'));\nwindow.addEventListener('DOMContentLoaded', collectPassiveData);\n<\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>\u041a\u0430\u043a \u0432\u0430\u0441 \u0432\u0438\u0434\u044f\u0442 \u0441\u0430\u0439\u0442\u044b | Device Intelligence \ud83d\udd0d \u041a\u0430\u043a \u0432\u0430\u0441 \u0432\u0438\u0434\u044f\u0442 \u0441\u0430\u0439\u0442\u044b \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0432\u0430\u0448\u0435\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442 \ud83d\udd13 \u0413\u043b\u0443\u0431\u043e\u043a\u043e\u0435 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 GPS, \u043a\u0430\u043c\u0435\u0440\u044b \u0438 \u043c\u0438\u043a\u0440\u043e\u0444\u043e\u043d\u044b \u2014 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u0430\u0448\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f&#8230; 0% \ud83d\ude80 \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0433\u043b\u0443\u0431\u043e\u043a\u0438\u0439 \u0441\u043a\u0430\u043d * \u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0433\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u0438 \u0438 \u043c\u0435\u0434\u0438\u0430 \ud83d\udccd \u0413\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u044f \u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435&#8230; \ud83c\udfa5 \u041a\u0430\u043c\u0435\u0440\u044b\/\u041c\u0438\u043a\u0440\u043e\u0444\u043e\u043d\u044b \u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435&#8230; \ud83d\udd0a \u0410\u0443\u0434\u0438\u043e \u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435&#8230;&hellip;&nbsp;<a href=\"https:\/\/1.cbm.ua\/?p=8974\" rel=\"bookmark\">\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 &raquo;<span class=\"screen-reader-text\">\u041a\u0430\u043a \u0432\u0430\u0441 \u0432\u0438\u0434\u044f\u0442 \u0441\u0430\u0439\u0442\u044b. (\u041a\u0430\u043a\u043e\u0435 \u0443 \u0432\u0430\u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u044b \u043e\u0442\u043a\u0440\u044b\u043b\u0438 \u044d\u0442\u0443 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.)<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"categories":[184,6],"tags":[],"class_list":["post-8974","post","type-post","status-publish","format-standard","hentry","category--script","category-js"],"_links":{"self":[{"href":"https:\/\/1.cbm.ua\/index.php?rest_route=\/wp\/v2\/posts\/8974","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/1.cbm.ua\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/1.cbm.ua\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/1.cbm.ua\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/1.cbm.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=8974"}],"version-history":[{"count":17,"href":"https:\/\/1.cbm.ua\/index.php?rest_route=\/wp\/v2\/posts\/8974\/revisions"}],"predecessor-version":[{"id":9032,"href":"https:\/\/1.cbm.ua\/index.php?rest_route=\/wp\/v2\/posts\/8974\/revisions\/9032"}],"wp:attachment":[{"href":"https:\/\/1.cbm.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=8974"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/1.cbm.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=8974"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/1.cbm.ua\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=8974"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}