{"id":2183,"date":"2026-04-05T05:02:13","date_gmt":"2026-04-05T05:02:13","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=2183"},"modified":"2026-08-08T06:31:17","modified_gmt":"2026-08-08T06:31:17","slug":"bcrypt-hash-generator-verifier","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/bcrypt-hash-generator-verifier\/","title":{"rendered":"Free Bcrypt Hash Generator &amp; Verifier &#8211; Offline Tool"},"content":{"rendered":"<div class=\"pth-hero-section\">\n<div class=\"pth-hero-content\">\n<h2>Free Bcrypt Hash Generator &#038; Verifier &#8211; Offline Tool<\/h2>\n<p>Generate and verify Bcrypt hashes securely with our 100% offline Bcrypt Hash Generator. Adjust cost factors and test password matches instantly.<\/p>\n<div id=\"pth-toc-placeholder\"><\/div>\n<\/p>\n<\/div>\n<div class=\"pth-hero-image\">\n        <img decoding=\"async\" data-no-lazy=\"1\" width=\"450\" height=\"253\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/05\/Bcrypt-Hash-Generator-1024x572.jpeg\" alt=\"Bcrypt Hash Generator\">\n    <\/div>\n<\/div>\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#\ud83d\udfe5-cryptographic-mathematics-of-a-bcrypt-hash-generator\">\ud83d\udfe5 Cryptographic Mathematics of a Bcrypt Hash Generator<\/a><\/li><li><a href=\"#\ud83d\udfe7-adaptive-hashing-and-brute-force-defenses\">\ud83d\udfe7 Adaptive Hashing and Brute-Force Defenses<\/a><\/li><li><a href=\"#\ud83d\udfe8-memory-security-and-offline-compilation\">\ud83d\udfe8 Memory Security and Offline Compilation<\/a><\/li><li><a href=\"#\ud83d\udfe9-verification-standards-and-tool-integration\">\ud83d\udfe9 Verification Standards and Tool Integration<\/a><\/li><\/ul><\/nav><\/div>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<div id=\"pth-bcrypt-wrapper\">\r\n    <style>\r\n        #pth-bcrypt-wrapper { box-sizing: border-box; font-family: 'Inter', system-ui, -apple-system, sans-serif; color: #1e293b; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden; margin: 20px 0; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); }\r\n        #pth-bcrypt-wrapper * { box-sizing: border-box; min-width: 0; }\r\n\r\n        #pth-bcrypt-wrapper .pth-topbar { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; padding: 20px 24px 0; }\r\n        #pth-bcrypt-wrapper .pth-title { margin: 0; font-size: 1.35rem; font-weight: 800; color: #0f172a; }\r\n        #pth-bcrypt-wrapper .pth-toolbar { display: flex; gap: 8px; flex-wrap: wrap; }\r\n        #pth-bcrypt-wrapper .pth-btn { border: none; padding: 8px 14px; font-size: 0.85rem; border-radius: 7px; cursor: pointer; font-weight: 700; font-family: inherit; }\r\n        #pth-bcrypt-wrapper .pth-sample-btn { background: #eff6ff; color: #1d4ed8; }\r\n        #pth-bcrypt-wrapper .pth-sample-btn:hover { background: #dbeafe; }\r\n        #pth-bcrypt-wrapper .pth-fw-btn { background: #e2e8f0; color: #0f172a; }\r\n        #pth-bcrypt-wrapper .pth-fw-btn:hover { background: #cbd5e1; }\r\n        #pth-bcrypt-wrapper .pth-clear-btn { background: #fef2f2; color: #991b1b; }\r\n        #pth-bcrypt-wrapper .pth-clear-btn:hover { background: #fee2e2; }\r\n\r\n        #pth-bcrypt-wrapper .pth-meta-bar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; padding: 8px 24px 0; }\r\n        #pth-bcrypt-wrapper .pth-version-badge { background: #eff6ff; color: #1d4ed8; font-size: 0.72rem; font-weight: 800; padding: 4px 10px; border-radius: 20px; letter-spacing: 0.4px; }\r\n        #pth-bcrypt-wrapper .pth-status-offline { background: #ecfdf5; color: #047857; font-size: 0.72rem; font-weight: 800; padding: 4px 10px; border-radius: 20px; }\r\n\r\n        #pth-bcrypt-wrapper .pth-tabbar { display: flex; gap: 4px; flex-wrap: wrap; padding: 16px 24px 0; border-bottom: 2px solid #e2e8f0; }\r\n        #pth-bcrypt-wrapper .pth-tab-btn { background: transparent; border: none; border-bottom: 3px solid transparent; margin-bottom: -2px; padding: 10px 14px; font-size: 0.86rem; font-weight: 700; color: #334155; cursor: pointer; font-family: inherit; border-radius: 6px 6px 0 0; }\r\n        #pth-bcrypt-wrapper .pth-tab-btn:hover { background: #f1f5f9; color: #0f172a; }\r\n        #pth-bcrypt-wrapper .pth-tab-btn.active { color: #1d4ed8; border-bottom-color: #2563eb; background: #eff6ff; }\r\n\r\n        #pth-bcrypt-wrapper .pth-grid { display: grid; grid-template-columns: 1.8fr 1fr; }\r\n        #pth-bcrypt-wrapper .pth-main { padding: 24px; border-right: 1px solid #e2e8f0; }\r\n        #pth-bcrypt-wrapper .pth-side { padding: 24px; background: #f8fafc; }\r\n        #pth-bcrypt-wrapper .pth-grid.full-width { grid-template-columns: 1fr; }\r\n        #pth-bcrypt-wrapper .pth-grid.full-width .pth-side { display: none; }\r\n        #pth-bcrypt-wrapper .pth-grid.full-width .pth-main { border-right: none; }\r\n\r\n        #pth-bcrypt-wrapper .pth-panel { display: none; }\r\n        #pth-bcrypt-wrapper .pth-panel.active { display: block; }\r\n        #pth-bcrypt-wrapper .pth-panel-intro { font-size: 0.89rem; color: #334155; line-height: 1.6; margin: 0 0 18px; font-weight: 500; }\r\n\r\n        #pth-bcrypt-wrapper .pth-field { margin-bottom: 16px; }\r\n        #pth-bcrypt-wrapper .pth-field > label { display: block; font-size: 0.88rem; font-weight: 700; margin-bottom: 8px; color: #334155; }\r\n        #pth-bcrypt-wrapper .pth-hint { font-size: 0.79rem; color: #334155; font-style: italic; margin: 0 0 6px; }\r\n        #pth-bcrypt-wrapper .pth-inp { width: 100%; padding: 11px 13px; border: 2px solid #cbd5e1; border-radius: 8px; font-family: 'Courier New', monospace; font-size: 0.92rem; color: #0f172a; background: #ffffff; font-weight: 600; }\r\n        #pth-bcrypt-wrapper .pth-inp:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37,99,235,0.12); }\r\n        #pth-bcrypt-wrapper textarea.pth-inp { min-height: 130px; resize: vertical; line-height: 1.6; }\r\n        #pth-bcrypt-wrapper .pth-labelrow { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }\r\n        #pth-bcrypt-wrapper .pth-range { width: 100%; accent-color: #2563eb; }\r\n        #pth-bcrypt-wrapper .pth-valbadge { background: #2563eb; color: #ffffff; font-weight: 800; padding: 3px 12px; border-radius: 20px; font-size: 0.82rem; font-family: monospace; }\r\n        #pth-bcrypt-wrapper .pth-costnote { font-size: 0.8rem; font-weight: 800; }\r\n        #pth-bcrypt-wrapper .pth-c-fast { color: #92400e; }\r\n        #pth-bcrypt-wrapper .pth-c-good { color: #047857; }\r\n        #pth-bcrypt-wrapper .pth-c-slow { color: #991b1b; }\r\n\r\n        #pth-bcrypt-wrapper .pth-action-btn { background: #2563eb; color: #ffffff; border: none; padding: 12px 22px; font-size: 0.92rem; font-weight: 700; border-radius: 8px; cursor: pointer; font-family: inherit; }\r\n        #pth-bcrypt-wrapper .pth-action-btn:hover { background: #1d4ed8; }\r\n        #pth-bcrypt-wrapper .pth-action-btn[disabled] { background: #94a3b8; cursor: progress; }\r\n        #pth-bcrypt-wrapper .pth-mini-btn { background: #ffffff; color: #0f172a; border: 1px solid #cbd5e1; padding: 8px 13px; font-size: 0.8rem; font-weight: 700; border-radius: 6px; cursor: pointer; font-family: inherit; }\r\n        #pth-bcrypt-wrapper .pth-mini-btn:hover { background: #f1f5f9; }\r\n        #pth-bcrypt-wrapper .pth-btn-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }\r\n\r\n        #pth-bcrypt-wrapper .pth-out-box { background: #f8fafc; border: 2px dashed #cbd5e1; border-radius: 10px; padding: 16px; margin-top: 16px; }\r\n        #pth-bcrypt-wrapper .pth-out-text { font-family: 'Courier New', monospace; font-size: 1rem; font-weight: 700; color: #1d4ed8; word-break: break-all; line-height: 1.6; }\r\n        #pth-bcrypt-wrapper .pth-out-meta { font-size: 0.8rem; color: #334155; font-weight: 700; margin-top: 10px; }\r\n\r\n        #pth-bcrypt-wrapper .pth-verdict { padding: 14px 18px; border-radius: 8px; font-weight: 800; font-size: 0.98rem; margin-top: 16px; display: flex; align-items: center; gap: 10px; }\r\n        #pth-bcrypt-wrapper .pth-verdict.ok { background: #059669; color: #ffffff; }\r\n        #pth-bcrypt-wrapper .pth-verdict.bad { background: #dc2626; color: #ffffff; }\r\n        #pth-bcrypt-wrapper .pth-verdict.neutral { background: #e2e8f0; color: #334155; }\r\n\r\n        #pth-bcrypt-wrapper .pth-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px,1fr)); gap: 10px; margin-top: 16px; }\r\n        #pth-bcrypt-wrapper .pth-card { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 13px; }\r\n        #pth-bcrypt-wrapper .pth-card.wide { grid-column: 1 \/ -1; }\r\n        #pth-bcrypt-wrapper .pth-card-lbl { font-size: 0.71rem; color: #334155; font-weight: 800; text-transform: uppercase; letter-spacing: 0.3px; margin-bottom: 5px; }\r\n        #pth-bcrypt-wrapper .pth-card-val { font-size: 1rem; font-weight: 800; color: #0f172a; font-family: monospace; word-break: break-all; }\r\n        #pth-bcrypt-wrapper .pth-card-val.green { color: #047857; }\r\n        #pth-bcrypt-wrapper .pth-card-val.amber { color: #92400e; }\r\n        #pth-bcrypt-wrapper .pth-card-val.blue { color: #1d4ed8; }\r\n\r\n        #pth-bcrypt-wrapper .pth-finding { padding: 12px 14px; border-radius: 8px; font-size: 0.86rem; line-height: 1.55; margin-top: 12px; font-weight: 500; }\r\n        #pth-bcrypt-wrapper .pth-f-ok { background: #ecfdf5; color: #047857; border: 1px solid #a7f3d0; }\r\n        #pth-bcrypt-wrapper .pth-f-warn { background: #fefce8; color: #92400e; border: 1px solid #fde68a; }\r\n        #pth-bcrypt-wrapper .pth-f-crit { background: #fef2f2; color: #991b1b; border: 1px solid #fecaca; }\r\n        #pth-bcrypt-wrapper .pth-f-info { background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe; }\r\n        #pth-bcrypt-wrapper .pth-finding strong { font-weight: 800; }\r\n\r\n        #pth-bcrypt-wrapper .pth-bytebar { height: 26px; background: #e2e8f0; border-radius: 6px; overflow: hidden; display: flex; margin-top: 10px; position: relative; }\r\n        #pth-bcrypt-wrapper .pth-bytefill { height: 100%; background: #059669; transition: width 0.2s; }\r\n        #pth-bcrypt-wrapper .pth-bytefill.over { background: #dc2626; }\r\n        #pth-bcrypt-wrapper .pth-bytecut { height: 100%; background: #fca5a5; }\r\n        #pth-bcrypt-wrapper .pth-byteinfo { display: flex; justify-content: space-between; font-size: 0.8rem; font-weight: 700; color: #334155; margin-top: 6px; }\r\n\r\n        #pth-bcrypt-wrapper .pth-table-wrap { overflow-x: auto; border: 1px solid #e2e8f0; border-radius: 8px; margin-top: 14px; }\r\n        #pth-bcrypt-wrapper table.pth-table { width: 100%; border-collapse: collapse; }\r\n        #pth-bcrypt-wrapper .pth-table th { background: #f1f5f9; color: #334155; font-weight: 800; padding: 10px 12px; text-align: left; font-size: 0.79rem; border-bottom: 2px solid #cbd5e1; }\r\n        #pth-bcrypt-wrapper .pth-table td { padding: 9px 12px; border-bottom: 1px solid #f1f5f9; font-size: 0.85rem; color: #0f172a; }\r\n        #pth-bcrypt-wrapper .pth-table td.mono { font-family: monospace; font-weight: 700; }\r\n        #pth-bcrypt-wrapper tr.row-best td { background: #ecfdf5; }\r\n        #pth-bcrypt-wrapper .pth-tag { padding: 2px 8px; border-radius: 5px; font-size: 0.72rem; font-weight: 800; }\r\n        #pth-bcrypt-wrapper .tag-ok { background: #dcfce7; color: #166534; }\r\n        #pth-bcrypt-wrapper .tag-warn { background: #fef9c3; color: #92400e; }\r\n        #pth-bcrypt-wrapper .tag-bad { background: #fee2e2; color: #991b1b; }\r\n\r\n        #pth-bcrypt-wrapper .pth-list-box { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 14px; font-family: 'Courier New', monospace; font-size: 0.83rem; color: #0f172a; white-space: pre-wrap; word-break: break-all; min-height: 60px; margin-top: 14px; line-height: 1.8; max-height: 340px; overflow-y: auto; }\r\n        #pth-bcrypt-wrapper .pth-progress { height: 8px; background: #e2e8f0; border-radius: 4px; overflow: hidden; margin-top: 12px; }\r\n        #pth-bcrypt-wrapper .pth-progress-fill { height: 100%; background: #2563eb; width: 0%; transition: width 0.2s; }\r\n\r\n        #pth-bcrypt-wrapper .pth-side-title { font-size: 0.95rem; font-weight: 800; margin: 0 0 10px; color: #0f172a; }\r\n        #pth-bcrypt-wrapper .pth-side-title.mt { margin-top: 22px; }\r\n        #pth-bcrypt-wrapper .pth-side-text { font-size: 0.84rem; color: #334155; line-height: 1.65; font-weight: 500; margin: 0 0 12px; }\r\n        #pth-bcrypt-wrapper .pth-anat { font-family: monospace; font-size: 0.82rem; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 8px; padding: 12px; line-height: 2; word-break: break-all; }\r\n        #pth-bcrypt-wrapper .a-alg { background: #fee2e2; color: #991b1b; padding: 2px 4px; border-radius: 3px; font-weight: 800; }\r\n        #pth-bcrypt-wrapper .a-cost { background: #fef9c3; color: #92400e; padding: 2px 4px; border-radius: 3px; font-weight: 800; }\r\n        #pth-bcrypt-wrapper .a-salt { background: #dcfce7; color: #166534; padding: 2px 4px; border-radius: 3px; font-weight: 800; }\r\n        #pth-bcrypt-wrapper .a-hash { background: #dbeafe; color: #1e3a8a; padding: 2px 4px; border-radius: 3px; font-weight: 800; }\r\n        #pth-bcrypt-wrapper .pth-note { background: #fffbeb; border: 1px solid #fde68a; padding: 12px; border-radius: 8px; font-size: 0.83rem; color: #92400e; line-height: 1.55; font-weight: 500; margin-top: 16px; }\r\n        #pth-bcrypt-wrapper .pth-note strong { font-weight: 800; }\r\n        #pth-bcrypt-wrapper .pth-code { background: #e2e8f0; color: #0f172a; padding: 2px 6px; border-radius: 4px; font-family: monospace; font-size: 0.8rem; font-weight: 700; }\r\n        #pth-bcrypt-wrapper .pth-related a { color: #1d4ed8; text-decoration: none; font-weight: 700; }\r\n        #pth-bcrypt-wrapper .pth-related a:hover { text-decoration: underline; }\r\n        #pth-bcrypt-wrapper .pth-related li { margin-bottom: 7px; font-size: 0.85rem; }\r\n\r\n        #pth-bcrypt-wrapper .pth-toast-wrap { position: fixed; bottom: 20px; right: 20px; z-index: 999999; display: flex; flex-direction: column; gap: 8px; }\r\n        #pth-bcrypt-wrapper .pth-toast { padding: 12px 18px; border-radius: 8px; color: #ffffff; font-size: 0.88rem; font-weight: 700; box-shadow: 0 8px 24px rgba(0,0,0,0.18); }\r\n        #pth-bcrypt-wrapper .pth-toast.success { background: #059669; }\r\n        #pth-bcrypt-wrapper .pth-toast.error { background: #dc2626; }\r\n        #pth-bcrypt-wrapper .pth-toast.info { background: #2563eb; }\r\n\r\n        @media (max-width: 900px) {\r\n            #pth-bcrypt-wrapper .pth-grid { grid-template-columns: 1fr; }\r\n            #pth-bcrypt-wrapper .pth-main { border-right: none; border-bottom: 1px solid #e2e8f0; }\r\n        }\r\n    <\/style>\r\n\r\n    <div class=\"pth-topbar\">\r\n        <h2 class=\"pth-title\">Bcrypt Studio Pro<\/h2>\r\n        <div class=\"pth-toolbar\">\r\n            <button type=\"button\" class=\"pth-btn pth-sample-btn\" id=\"pth-bc-sample\">&#128161; Load Sample<\/button>\r\n            <button type=\"button\" class=\"pth-btn pth-fw-btn\" id=\"pth-bc-fw\" aria-label=\"Toggle full width view\">&#9214; Full Width<\/button>\r\n            <button type=\"button\" class=\"pth-btn pth-clear-btn\" id=\"pth-bc-clear\">&#128465;&#65039; Clear<\/button>\r\n        <\/div>\r\n    <\/div>\r\n    <div class=\"pth-meta-bar\">\r\n        <span class=\"pth-version-badge\">BCRYPT STUDIO v5.1<\/span>\r\n        <span class=\"pth-status-offline\">&#128274; 100% Offline<\/span>\r\n    <\/div>\r\n\r\n    <div class=\"pth-tabbar\" role=\"tablist\">\r\n        <button type=\"button\" class=\"pth-tab-btn active\" data-tab=\"gen\" role=\"tab\">&#128272; Generate<\/button>\r\n        <button type=\"button\" class=\"pth-tab-btn\" data-tab=\"verify\" role=\"tab\">&#128737;&#65039; Verify<\/button>\r\n        <button type=\"button\" class=\"pth-tab-btn\" data-tab=\"inspect\" role=\"tab\">&#128269; Hash Inspector<\/button>\r\n        <button type=\"button\" class=\"pth-tab-btn\" data-tab=\"limit\" role=\"tab\">&#9888;&#65039; 72-Byte Limit<\/button>\r\n        <button type=\"button\" class=\"pth-tab-btn\" data-tab=\"bench\" role=\"tab\">&#9201;&#65039; Cost Benchmark<\/button>\r\n    <\/div>\r\n\r\n    <div class=\"pth-grid\" id=\"pth-bc-grid\">\r\n        <div class=\"pth-main\">\r\n\r\n            <!-- TAB 1: GENERATE -->\r\n            <div class=\"pth-panel active\" id=\"pth-panel-gen\" role=\"tabpanel\">\r\n                <p class=\"pth-panel-intro\">Hash a password with a fresh random salt. The work factor is deliberately slow, so a higher cost means a slower login for your users and a far slower attack for everyone else.<\/p>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-bc-gen-in\">Plain text to hash<\/label>\r\n                    <p class=\"pth-hint\">&#8505;&#65039; Nothing leaves this page. Even so, prefer a test value over a live production password.<\/p>\r\n                    <input type=\"text\" id=\"pth-bc-gen-in\" class=\"pth-inp\" autocomplete=\"off\" aria-label=\"Text to hash\" placeholder=\"Enter the password to hash...\">\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                    <div class=\"pth-labelrow\">\r\n                        <label for=\"pth-bc-gen-cost\" style=\"margin:0;\">Cost factor (work rounds)<\/label>\r\n                        <span><span class=\"pth-costnote\" id=\"pth-bc-gen-note\">Balanced<\/span> <span class=\"pth-valbadge\" id=\"pth-bc-gen-badge\">10<\/span><\/span>\r\n                    <\/div>\r\n                    <input type=\"range\" id=\"pth-bc-gen-cost\" class=\"pth-range\" min=\"4\" max=\"15\" step=\"1\" value=\"10\" aria-label=\"Cost factor\">\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-bc-gen-prefix\">Prefix version<\/label>\r\n                    <select id=\"pth-bc-gen-prefix\" class=\"pth-inp\" aria-label=\"Bcrypt prefix version\">\r\n                        <option value=\"b\">$2b$ &mdash; current standard (recommended)<\/option>\r\n                        <option value=\"a\">$2a$ &mdash; legacy, widest compatibility<\/option>\r\n                        <option value=\"y\">$2y$ &mdash; PHP variant<\/option>\r\n                    <\/select>\r\n                <\/div>\r\n                <button type=\"button\" class=\"pth-action-btn\" id=\"pth-bc-gen-run\">&#9889; Generate Hash<\/button>\r\n                <div id=\"pth-bc-gen-warn\"><\/div>\r\n                <div class=\"pth-out-box\" id=\"pth-bc-gen-box\" style=\"display:none;\">\r\n                    <div class=\"pth-out-text\" id=\"pth-bc-gen-out\" aria-live=\"polite\"><\/div>\r\n                    <div class=\"pth-out-meta\" id=\"pth-bc-gen-time\"><\/div>\r\n                    <div class=\"pth-btn-row\">\r\n                        <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-bc-gen-copy\">&#128203; Copy hash<\/button>\r\n                        <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-bc-gen-verify\">&#128737;&#65039; Send to Verify<\/button>\r\n                        <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-bc-gen-inspect\">&#128269; Inspect<\/button>\r\n                        <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-bc-gen-txt\">&#11015;&#65039; Export .txt<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <h3 class=\"pth-side-title mt\">Hash many at once<\/h3>\r\n                <p class=\"pth-panel-intro\" style=\"margin-bottom:12px;\">One password per line, up to 50. Useful for seeding a test database with realistic hashed accounts.<\/p>\r\n                <textarea id=\"pth-bc-bulk-in\" class=\"pth-inp\" aria-label=\"Bulk passwords\" placeholder=\"password123&#10;admin2026&#10;test-account\"><\/textarea>\r\n                <div class=\"pth-btn-row\">\r\n                    <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-bc-bulk-run\">&#128218; Hash all<\/button>\r\n                    <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-bc-bulk-csv\">&#11015;&#65039; Export CSV<\/button>\r\n                <\/div>\r\n                <div class=\"pth-progress\" id=\"pth-bc-bulk-prog\" style=\"display:none;\"><div class=\"pth-progress-fill\" id=\"pth-bc-bulk-fill\"><\/div><\/div>\r\n                <div class=\"pth-list-box\" id=\"pth-bc-bulk-out\" style=\"display:none;\"><\/div>\r\n            <\/div>\r\n\r\n            <!-- TAB 2: VERIFY -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-verify\" role=\"tabpanel\">\r\n                <p class=\"pth-panel-intro\">Check a plain password against an existing hash. The salt and cost are read from the hash itself, which is why no separate salt field is needed.<\/p>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-bc-ver-text\">Plain text<\/label>\r\n                    <input type=\"text\" id=\"pth-bc-ver-text\" class=\"pth-inp\" autocomplete=\"off\" aria-label=\"Plain text to verify\" placeholder=\"The original password...\">\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-bc-ver-hash\">Bcrypt hash<\/label>\r\n                    <input type=\"text\" id=\"pth-bc-ver-hash\" class=\"pth-inp\" autocomplete=\"off\" aria-label=\"Bcrypt hash\" placeholder=\"$2b$10$...\">\r\n                <\/div>\r\n                <button type=\"button\" class=\"pth-action-btn\" id=\"pth-bc-ver-run\">&#128737;&#65039; Verify Match<\/button>\r\n                <div id=\"pth-bc-ver-out\"><\/div>\r\n            <\/div>\r\n\r\n            <!-- TAB 3: INSPECTOR -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-inspect\" role=\"tabpanel\">\r\n                <p class=\"pth-panel-intro\">A bcrypt hash is four fields packed into one string. Paste one and it is taken apart for you, with a verdict on whether its cost still holds up today.<\/p>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-bc-insp-in\">Hash to inspect<\/label>\r\n                    <p class=\"pth-hint\">&#8505;&#65039; Analyses as you type. A complete hash is 60 characters.<\/p>\r\n                    <input type=\"text\" id=\"pth-bc-insp-in\" class=\"pth-inp\" autocomplete=\"off\" aria-label=\"Hash to inspect\" placeholder=\"$2b$12$...\">\r\n                <\/div>\r\n                <div id=\"pth-bc-insp-out\"><\/div>\r\n            <\/div>\r\n\r\n            <!-- TAB 4: 72-BYTE LIMIT -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-limit\" role=\"tabpanel\">\r\n                <p class=\"pth-panel-intro\">Bcrypt silently ignores everything past 72 <strong>bytes<\/strong>, not characters. Two different long passwords can therefore unlock the same account, and no error is ever raised.<\/p>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-bc-lim-in\">Password to measure<\/label>\r\n                    <p class=\"pth-hint\">&#8505;&#65039; Non-Latin scripts cost more than one byte per character, so the limit arrives much sooner than the character count suggests.<\/p>\r\n                    <input type=\"text\" id=\"pth-bc-lim-in\" class=\"pth-inp\" autocomplete=\"off\" aria-label=\"Password to measure\" placeholder=\"Type or paste a password...\">\r\n                <\/div>\r\n                <div class=\"pth-bytebar\" id=\"pth-bc-lim-bar\"><div class=\"pth-bytefill\" id=\"pth-bc-lim-fill\" style=\"width:0%;\"><\/div><div class=\"pth-bytecut\" id=\"pth-bc-lim-cut\" style=\"width:0%;\"><\/div><\/div>\r\n                <div class=\"pth-byteinfo\"><span id=\"pth-bc-lim-left\">0 bytes used<\/span><span>72-byte limit<\/span><\/div>\r\n                <div class=\"pth-cards\">\r\n                    <div class=\"pth-card\"><div class=\"pth-card-lbl\">Characters<\/div><div class=\"pth-card-val\" id=\"pth-bc-lim-chars\">0<\/div><\/div>\r\n                    <div class=\"pth-card\"><div class=\"pth-card-lbl\">UTF-8 bytes<\/div><div class=\"pth-card-val blue\" id=\"pth-bc-lim-bytes\">0<\/div><\/div>\r\n                    <div class=\"pth-card\"><div class=\"pth-card-lbl\">Bytes ignored<\/div><div class=\"pth-card-val\" id=\"pth-bc-lim-lost\">0<\/div><\/div>\r\n                <\/div>\r\n                <div id=\"pth-bc-lim-verdict\"><\/div>\r\n                <div id=\"pth-bc-lim-script\"><\/div>\r\n                <h3 class=\"pth-side-title mt\">See the collision for yourself<\/h3>\r\n                <p class=\"pth-panel-intro\" style=\"margin-bottom:12px;\">This builds two passwords that are identical for the first 72 bytes and completely different afterwards, hashes the first, then checks the second against it.<\/p>\r\n                <button type=\"button\" class=\"pth-action-btn\" id=\"pth-bc-lim-demo\">&#9888;&#65039; Run collision demo<\/button>\r\n                <div id=\"pth-bc-lim-demo-out\"><\/div>\r\n            <\/div>\r\n\r\n            <!-- TAB 5: BENCHMARK -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-bench\" role=\"tabpanel\">\r\n                <p class=\"pth-panel-intro\">Cost is not a score, it is a time budget. This measures how long each cost factor actually takes on <strong>this<\/strong> device, then suggests the highest cost your login flow can afford.<\/p>\r\n                <div class=\"pth-field\">\r\n                    <div class=\"pth-labelrow\">\r\n                        <label for=\"pth-bc-bench-max\" style=\"margin:0;\">Test up to cost<\/label>\r\n                        <span class=\"pth-valbadge\" id=\"pth-bc-bench-badge\">12<\/span>\r\n                    <\/div>\r\n                    <input type=\"range\" id=\"pth-bc-bench-max\" class=\"pth-range\" min=\"8\" max=\"14\" step=\"1\" value=\"12\" aria-label=\"Maximum cost to benchmark\">\r\n                    <p class=\"pth-hint\" style=\"margin-top:6px;\">&#8505;&#65039; Each step doubles the work. Cost 14 can take several seconds and the page will pause while it runs.<\/p>\r\n                <\/div>\r\n                <button type=\"button\" class=\"pth-action-btn\" id=\"pth-bc-bench-run\">&#9201;&#65039; Run Benchmark<\/button>\r\n                <div class=\"pth-progress\" id=\"pth-bc-bench-prog\" style=\"display:none;\"><div class=\"pth-progress-fill\" id=\"pth-bc-bench-fill\"><\/div><\/div>\r\n                <div id=\"pth-bc-bench-out\"><\/div>\r\n            <\/div>\r\n\r\n        <\/div>\r\n\r\n        <div class=\"pth-side\">\r\n            <h3 class=\"pth-side-title\">Anatomy of a hash<\/h3>\r\n            <div class=\"pth-anat\">\r\n                <span class=\"a-alg\">$2b$<\/span><span class=\"a-cost\">12$<\/span><span class=\"a-salt\">LQv3c1yqBWVHxkd0LHAkCO<\/span><span class=\"a-hash\">YzGH7.whpTQOMUZ2bXQ0M8kO1qXeS<\/span>\r\n            <\/div>\r\n            <p class=\"pth-side-text\" style=\"margin-top:12px;\">\r\n                <span class=\"a-alg\">Prefix<\/span> the algorithm version.<br>\r\n                <span class=\"a-cost\">Cost<\/span> 2 to the power of this many rounds.<br>\r\n                <span class=\"a-salt\">Salt<\/span> 22 characters, random per hash.<br>\r\n                <span class=\"a-hash\">Digest<\/span> 31 characters of output.\r\n            <\/p>\r\n\r\n            <h3 class=\"pth-side-title mt\">Why the salt is inside<\/h3>\r\n            <p class=\"pth-side-text\">The salt travels with the hash, so two identical passwords still produce two completely different strings. That is what makes precomputed rainbow tables useless against bcrypt.<\/p>\r\n\r\n            <div class=\"pth-note\"><strong>&#128274; Runs on your device.<\/strong> The bcrypt implementation is written into this page &mdash; no library is fetched and no password is sent anywhere. Hashing is genuinely slow by design, so higher costs will briefly freeze the tab.<\/div>\r\n\r\n            <h3 class=\"pth-side-title mt\">Related Tools<\/h3>\r\n            <ul class=\"pth-related\" style=\"list-style:none; padding:0; margin:0;\">\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/free-strong-password-generator\/\">Password Studio<\/a><\/li>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/free-secure-hash-generator\/\">SHA Hash Generator<\/a><\/li>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/jwt-decoder-inspector\/\">JWT Studio<\/a><\/li>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/uuid-guid-generator-validator\/\">UUID Generator<\/a><\/li>\r\n            <\/ul>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"pth-toast-wrap\" id=\"pth-bc-toast-wrap\" aria-live=\"assertive\"><\/div>\r\n\r\n    <script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n    (function () {\r\n        'use strict';\r\n        if (window.pthBcryptApp) { return; }\r\n\r\n        \/* Angle-bracket + quote helpers from char codes, so no raw tag substring or\r\n           bare quote-regex sits in this script. WordPress\/LiteSpeed mangles raw\r\n           closing-tag substrings inside inline scripts and kills the whole block\r\n           (every button dies); this keeps the file free of raw tag literals. *\/\r\n        var LT = String.fromCharCode(60); \/* < *\/\r\n        var GT = String.fromCharCode(62); \/* > *\/\r\n        var QT = String.fromCharCode(34); \/* \" *\/\r\n\r\n    \/* ==================== SELF-CONTAINED BCRYPT ENGINE ====================\r\n       Blowfish \/ EksBlowfish. Verified bit-for-bit against the reference\r\n       implementation and the published OpenBSD test vectors. No CDN.\r\n       ==================================================================== *\/\r\n    var PTHBcrypt = (function () {\r\n\/* Self-contained bcrypt (Blowfish \/ EksBlowfish) - ES5, no dependencies *\/\r\n\r\n        var P_ORIG = [\r\n            0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,\r\n            0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,\r\n            0x9216d5d9, 0x8979fb1b\r\n        ];\r\n\r\n        var S_ORIG = [\r\n            0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,\r\n            0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,\r\n            0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,\r\n            0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,\r\n            0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,\r\n            0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,\r\n            0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,\r\n            0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,\r\n            0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,\r\n            0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,\r\n            0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,\r\n            0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,\r\n            0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,\r\n            0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,\r\n            0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,\r\n            0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,\r\n            0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,\r\n            0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,\r\n            0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,\r\n            0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,\r\n            0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,\r\n            0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,\r\n            0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,\r\n            0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,\r\n            0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,\r\n            0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,\r\n            0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,\r\n            0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,\r\n            0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,\r\n            0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,\r\n            0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,\r\n            0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,\r\n            0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,\r\n            0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,\r\n            0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,\r\n            0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,\r\n            0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,\r\n            0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,\r\n            0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,\r\n            0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,\r\n            0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,\r\n            0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,\r\n            0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,\r\n            0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,\r\n            0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,\r\n            0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,\r\n            0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,\r\n            0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,\r\n            0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,\r\n            0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,\r\n            0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,\r\n            0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,\r\n            0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,\r\n            0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,\r\n            0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,\r\n            0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,\r\n            0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,\r\n            0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,\r\n            0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,\r\n            0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,\r\n            0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,\r\n            0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,\r\n            0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,\r\n            0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,\r\n            0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,\r\n            0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,\r\n            0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,\r\n            0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,\r\n            0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,\r\n            0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,\r\n            0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,\r\n            0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,\r\n            0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,\r\n            0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,\r\n            0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,\r\n            0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,\r\n            0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,\r\n            0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,\r\n            0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,\r\n            0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,\r\n            0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,\r\n            0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,\r\n            0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,\r\n            0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,\r\n            0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,\r\n            0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,\r\n            0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,\r\n            0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,\r\n            0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,\r\n            0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,\r\n            0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,\r\n            0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,\r\n            0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,\r\n            0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,\r\n            0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,\r\n            0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,\r\n            0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,\r\n            0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,\r\n            0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,\r\n            0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,\r\n            0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,\r\n            0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,\r\n            0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,\r\n            0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,\r\n            0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,\r\n            0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,\r\n            0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,\r\n            0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,\r\n            0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,\r\n            0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,\r\n            0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,\r\n            0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,\r\n            0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,\r\n            0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,\r\n            0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,\r\n            0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,\r\n            0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,\r\n            0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,\r\n            0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,\r\n            0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,\r\n            0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,\r\n            0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,\r\n            0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,\r\n            0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,\r\n            0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,\r\n            0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,\r\n            0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,\r\n            0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6\r\n        ];\r\n\r\n    var C_ORIG = [0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274];\r\n\r\n    var BASE64_CODE = '.\/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split('');\r\n    var BASE64_INDEX = (function () {\r\n        var m = {}, i;\r\n        for (i = 0; i < BASE64_CODE.length; i++) { m[BASE64_CODE[i]] = i; }\r\n        return m;\r\n    })();\r\n\r\n    \/* --- bcrypt's own base64 --- *\/\r\n    function b64encode(bytes, len) {\r\n        var off = 0, rs = [], c1, c2;\r\n        if (len <= 0 || len > bytes.length) { throw new Error('Illegal length'); }\r\n        while (off < len) {\r\n            c1 = bytes[off++] & 0xff;\r\n            rs.push(BASE64_CODE[(c1 >> 2) & 0x3f]);\r\n            c1 = (c1 & 0x03) << 4;\r\n            if (off >= len) { rs.push(BASE64_CODE[c1 & 0x3f]); break; }\r\n            c2 = bytes[off++] & 0xff;\r\n            c1 |= (c2 >> 4) & 0x0f;\r\n            rs.push(BASE64_CODE[c1 & 0x3f]);\r\n            c1 = (c2 & 0x0f) << 2;\r\n            if (off >= len) { rs.push(BASE64_CODE[c1 & 0x3f]); break; }\r\n            c2 = bytes[off++] & 0xff;\r\n            c1 |= (c2 >> 6) & 0x03;\r\n            rs.push(BASE64_CODE[c1 & 0x3f]);\r\n            rs.push(BASE64_CODE[c2 & 0x3f]);\r\n        }\r\n        return rs.join('');\r\n    }\r\n\r\n    function b64decode(s, len) {\r\n        var off = 0, slen = s.length, olen = 0, rs = [], c1, c2, c3, c4, o, code;\r\n        if (len <= 0) { throw new Error('Illegal length'); }\r\n        while (off < slen - 1 && olen < len) {\r\n            code = s.charAt(off++);\r\n            c1 = BASE64_INDEX[code] === undefined ? -1 : BASE64_INDEX[code];\r\n            code = s.charAt(off++);\r\n            c2 = BASE64_INDEX[code] === undefined ? -1 : BASE64_INDEX[code];\r\n            if (c1 === -1 || c2 === -1) { break; }\r\n            o = (c1 << 2) >>> 0;\r\n            o |= (c2 & 0x30) >> 4;\r\n            rs.push(String.fromCharCode(o));\r\n            if (++olen >= len || off >= slen) { break; }\r\n            code = s.charAt(off++);\r\n            c3 = BASE64_INDEX[code] === undefined ? -1 : BASE64_INDEX[code];\r\n            if (c3 === -1) { break; }\r\n            o = ((c2 & 0x0f) << 4) >>> 0;\r\n            o |= (c3 & 0x3c) >> 2;\r\n            rs.push(String.fromCharCode(o));\r\n            if (++olen >= len || off >= slen) { break; }\r\n            code = s.charAt(off++);\r\n            c4 = BASE64_INDEX[code] === undefined ? -1 : BASE64_INDEX[code];\r\n            o = ((c3 & 0x03) << 6) >>> 0;\r\n            o |= c4;\r\n            rs.push(String.fromCharCode(o));\r\n            ++olen;\r\n        }\r\n        var res = [];\r\n        for (off = 0; off < olen; off++) { res.push(rs[off].charCodeAt(0)); }\r\n        return res;\r\n    }\r\n\r\n    \/* --- UTF-8 --- *\/\r\n    function utf8Bytes(str) {\r\n        var out = [], i, c;\r\n        for (i = 0; i < str.length; i++) {\r\n            c = str.charCodeAt(i);\r\n            if (c < 128) { out.push(c); }\r\n            else if (c < 2048) { out.push((c >> 6) | 192, (c & 63) | 128); }\r\n            else if (c >= 0xD800 && c <= 0xDBFF && i + 1 < str.length) {\r\n                var c2 = str.charCodeAt(i + 1);\r\n                if (c2 >= 0xDC00 && c2 <= 0xDFFF) {\r\n                    var cp = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;\r\n                    out.push((cp >> 18) | 240, ((cp >> 12) & 63) | 128, ((cp >> 6) & 63) | 128, (cp & 63) | 128);\r\n                    i++;\r\n                } else { out.push((c >> 12) | 224, ((c >> 6) & 63) | 128, (c & 63) | 128); }\r\n            }\r\n            else { out.push((c >> 12) | 224, ((c >> 6) & 63) | 128, (c & 63) | 128); }\r\n        }\r\n        return out;\r\n    }\r\n\r\n    \/* --- Blowfish core --- *\/\r\n    function encipher(lr, off, P, S) {\r\n        var n, l = lr[off], r = lr[off + 1];\r\n        l ^= P[0];\r\n        for (var i = 0; i <= 15;) {\r\n            n = S[(l >> 24) & 0xff];\r\n            n += S[0x100 | ((l >> 16) & 0xff)];\r\n            n ^= S[0x200 | ((l >> 8) & 0xff)];\r\n            n += S[0x300 | (l & 0xff)];\r\n            r ^= (n ^ P[++i]);\r\n            n = S[(r >> 24) & 0xff];\r\n            n += S[0x100 | ((r >> 16) & 0xff)];\r\n            n ^= S[0x200 | ((r >> 8) & 0xff)];\r\n            n += S[0x300 | (r & 0xff)];\r\n            l ^= (n ^ P[++i]);\r\n        }\r\n        lr[off] = r ^ P[17];\r\n        lr[off + 1] = l;\r\n        return lr;\r\n    }\r\n\r\n    function streamToWord(data, offp) {\r\n        var word = 0, off = offp[0];\r\n        for (var i = 0; i < 4; i++) {\r\n            word = (word << 8) | (data[off] & 0xff);\r\n            off = (off + 1) % data.length;\r\n        }\r\n        offp[0] = off;\r\n        return word;\r\n    }\r\n\r\n    function key(k, P, S) {\r\n        var offp = [0], i, sw;\r\n        for (i = 0; i < 18; i++) { P[i] = P[i] ^ streamToWord(k, offp); }\r\n        var lr = [0, 0];\r\n        for (i = 0; i < 18; i += 2) {\r\n            lr = encipher(lr, 0, P, S);\r\n            P[i] = lr[0]; P[i + 1] = lr[1];\r\n        }\r\n        for (i = 0; i < 1024; i += 2) {\r\n            lr = encipher(lr, 0, P, S);\r\n            S[i] = lr[0]; S[i + 1] = lr[1];\r\n        }\r\n    }\r\n\r\n    function ekskey(data, k, P, S) {\r\n        var offp = [0], doffp = [0], i, lr = [0, 0];\r\n        for (i = 0; i < 18; i++) { P[i] = P[i] ^ streamToWord(k, offp); }\r\n        offp[0] = 0;\r\n        for (i = 0; i < 18; i += 2) {\r\n            lr[0] ^= streamToWord(data, doffp);\r\n            lr[1] ^= streamToWord(data, doffp);\r\n            lr = encipher(lr, 0, P, S);\r\n            P[i] = lr[0]; P[i + 1] = lr[1];\r\n        }\r\n        for (i = 0; i < 1024; i += 2) {\r\n            lr[0] ^= streamToWord(data, doffp);\r\n            lr[1] ^= streamToWord(data, doffp);\r\n            lr = encipher(lr, 0, P, S);\r\n            S[i] = lr[0]; S[i + 1] = lr[1];\r\n        }\r\n    }\r\n\r\n    function crypt_raw(b, salt, rounds) {\r\n        var cdata = C_ORIG.slice(), clen = cdata.length, i, j, rnds;\r\n        if (rounds < 4 || rounds > 31) { throw new Error('Illegal number of rounds (4-31): ' + rounds); }\r\n        if (salt.length !== 16) { throw new Error('Illegal salt length: ' + salt.length + ' != 16'); }\r\n        rnds = 1 << rounds;\r\n\r\n        var P = P_ORIG.slice(), S = S_ORIG.slice();\r\n        ekskey(salt, b, P, S);\r\n        for (i = 0; i < rnds; i++) {\r\n            key(b, P, S);\r\n            key(salt, P, S);\r\n        }\r\n        for (i = 0; i < 64; i++) {\r\n            for (j = 0; j < (clen >> 1); j++) { encipher(cdata, j << 1, P, S); }\r\n        }\r\n        var ret = [];\r\n        for (i = 0; i < clen; i++) {\r\n            ret.push(((cdata[i] >> 24) & 0xff) >>> 0);\r\n            ret.push(((cdata[i] >> 16) & 0xff) >>> 0);\r\n            ret.push(((cdata[i] >> 8) & 0xff) >>> 0);\r\n            ret.push((cdata[i] & 0xff) >>> 0);\r\n        }\r\n        return ret;\r\n    }\r\n\r\n    function hashRaw(password, salt) {\r\n        var minor, offset, rounds, real_salt, passwordb, saltb;\r\n        if (salt.charAt(0) !== '$' || salt.charAt(1) !== '2') { throw new Error('Invalid salt version'); }\r\n        if (salt.charAt(2) === '$') { minor = String.fromCharCode(0); offset = 3; }\r\n        else {\r\n            minor = salt.charAt(2);\r\n            if ((minor !== 'a' && minor !== 'b' && minor !== 'y') || salt.charAt(3) !== '$') { throw new Error('Invalid salt revision'); }\r\n            offset = 4;\r\n        }\r\n        if (salt.charAt(offset + 2) > '$') { throw new Error('Missing salt rounds'); }\r\n        var r1 = parseInt(salt.substring(offset, offset + 1), 10) * 10;\r\n        var r2 = parseInt(salt.substring(offset + 1, offset + 2), 10);\r\n        rounds = r1 + r2;\r\n        real_salt = salt.substring(offset + 3, offset + 25);\r\n\r\n        passwordb = utf8Bytes(password + (minor >= 'a' ? '\\u0000' : ''));\r\n        saltb = b64decode(real_salt, 16);\r\n\r\n        var hashed = crypt_raw(passwordb, saltb, rounds);\r\n        var rs = [];\r\n        rs.push('$2');\r\n        if (minor >= 'a') { rs.push(minor); }\r\n        rs.push('$');\r\n        if (rounds < 10) { rs.push('0'); }\r\n        rs.push(String(rounds));\r\n        rs.push('$');\r\n        rs.push(b64encode(saltb, saltb.length));\r\n        rs.push(b64encode(hashed, C_ORIG.length * 4 - 1));\r\n        return rs.join('');\r\n    }\r\n\r\n    function randomBytes(len) {\r\n        var out = new Uint8Array(len), i;\r\n        if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {\r\n            window.crypto.getRandomValues(out);\r\n        } else if (typeof require === 'function') {\r\n            var nb = require('crypto').randomBytes(len);\r\n            for (i = 0; i < len; i++) { out[i] = nb[i]; }\r\n        } else { throw new Error('No secure random source available'); }\r\n        var arr = [];\r\n        for (i = 0; i < len; i++) { arr.push(out[i]); }\r\n        return arr;\r\n    }\r\n\r\n    function genSalt(rounds, minor) {\r\n        rounds = rounds || 10;\r\n        minor = minor || 'b';\r\n        if (rounds < 4 || rounds > 31) { throw new Error('Illegal number of rounds (4-31)'); }\r\n        var salt = ['$2', minor, '$'];\r\n        if (rounds < 10) { salt.push('0'); }\r\n        salt.push(String(rounds));\r\n        salt.push('$');\r\n        salt.push(b64encode(randomBytes(16), 16));\r\n        return salt.join('');\r\n    }\r\n\r\n    function hash(password, rounds, minor) {\r\n        return hashRaw(password, genSalt(rounds, minor));\r\n    }\r\n\r\n    \/* constant-time-ish compare *\/\r\n    function compare(password, hashStr) {\r\n        if (typeof password !== 'string' || typeof hashStr !== 'string') { return false; }\r\n        if (hashStr.length !== 60) { return false; }\r\n        var computed;\r\n        try { computed = hashRaw(password, hashStr.substring(0, 29)); }\r\n        catch (e) { return false; }\r\n        if (computed.length !== hashStr.length) { return false; }\r\n        var diff = 0;\r\n        for (var i = 0; i < computed.length; i++) { diff |= computed.charCodeAt(i) ^ hashStr.charCodeAt(i); }\r\n        return diff === 0;\r\n    }\r\n\r\n    function byteLength(str) { return utf8Bytes(str).length; }\r\n\r\n    return {\r\n        hash: hash,\r\n        hashRaw: hashRaw,\r\n        genSalt: genSalt,\r\n        compare: compare,\r\n        byteLength: byteLength,\r\n        utf8Bytes: utf8Bytes\r\n    };\r\n    })();\r\n\r\n    \/* ==================== APP ==================== *\/\r\n        window.pthBcryptApp = {\r\n            initialized: false,\r\n            lastHash: '',\r\n            bulkRows: [],\r\n            benchRows: [],\r\n\r\n            init: function () {\r\n                this.wrapper = document.getElementById('pth-bcrypt-wrapper');\r\n                if (!this.wrapper) { return; }\r\n                this.grid = document.getElementById('pth-bc-grid');\r\n                this.activeTab = 'gen';\r\n                this.attachEvents();\r\n                this.updateCostNote();\r\n                this.updateLimit();\r\n                this.applyDeepLink();\r\n            },\r\n\r\n            applyDeepLink: function () {\r\n                try {\r\n                    var t = new URLSearchParams(window.location.search).get('tab');\r\n                    if (t) { this.switchTab(t); }\r\n                } catch (e) {}\r\n            },\r\n\r\n            attachEvents: function () {\r\n                var self = this, i;\r\n                var tabs = this.wrapper.querySelectorAll('.pth-tab-btn');\r\n                for (i = 0; i < tabs.length; i++) {\r\n                    tabs[i].addEventListener('click', function () { self.switchTab(this.getAttribute('data-tab')); });\r\n                }\r\n                document.getElementById('pth-bc-sample').addEventListener('click', function () { self.loadSample(); });\r\n                document.getElementById('pth-bc-clear').addEventListener('click', function () { self.clearActive(); });\r\n                document.getElementById('pth-bc-fw').addEventListener('click', function () { self.toggleWidth(); });\r\n\r\n                document.getElementById('pth-bc-gen-cost').addEventListener('input', function () { self.updateCostNote(); });\r\n                document.getElementById('pth-bc-gen-run').addEventListener('click', function () { self.runGenerate(); });\r\n                document.getElementById('pth-bc-gen-in').addEventListener('input', function () { self.checkGenBytes(); });\r\n                document.getElementById('pth-bc-gen-copy').addEventListener('click', function () { self.copyText(self.lastHash); });\r\n                document.getElementById('pth-bc-gen-txt').addEventListener('click', function () {\r\n                    if (!self.lastHash) { self.showToast('Generate a hash first', 'info'); return; }\r\n                    self.download('Generated offline with primetoolhub.com\\n\\n' + self.lastHash + '\\n', 'bcrypt-hash.txt', 'text\/plain');\r\n                });\r\n                document.getElementById('pth-bc-gen-verify').addEventListener('click', function () {\r\n                    if (!self.lastHash) { self.showToast('Generate a hash first', 'info'); return; }\r\n                    document.getElementById('pth-bc-ver-hash').value = self.lastHash;\r\n                    document.getElementById('pth-bc-ver-text').value = document.getElementById('pth-bc-gen-in').value;\r\n                    self.switchTab('verify');\r\n                    self.runVerify();\r\n                });\r\n                document.getElementById('pth-bc-gen-inspect').addEventListener('click', function () {\r\n                    if (!self.lastHash) { self.showToast('Generate a hash first', 'info'); return; }\r\n                    document.getElementById('pth-bc-insp-in').value = self.lastHash;\r\n                    self.switchTab('inspect');\r\n                    self.runInspect();\r\n                });\r\n\r\n                document.getElementById('pth-bc-bulk-run').addEventListener('click', function () { self.runBulk(); });\r\n                document.getElementById('pth-bc-bulk-csv').addEventListener('click', function () { self.exportBulkCsv(); });\r\n\r\n                document.getElementById('pth-bc-ver-run').addEventListener('click', function () { self.runVerify(); });\r\n                document.getElementById('pth-bc-insp-in').addEventListener('input', function () { self.runInspect(); });\r\n                document.getElementById('pth-bc-lim-in').addEventListener('input', function () { self.updateLimit(); });\r\n                document.getElementById('pth-bc-lim-demo').addEventListener('click', function () { self.runCollisionDemo(); });\r\n\r\n                document.getElementById('pth-bc-bench-max').addEventListener('input', function () {\r\n                    document.getElementById('pth-bc-bench-badge').textContent = this.value;\r\n                });\r\n                document.getElementById('pth-bc-bench-run').addEventListener('click', function () { self.runBenchmark(); });\r\n            },\r\n\r\n            switchTab: function (name) {\r\n                var valid = { gen:1, verify:1, inspect:1, limit:1, bench:1 };\r\n                if (!valid[name]) { return; }\r\n                this.activeTab = name;\r\n                var i, tabs = this.wrapper.querySelectorAll('.pth-tab-btn');\r\n                for (i = 0; i < tabs.length; i++) {\r\n                    if (tabs[i].getAttribute('data-tab') === name) { tabs[i].classList.add('active'); }\r\n                    else { tabs[i].classList.remove('active'); }\r\n                }\r\n                var panels = this.wrapper.querySelectorAll('.pth-panel');\r\n                for (i = 0; i < panels.length; i++) {\r\n                    if (panels[i].id === 'pth-panel-' + name) { panels[i].classList.add('active'); }\r\n                    else { panels[i].classList.remove('active'); }\r\n                }\r\n            },\r\n\r\n            toggleWidth: function () {\r\n                this.grid.classList.toggle('full-width');\r\n                var b = document.getElementById('pth-bc-fw');\r\n                b.textContent = this.grid.classList.contains('full-width') ? '\\u25E7 Split View' : '\\u26F6 Full Width';\r\n            },\r\n\r\n            escapeHtml: function (s) {\r\n                return String(s).replace(\/&\/g, '&amp;').replace(new RegExp(LT, 'g'), '&lt;').replace(new RegExp(GT, 'g'), '&gt;').replace(new RegExp(QT, 'g'), '&quot;');\r\n            },\r\n\r\n            loadSample: function () {\r\n                var t = this.activeTab;\r\n                if (t === 'gen') {\r\n                    document.getElementById('pth-bc-gen-in').value = 'CorrectHorseBatteryStaple';\r\n                    document.getElementById('pth-bc-gen-cost').value = 10;\r\n                    this.updateCostNote();\r\n                    this.checkGenBytes();\r\n                    this.runGenerate();\r\n                } else if (t === 'verify') {\r\n                    var self = this;\r\n                    var pw = 'CorrectHorseBatteryStaple';\r\n                    var h = PTHBcrypt.hash(pw, 8, 'b');\r\n                    document.getElementById('pth-bc-ver-text').value = pw;\r\n                    document.getElementById('pth-bc-ver-hash').value = h;\r\n                    self.runVerify();\r\n                } else if (t === 'inspect') {\r\n                    document.getElementById('pth-bc-insp-in').value = PTHBcrypt.hash('sample', 12, 'b');\r\n                    this.runInspect();\r\n                } else if (t === 'limit') {\r\n                    document.getElementById('pth-bc-lim-in').value = 'this-passphrase-is-deliberately-long-so-that-it-runs-past-the-seventy-two-byte-ceiling';\r\n                    this.updateLimit();\r\n                } else if (t === 'bench') {\r\n                    document.getElementById('pth-bc-bench-max').value = 12;\r\n                    document.getElementById('pth-bc-bench-badge').textContent = '12';\r\n                }\r\n                this.showToast('Sample loaded', 'success');\r\n            },\r\n\r\n            clearActive: function () {\r\n                var t = this.activeTab;\r\n                if (t === 'gen') {\r\n                    document.getElementById('pth-bc-gen-in').value = '';\r\n                    document.getElementById('pth-bc-gen-box').style.display = 'none';\r\n                    document.getElementById('pth-bc-gen-warn').innerHTML = '';\r\n                    document.getElementById('pth-bc-bulk-in').value = '';\r\n                    document.getElementById('pth-bc-bulk-out').style.display = 'none';\r\n                    this.lastHash = ''; this.bulkRows = [];\r\n                } else if (t === 'verify') {\r\n                    document.getElementById('pth-bc-ver-text').value = '';\r\n                    document.getElementById('pth-bc-ver-hash').value = '';\r\n                    document.getElementById('pth-bc-ver-out').innerHTML = '';\r\n                } else if (t === 'inspect') {\r\n                    document.getElementById('pth-bc-insp-in').value = '';\r\n                    document.getElementById('pth-bc-insp-out').innerHTML = '';\r\n                } else if (t === 'limit') {\r\n                    document.getElementById('pth-bc-lim-in').value = '';\r\n                    document.getElementById('pth-bc-lim-demo-out').innerHTML = '';\r\n                    this.updateLimit();\r\n                } else if (t === 'bench') {\r\n                    document.getElementById('pth-bc-bench-out').innerHTML = '';\r\n                    this.benchRows = [];\r\n                }\r\n                this.showToast('Cleared', 'info');\r\n            },\r\n\r\n            \/* ---------- cost helpers ---------- *\/\r\n            costNote: function (c) {\r\n                if (c <= 7) { return { t: 'Too fast for production', c: 'pth-c-fast' }; }\r\n                if (c <= 9) { return { t: 'Low, acceptable for testing', c: 'pth-c-fast' }; }\r\n                if (c <= 12) { return { t: 'Balanced', c: 'pth-c-good' }; }\r\n                if (c <= 13) { return { t: 'Strong, slower logins', c: 'pth-c-good' }; }\r\n                return { t: 'Very slow, check your budget', c: 'pth-c-slow' };\r\n            },\r\n\r\n            updateCostNote: function () {\r\n                var c = parseInt(document.getElementById('pth-bc-gen-cost').value, 10);\r\n                document.getElementById('pth-bc-gen-badge').textContent = c;\r\n                var n = this.costNote(c);\r\n                var el = document.getElementById('pth-bc-gen-note');\r\n                el.textContent = n.t;\r\n                el.className = 'pth-costnote ' + n.c;\r\n            },\r\n\r\n            checkGenBytes: function () {\r\n                var v = document.getElementById('pth-bc-gen-in').value;\r\n                var b = PTHBcrypt.byteLength(v);\r\n                var box = document.getElementById('pth-bc-gen-warn');\r\n                if (b > 72) {\r\n                    box.innerHTML = '' + LT + 'div class=\"pth-finding pth-f-crit\">' + LT + 'strong>Past the 72-byte limit.' + LT + '\/strong> This input is ' + b +\r\n                        ' bytes, so bcrypt will ignore the last ' + (b - 72) + '. Open the 72-Byte Limit tab to see exactly what gets dropped.' + LT + '\/div>';\r\n                } else { box.innerHTML = ''; }\r\n            },\r\n\r\n            \/* ---------- TAB 1 ---------- *\/\r\n            runGenerate: function () {\r\n                var self = this;\r\n                var pw = document.getElementById('pth-bc-gen-in').value;\r\n                if (!pw) { this.showToast('Enter some text to hash', 'info'); return; }\r\n                var cost = parseInt(document.getElementById('pth-bc-gen-cost').value, 10);\r\n                var prefix = document.getElementById('pth-bc-gen-prefix').value;\r\n                var btn = document.getElementById('pth-bc-gen-run');\r\n                btn.disabled = true;\r\n                btn.textContent = '\\u23F3 Hashing at cost ' + cost + '...';\r\n\r\n                setTimeout(function () {\r\n                    var t0 = (new Date()).getTime(), hash, err = null;\r\n                    try { hash = PTHBcrypt.hash(pw, cost, prefix); }\r\n                    catch (e) { err = e.message; }\r\n                    var ms = (new Date()).getTime() - t0;\r\n                    btn.disabled = false;\r\n                    btn.textContent = '\\u26A1 Generate Hash';\r\n                    if (err) { self.showToast(err, 'error'); return; }\r\n                    self.lastHash = hash;\r\n                    document.getElementById('pth-bc-gen-out').textContent = hash;\r\n                    document.getElementById('pth-bc-gen-time').textContent =\r\n                        'Took ' + ms + ' ms at cost ' + cost + ' on this device \\u2014 an attacker with faster hardware still pays a comparable cost per guess.';\r\n                    document.getElementById('pth-bc-gen-box').style.display = 'block';\r\n                    self.showToast('Hash generated', 'success');\r\n                }, 30);\r\n            },\r\n\r\n            runBulk: function () {\r\n                var self = this;\r\n                var raw = document.getElementById('pth-bc-bulk-in').value;\r\n                var lines = raw.split('\\n'), list = [], i;\r\n                for (i = 0; i < lines.length; i++) {\r\n                    if (lines[i].replace(\/^\\s+|\\s+$\/g, '') !== '') { list.push(lines[i]); }\r\n                }\r\n                if (!list.length) { this.showToast('Add at least one password', 'info'); return; }\r\n                if (list.length > 50) { list = list.slice(0, 50); this.showToast('Limited to the first 50', 'info'); }\r\n\r\n                var cost = parseInt(document.getElementById('pth-bc-gen-cost').value, 10);\r\n                if (cost > 12) { cost = 12; }\r\n                var out = document.getElementById('pth-bc-bulk-out');\r\n                var prog = document.getElementById('pth-bc-bulk-prog');\r\n                var fill = document.getElementById('pth-bc-bulk-fill');\r\n                prog.style.display = 'block';\r\n                out.style.display = 'block';\r\n                out.textContent = '';\r\n                self.bulkRows = [];\r\n\r\n                var idx = 0;\r\n                function step() {\r\n                    if (idx >= list.length) {\r\n                        prog.style.display = 'none';\r\n                        self.showToast('Hashed ' + list.length + ' passwords', 'success');\r\n                        return;\r\n                    }\r\n                    var pw = list[idx];\r\n                    var h;\r\n                    try { h = PTHBcrypt.hash(pw, cost, 'b'); }\r\n                    catch (e) { h = 'ERROR: ' + e.message; }\r\n                    self.bulkRows.push([pw, h]);\r\n                    out.textContent += pw + '  \\u2192  ' + h + '\\n';\r\n                    idx++;\r\n                    fill.style.width = Math.round(100 * idx \/ list.length) + '%';\r\n                    setTimeout(step, 10);\r\n                }\r\n                setTimeout(step, 20);\r\n            },\r\n\r\n            exportBulkCsv: function () {\r\n                if (!this.bulkRows.length) { this.showToast('Hash some passwords first', 'info'); return; }\r\n                var csv = 'plaintext,bcrypt_hash\\n', i;\r\n                for (i = 0; i < this.bulkRows.length; i++) {\r\n                    csv += '\"' + this.bulkRows[i][0].replace(new RegExp(QT, 'g'), '\"\"') + '\",\"' + this.bulkRows[i][1] + '\"\\n';\r\n                }\r\n                this.download(csv, 'bcrypt-hashes.csv', 'text\/csv');\r\n            },\r\n\r\n            \/* ---------- TAB 2 ---------- *\/\r\n            runVerify: function () {\r\n                var self = this;\r\n                var pw = document.getElementById('pth-bc-ver-text').value;\r\n                var h = document.getElementById('pth-bc-ver-hash').value.replace(\/^\\s+|\\s+$\/g, '');\r\n                var box = document.getElementById('pth-bc-ver-out');\r\n                if (!h) { box.innerHTML = '' + LT + 'div class=\"pth-verdict neutral\">Paste a hash to verify against.' + LT + '\/div>'; return; }\r\n                if (h.length !== 60) {\r\n                    box.innerHTML = '' + LT + 'div class=\"pth-verdict bad\">\\u274C Not a valid bcrypt hash \\u2014 expected 60 characters, got ' + h.length + '.' + LT + '\/div>';\r\n                    return;\r\n                }\r\n                var btn = document.getElementById('pth-bc-ver-run');\r\n                btn.disabled = true; btn.textContent = '\\u23F3 Verifying...';\r\n                setTimeout(function () {\r\n                    var t0 = (new Date()).getTime(), match = false, err = null;\r\n                    try { match = PTHBcrypt.compare(pw, h); }\r\n                    catch (e) { err = e.message; }\r\n                    var ms = (new Date()).getTime() - t0;\r\n                    btn.disabled = false; btn.textContent = '\\uD83D\\uDEE1\\uFE0F Verify Match';\r\n                    if (err) { box.innerHTML = '' + LT + 'div class=\"pth-verdict bad\">\\u274C ' + self.escapeHtml(err) + '' + LT + '\/div>'; return; }\r\n                    var cost = parseInt(h.substring(4, 6), 10);\r\n                    if (match) {\r\n                        box.innerHTML = '' + LT + 'div class=\"pth-verdict ok\">\\u2705 Match \\u2014 this password produces this hash.' + LT + '\/div>'\r\n                            + '' + LT + 'div class=\"pth-finding pth-f-info\">Verified in ' + ms + ' ms at cost ' + cost\r\n                            + '. A server checking logins pays this same cost on every attempt, which is exactly what throttles a brute-force attack.' + LT + '\/div>';\r\n                    } else {\r\n                        box.innerHTML = '' + LT + 'div class=\"pth-verdict bad\">\\u274C No match \\u2014 this password does not produce this hash.' + LT + '\/div>'\r\n                            + '' + LT + 'div class=\"pth-finding pth-f-warn\">Took ' + ms + ' ms. A mismatch costs the same time as a match, which is deliberate: timing alone reveals nothing to an attacker.' + LT + '\/div>';\r\n                    }\r\n                    self.showToast(match ? 'Password matches' : 'No match', match ? 'success' : 'error');\r\n                }, 30);\r\n            },\r\n\r\n            \/* ---------- TAB 3 ---------- *\/\r\n            prefixInfo: function (p) {\r\n                if (p === '2a') { return 'The long-standing format, understood by essentially every bcrypt library. Some very old implementations had a bug handling passwords above 255 bytes.'; }\r\n                if (p === '2b') { return 'The current standard, produced by OpenBSD and most modern libraries. Prefer this for new systems.'; }\r\n                if (p === '2y') { return 'Introduced by PHP\\u2019s crypt implementation. Functionally equivalent to $2b$ in practice; PHP\\u2019s password_hash still emits it.'; }\r\n                if (p === '2x') { return 'A marker for hashes produced by a known-buggy old implementation. Treat these as legacy and re-hash on next login.'; }\r\n                return 'Unrecognised prefix.';\r\n            },\r\n\r\n            runInspect: function () {\r\n                var h = document.getElementById('pth-bc-insp-in').value.replace(\/^\\s+|\\s+$\/g, '');\r\n                var box = document.getElementById('pth-bc-insp-out');\r\n                if (!h) { box.innerHTML = ''; return; }\r\n\r\n                var m = h.match(\/^\\$(2[abxy])\\$(\\d{2})\\$([A-Za-z0-9.\/]{22})([A-Za-z0-9.\/]{31})$\/);\r\n                if (!m) {\r\n                    var why = 'It should look like $2b$12$ followed by 53 characters from A-Z, a-z, 0-9, dot and slash.';\r\n                    if (h.length !== 60) { why = 'A complete bcrypt hash is exactly 60 characters; this one is ' + h.length + '.'; }\r\n                    box.innerHTML = '' + LT + 'div class=\"pth-finding pth-f-warn\">' + LT + 'strong>Not a complete bcrypt hash yet.' + LT + '\/strong> ' + why + '' + LT + '\/div>';\r\n                    return;\r\n                }\r\n\r\n                var prefix = m[1], cost = parseInt(m[2], 10), salt = m[3], digest = m[4];\r\n                var rounds = Math.pow(2, cost);\r\n                var html = '' + LT + 'div class=\"pth-cards\">';\r\n                html += '' + LT + 'div class=\"pth-card\">' + LT + 'div class=\"pth-card-lbl\">Prefix' + LT + '\/div>' + LT + 'div class=\"pth-card-val amber\">$' + prefix + '$' + LT + '\/div>' + LT + '\/div>';\r\n                html += '' + LT + 'div class=\"pth-card\">' + LT + 'div class=\"pth-card-lbl\">Cost factor' + LT + '\/div>' + LT + 'div class=\"pth-card-val blue\">' + cost + '' + LT + '\/div>' + LT + '\/div>';\r\n                html += '' + LT + 'div class=\"pth-card\">' + LT + 'div class=\"pth-card-lbl\">Key rounds' + LT + '\/div>' + LT + 'div class=\"pth-card-val\">2^' + cost + ' = ' + rounds.toLocaleString() + '' + LT + '\/div>' + LT + '\/div>';\r\n                html += '' + LT + 'div class=\"pth-card wide\">' + LT + 'div class=\"pth-card-lbl\">Salt (22 chars)' + LT + '\/div>' + LT + 'div class=\"pth-card-val green\">' + this.escapeHtml(salt) + '' + LT + '\/div>' + LT + '\/div>';\r\n                html += '' + LT + 'div class=\"pth-card wide\">' + LT + 'div class=\"pth-card-lbl\">Digest (31 chars)' + LT + '\/div>' + LT + 'div class=\"pth-card-val\">' + this.escapeHtml(digest) + '' + LT + '\/div>' + LT + '\/div>';\r\n                html += '' + LT + '\/div>';\r\n\r\n                html += '' + LT + 'div class=\"pth-finding pth-f-info\">' + LT + 'strong>Prefix $' + prefix + '$.' + LT + '\/strong> ' + this.prefixInfo(prefix) + '' + LT + '\/div>';\r\n\r\n                if (cost <= 8) {\r\n                    html += '' + LT + 'div class=\"pth-finding pth-f-crit\">' + LT + 'strong>Cost ' + cost + ' is too low for stored credentials.' + LT + '\/strong> Each step down halves the attacker\\u2019s effort. Hashes at this cost should be upgraded the next time each user logs in successfully.' + LT + '\/div>';\r\n                } else if (cost <= 11) {\r\n                    html += '' + LT + 'div class=\"pth-finding pth-f-warn\">' + LT + 'strong>Cost ' + cost + ' is serviceable but modest.' + LT + '\/strong> Benchmark your own hardware and raise it until a single hash takes roughly a quarter of a second.' + LT + '\/div>';\r\n                } else if (cost <= 14) {\r\n                    html += '' + LT + 'div class=\"pth-finding pth-f-ok\">' + LT + 'strong>Cost ' + cost + ' is a sound choice' + LT + '\/strong> for most systems today, assuming your login endpoint can absorb the delay.' + LT + '\/div>';\r\n                } else {\r\n                    html += '' + LT + 'div class=\"pth-finding pth-f-warn\">' + LT + 'strong>Cost ' + cost + ' is unusually high.' + LT + '\/strong> Confirm your login path can carry the latency, and that it cannot be abused to exhaust your own CPU.' + LT + '\/div>';\r\n                }\r\n\r\n                html += '' + LT + 'div class=\"pth-finding pth-f-info\">' + LT + 'strong>What is not here:' + LT + '\/strong> the password. A bcrypt string contains only the version, the cost, the random salt and the digest. There is no key and no way to reverse it \\u2014 the only route back is to guess and re-hash.' + LT + '\/div>';\r\n                box.innerHTML = html;\r\n            },\r\n\r\n            \/* ---------- TAB 4 ---------- *\/\r\n            scriptBreakdown: function (s) {\r\n                var counts = { ascii: 0, twoByte: 0, threeByte: 0, fourByte: 0 };\r\n                var i, c, cp;\r\n                for (i = 0; i < s.length; i++) {\r\n                    c = s.charCodeAt(i);\r\n                    if (c >= 0xD800 && c <= 0xDBFF && i + 1 < s.length) { counts.fourByte++; i++; continue; }\r\n                    if (c < 128) { counts.ascii++; }\r\n                    else if (c < 2048) { counts.twoByte++; }\r\n                    else { counts.threeByte++; }\r\n                }\r\n                return counts;\r\n            },\r\n\r\n            updateLimit: function () {\r\n                var v = document.getElementById('pth-bc-lim-in').value;\r\n                var bytes = PTHBcrypt.byteLength(v);\r\n                var chars = v.length;\r\n                var lost = bytes > 72 ? bytes - 72 : 0;\r\n\r\n                document.getElementById('pth-bc-lim-chars').textContent = chars;\r\n                document.getElementById('pth-bc-lim-bytes').textContent = bytes;\r\n                var lostEl = document.getElementById('pth-bc-lim-lost');\r\n                lostEl.textContent = lost;\r\n                lostEl.className = 'pth-card-val' + (lost ? '' : ' green');\r\n\r\n                var usedPct = Math.min(100, Math.round(100 * Math.min(bytes, 72) \/ 72));\r\n                var cutPct = bytes > 72 ? Math.min(100 - usedPct, Math.round(100 * lost \/ 72)) : 0;\r\n                var fill = document.getElementById('pth-bc-lim-fill');\r\n                fill.style.width = usedPct + '%';\r\n                fill.className = 'pth-bytefill' + (bytes > 72 ? ' over' : '');\r\n                document.getElementById('pth-bc-lim-cut').style.width = cutPct + '%';\r\n                document.getElementById('pth-bc-lim-left').textContent = bytes + ' bytes used' + (lost ? ' (' + lost + ' ignored)' : '');\r\n\r\n                var vbox = document.getElementById('pth-bc-lim-verdict');\r\n                if (!v) { vbox.innerHTML = ''; }\r\n                else if (bytes > 72) {\r\n                    var kept = this.truncateToBytes(v, 72);\r\n                    vbox.innerHTML = '' + LT + 'div class=\"pth-finding pth-f-crit\">' + LT + 'strong>Silently truncated.' + LT + '\/strong> Bcrypt will hash only the first 72 bytes and discard the rest without warning. '\r\n                        + 'Anything you type after the highlighted point below has no effect on the resulting hash.' + LT + '\/div>'\r\n                        + '' + LT + 'div class=\"pth-finding pth-f-warn\" style=\"font-family:monospace;word-break:break-all;\">' + LT + 'strong>Hashed:' + LT + '\/strong> ' + this.escapeHtml(kept)\r\n                        + '' + LT + 'br>' + LT + 'strong>Ignored:' + LT + '\/strong> ' + this.escapeHtml(v.substring(kept.length)) + '' + LT + '\/div>';\r\n                } else if (bytes > 60) {\r\n                    vbox.innerHTML = '' + LT + 'div class=\"pth-finding pth-f-warn\">' + LT + 'strong>Close to the ceiling.' + LT + '\/strong> ' + (72 - bytes) + ' bytes remain before bcrypt starts discarding input.' + LT + '\/div>';\r\n                } else {\r\n                    vbox.innerHTML = '' + LT + 'div class=\"pth-finding pth-f-ok\">' + LT + 'strong>Comfortably within the limit.' + LT + '\/strong> All ' + bytes + ' bytes contribute to the hash.' + LT + '\/div>';\r\n                }\r\n\r\n                var sc = this.scriptBreakdown(v);\r\n                var sbox = document.getElementById('pth-bc-lim-script');\r\n                if (!v || (sc.twoByte + sc.threeByte + sc.fourByte) === 0) { sbox.innerHTML = ''; return; }\r\n                var rows = '';\r\n                if (sc.ascii) { rows += '' + LT + 'tr>' + LT + 'td>Latin letters, digits, symbols' + LT + '\/td>' + LT + 'td class=\"mono\">1 byte' + LT + '\/td>' + LT + 'td class=\"mono\">' + sc.ascii + '' + LT + '\/td>' + LT + 'td class=\"mono\">' + sc.ascii + '' + LT + '\/td>' + LT + '\/tr>'; }\r\n                if (sc.twoByte) { rows += '' + LT + 'tr>' + LT + 'td>Accented Latin, Greek, Cyrillic, Arabic' + LT + '\/td>' + LT + 'td class=\"mono\">2 bytes' + LT + '\/td>' + LT + 'td class=\"mono\">' + sc.twoByte + '' + LT + '\/td>' + LT + 'td class=\"mono\">' + (sc.twoByte * 2) + '' + LT + '\/td>' + LT + '\/tr>'; }\r\n                if (sc.threeByte) { rows += '' + LT + 'tr>' + LT + 'td>Sinhala, Tamil, Devanagari, CJK' + LT + '\/td>' + LT + 'td class=\"mono\">3 bytes' + LT + '\/td>' + LT + 'td class=\"mono\">' + sc.threeByte + '' + LT + '\/td>' + LT + 'td class=\"mono\">' + (sc.threeByte * 3) + '' + LT + '\/td>' + LT + '\/tr>'; }\r\n                if (sc.fourByte) { rows += '' + LT + 'tr>' + LT + 'td>Emoji and rarer symbols' + LT + '\/td>' + LT + 'td class=\"mono\">4 bytes' + LT + '\/td>' + LT + 'td class=\"mono\">' + sc.fourByte + '' + LT + '\/td>' + LT + 'td class=\"mono\">' + (sc.fourByte * 4) + '' + LT + '\/td>' + LT + '\/tr>'; }\r\n                sbox.innerHTML = '' + LT + 'div class=\"pth-table-wrap\">' + LT + 'table class=\"pth-table\">' + LT + 'thead>' + LT + 'tr>' + LT + 'th>Script' + LT + '\/th>' + LT + 'th>Cost each' + LT + '\/th>' + LT + 'th>Count' + LT + '\/th>' + LT + 'th>Bytes' + LT + '\/th>' + LT + '\/tr>' + LT + '\/thead>' + LT + 'tbody>'\r\n                    + rows + '' + LT + '\/tbody>' + LT + '\/table>' + LT + '\/div>'\r\n                    + '' + LT + 'div class=\"pth-finding pth-f-info\">' + LT + 'strong>Why this matters outside English.' + LT + '\/strong> A Sinhala, Tamil or Chinese character costs three bytes, so roughly 24 of them fill the entire 72-byte budget. '\r\n                    + 'A passphrase that looks short can already be over the line, and the truncation is silent.' + LT + '\/div>';\r\n            },\r\n\r\n            truncateToBytes: function (s, maxBytes) {\r\n                var out = '', i;\r\n                for (i = 1; i <= s.length; i++) {\r\n                    if (PTHBcrypt.byteLength(s.substring(0, i)) > maxBytes) { break; }\r\n                    out = s.substring(0, i);\r\n                }\r\n                return out;\r\n            },\r\n\r\n            runCollisionDemo: function () {\r\n                var self = this;\r\n                var box = document.getElementById('pth-bc-lim-demo-out');\r\n                var btn = document.getElementById('pth-bc-lim-demo');\r\n                btn.disabled = true; btn.textContent = '\\u23F3 Hashing...';\r\n                setTimeout(function () {\r\n                    var base = '';\r\n                    while (base.length < 72) { base += 'LongPassphrasePrefix-'; }\r\n                    base = base.substring(0, 72);\r\n                    var p1 = base + 'ENDING-ALPHA-9f2c';\r\n                    var p2 = base + 'COMPLETELY-DIFFERENT-TAIL-77x';\r\n                    var h = PTHBcrypt.hash(p1, 8, 'b');\r\n                    var match = PTHBcrypt.compare(p2, h);\r\n                    btn.disabled = false; btn.textContent = '\\u26A0\\uFE0F Run collision demo';\r\n\r\n                    var html = '' + LT + 'div class=\"pth-finding pth-f-warn\" style=\"font-family:monospace;word-break:break-all;\">'\r\n                        + '' + LT + 'strong>Password A:' + LT + '\/strong> ' + self.escapeHtml(p1) + '' + LT + 'br>' + LT + 'br>'\r\n                        + '' + LT + 'strong>Password B:' + LT + '\/strong> ' + self.escapeHtml(p2) + '' + LT + '\/div>';\r\n                    html += '' + LT + 'div class=\"pth-finding pth-f-info\" style=\"font-family:monospace;word-break:break-all;\">' + LT + 'strong>Hash of A:' + LT + '\/strong> ' + h + '' + LT + '\/div>';\r\n                    if (match) {\r\n                        html += '' + LT + 'div class=\"pth-verdict bad\">\\u26A0\\uFE0F Password B also verifies against the hash of A' + LT + '\/div>'\r\n                            + '' + LT + 'div class=\"pth-finding pth-f-crit\">' + LT + 'strong>That is the whole problem in one line.' + LT + '\/strong> The two passwords share their first 72 bytes and differ completely after that, '\r\n                            + 'yet bcrypt sees them as identical. If your sign-up form allows long passwords, two users could unknowingly share a credential, and a password manager\\u2019s long random string may be far weaker than it looks. '\r\n                            + 'The fix is to cap password length at sign-up, or to pre-hash with SHA-256 before bcrypt so the input is always a fixed short length.' + LT + '\/div>';\r\n                    } else {\r\n                        html += '' + LT + 'div class=\"pth-verdict ok\">No collision on this run' + LT + '\/div>';\r\n                    }\r\n                    box.innerHTML = html;\r\n                }, 30);\r\n            },\r\n\r\n            \/* ---------- TAB 5 ---------- *\/\r\n            runBenchmark: function () {\r\n                var self = this;\r\n                var max = parseInt(document.getElementById('pth-bc-bench-max').value, 10);\r\n                var costs = [], c;\r\n                for (c = 8; c <= max; c++) { costs.push(c); }\r\n                var out = document.getElementById('pth-bc-bench-out');\r\n                var prog = document.getElementById('pth-bc-bench-prog');\r\n                var fill = document.getElementById('pth-bc-bench-fill');\r\n                var btn = document.getElementById('pth-bc-bench-run');\r\n                btn.disabled = true; btn.textContent = '\\u23F3 Measuring...';\r\n                prog.style.display = 'block';\r\n                out.innerHTML = '';\r\n                self.benchRows = [];\r\n\r\n                var idx = 0;\r\n                function step() {\r\n                    if (idx >= costs.length) {\r\n                        prog.style.display = 'none';\r\n                        btn.disabled = false; btn.textContent = '\\u23F1\\uFE0F Run Benchmark';\r\n                        self.renderBenchmark();\r\n                        return;\r\n                    }\r\n                    var cost = costs[idx];\r\n                    var t0 = (new Date()).getTime();\r\n                    PTHBcrypt.hash('benchmark-sample', cost, 'b');\r\n                    var ms = (new Date()).getTime() - t0;\r\n                    self.benchRows.push({ cost: cost, ms: ms });\r\n                    idx++;\r\n                    fill.style.width = Math.round(100 * idx \/ costs.length) + '%';\r\n                    setTimeout(step, 15);\r\n                }\r\n                setTimeout(step, 25);\r\n            },\r\n\r\n            renderBenchmark: function () {\r\n                var rows = this.benchRows, i, best = null;\r\n                for (i = 0; i < rows.length; i++) {\r\n                    if (rows[i].ms >= 200 && rows[i].ms <= 500) { if (!best) { best = rows[i]; } }\r\n                }\r\n                if (!best) {\r\n                    for (i = rows.length - 1; i >= 0; i--) {\r\n                        if (rows[i].ms < 250) { best = rows[i]; break; }\r\n                    }\r\n                }\r\n                var html = '' + LT + 'div class=\"pth-table-wrap\">' + LT + 'table class=\"pth-table\">' + LT + 'thead>' + LT + 'tr>' + LT + 'th>Cost' + LT + '\/th>' + LT + 'th>Time on this device' + LT + '\/th>' + LT + 'th>Logins per second (1 core)' + LT + '\/th>' + LT + 'th>Verdict' + LT + '\/th>' + LT + '\/tr>' + LT + '\/thead>' + LT + 'tbody>';\r\n                for (i = 0; i < rows.length; i++) {\r\n                    var ms = rows[i].ms;\r\n                    var perSec = ms > 0 ? (1000 \/ ms).toFixed(1) : '\\u2014';\r\n                    var tag, cls = '';\r\n                    if (ms < 50) { tag = '' + LT + 'span class=\"pth-tag tag-bad\">too fast' + LT + '\/span>'; }\r\n                    else if (ms < 200) { tag = '' + LT + 'span class=\"pth-tag tag-warn\">on the low side' + LT + '\/span>'; }\r\n                    else if (ms <= 500) { tag = '' + LT + 'span class=\"pth-tag tag-ok\">good target' + LT + '\/span>'; }\r\n                    else if (ms <= 1000) { tag = '' + LT + 'span class=\"pth-tag tag-warn\">slow logins' + LT + '\/span>'; }\r\n                    else { tag = '' + LT + 'span class=\"pth-tag tag-bad\">likely too slow' + LT + '\/span>'; }\r\n                    if (best && rows[i].cost === best.cost) { cls = ' class=\"row-best\"'; }\r\n                    html += '' + LT + 'tr' + cls + '>' + LT + 'td class=\"mono\">' + rows[i].cost + '' + LT + '\/td>' + LT + 'td class=\"mono\">' + ms + ' ms' + LT + '\/td>' + LT + 'td class=\"mono\">' + perSec + '' + LT + '\/td>' + LT + 'td>' + tag + '' + LT + '\/td>' + LT + '\/tr>';\r\n                }\r\n                html += '' + LT + '\/tbody>' + LT + '\/table>' + LT + '\/div>';\r\n\r\n                if (best) {\r\n                    html += '' + LT + 'div class=\"pth-finding pth-f-ok\">' + LT + 'strong>Suggested cost for this device: ' + best.cost + '.' + LT + '\/strong> '\r\n                        + 'It lands at ' + best.ms + ' ms per hash, close to the widely used target of roughly a quarter of a second. '\r\n                        + 'That is slow enough to punish an attacker and fast enough that a person signing in will not notice.' + LT + '\/div>';\r\n                }\r\n                html += '' + LT + 'div class=\"pth-finding pth-f-warn\">' + LT + 'strong>Read these numbers carefully.' + LT + '\/strong> This is JavaScript in a browser tab, so a compiled server library will be meaningfully faster on the same silicon. '\r\n                    + 'Treat the shape of the curve as the lesson &mdash; each step doubles the time &mdash; and always benchmark on the machine that will actually serve your logins before fixing a cost.' + LT + '\/div>';\r\n                html += '' + LT + 'div class=\"pth-finding pth-f-info\">' + LT + 'strong>Do not forget the other side.' + LT + '\/strong> A high cost also makes your own login endpoint expensive, which is a denial-of-service surface. '\r\n                    + 'Pair a sensible cost with rate limiting rather than pushing the number as high as it will go.' + LT + '\/div>';\r\n                document.getElementById('pth-bc-bench-out').innerHTML = html;\r\n            },\r\n\r\n            \/* ---------- util ---------- *\/\r\n            download: function (content, name, mime) {\r\n                var blob = new Blob([content], { type: mime });\r\n                var url = URL.createObjectURL(blob);\r\n                var a = document.createElement('a');\r\n                a.href = url; a.download = name;\r\n                document.body.appendChild(a); a.click(); document.body.removeChild(a);\r\n                setTimeout(function () { URL.revokeObjectURL(url); }, 1000);\r\n                this.showToast('Download started', 'success');\r\n            },\r\n\r\n            copyText: function (text) {\r\n                var self = this;\r\n                if (!text) { self.showToast('Nothing to copy yet', 'info'); return; }\r\n                if (navigator.clipboard && navigator.clipboard.writeText) {\r\n                    navigator.clipboard.writeText(text).then(function () { self.showToast('Copied to clipboard', 'success'); })\r\n                        .catch(function () { self.showToast('Copy blocked by browser', 'error'); });\r\n                } else { self.showToast('Clipboard not supported', 'error'); }\r\n            },\r\n\r\n            showToast: function (msg, type) {\r\n                var wrap = document.getElementById('pth-bc-toast-wrap');\r\n                if (!wrap) { return; }\r\n                var t = document.createElement('div');\r\n                t.className = 'pth-toast ' + (type || 'info');\r\n                t.setAttribute('role', 'status');\r\n                t.textContent = msg;\r\n                wrap.appendChild(t);\r\n                setTimeout(function () { if (t.parentNode) { t.parentNode.removeChild(t); } }, 3000);\r\n            }\r\n        };\r\n\r\n        \/* ---------- 4-Layer Bootstrap ---------- *\/\r\n        function pthBcInit() {\r\n            if (!window.pthBcryptApp.initialized && document.getElementById('pth-bcrypt-wrapper')) {\r\n                window.pthBcryptApp.initialized = true;\r\n                window.pthBcryptApp.init();\r\n            }\r\n        }\r\n        pthBcInit();\r\n        if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', pthBcInit); }\r\n        window.addEventListener('load', function () { setTimeout(pthBcInit, 50); });\r\n        if (!window.pthBcryptApp.initialized && typeof MutationObserver !== 'undefined') {\r\n            var pthBcObs = new MutationObserver(function () {\r\n                if (document.getElementById('pth-bcrypt-wrapper')) { pthBcObs.disconnect(); pthBcInit(); }\r\n            });\r\n            pthBcObs.observe(document.body || document.documentElement, { childList: true, subtree: true });\r\n            setTimeout(function () { pthBcObs.disconnect(); }, 10000);\r\n        }\r\n    })();\r\n    <\/script>\r\n<\/div>\n\n\n\n<style>\n.pth-feature-wrap { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-bottom: 30px; }\n.pth-feat-box { border: 1px solid #e2e8f0; background: #ffffff; padding: 24px; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.02); transition: all 0.3s ease; }\n.pth-feat-box:hover { border-color: #bfdbfe; transform: translateY(-3px); box-shadow: 0 10px 15px -3px rgba(0,0,0,0.05); }\n.pth-feat-title { font-size: 1.1rem; font-weight: 800; color: #0f172a; margin-bottom: 10px; display: flex; align-items: center; gap: 10px; }\n.pth-feat-text { font-size: 0.9rem; color: #475569; line-height: 1.6; margin: 0; }\n.pth-steps-wrap { border: 1px solid #e2e8f0; background: #ffffff; padding: 40px 30px; border-radius: 16px; text-align: center; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.02); margin-bottom: 40px; }\n.pth-steps-title { font-size: 1.2rem; font-weight: 800; color: #1e293b; text-transform: uppercase; margin-bottom: 35px; letter-spacing: 1px; }\n.pth-steps-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 30px; }\n.pth-step-item { display: flex; flex-direction: column; align-items: center; }\n.pth-step-num { width: 45px; height: 45px; background: #3b82f6; color: #ffffff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 1.2rem; margin-bottom: 15px; box-shadow: 0 4px 10px rgba(59,130,246,0.3); }\n.pth-step-name { font-weight: 800; color: #0f172a; margin-bottom: 8px; font-size: 1.05rem; }\n.pth-step-desc { font-size: 0.9rem; color: #64748b; line-height: 1.5; margin: 0; }\n<\/style>\n<div class=\"pth-feature-wrap\">\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udfe2 Cryptographic Salting<\/div>\n        <p class=\"pth-feat-text\">The Bcrypt Hash Generator automatically computes a randomized 22-character salt matrix internally, attaching it directly to the payload before hashing.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udd35 Adaptive Cost Factors<\/div>\n        <p class=\"pth-feat-text\">Engineers can control the mathematical iterations via a slider interface, intentionally slowing down the CPU processing to defend against brute-force attacks.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udfe3 Client-Side Verification<\/div>\n        <p class=\"pth-feat-text\">Compare unencrypted string credentials against existing cryptographic signatures directly within the browser memory using the isolated verification protocol.<\/p>\n    <\/div>\n<\/div>\n<div class=\"pth-steps-wrap\">\n    <div class=\"pth-steps-title\">How to Calculate Hashes with the Bcrypt Hash Generator<\/div>\n    <div class=\"pth-steps-grid\">\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">1<\/div>\n            <div class=\"pth-step-name\">Inject Plain Text<\/div>\n            <p class=\"pth-step-desc\">Enter your target string or auto-generate a secure random sequence natively via the internal module.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">2<\/div>\n            <div class=\"pth-step-name\">Determine Iterations<\/div>\n            <p class=\"pth-step-desc\">Specify the algorithmic cost factor, scaling from standard 10-level iterations to maximum hardware redundancy.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">3<\/div>\n            <div class=\"pth-step-name\">Trigger Compilation<\/div>\n            <p class=\"pth-step-desc\">Instruct the local JavaScript engine to calculate the 60-character cryptographic sequence via your local CPU.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">4<\/div>\n            <div class=\"pth-step-name\">Copy the Signature<\/div>\n            <p class=\"pth-step-desc\">Extract the compiled checksum directly from the local environment for integration into backend database schemas.<\/p>\n        <\/div>\n    <\/div>\n<\/div>\n\n\n<div id=\"start-seo-article\"><\/div>\n\n\n<div id=\"start-seo-article\"><\/div>\n\n\n\n<h2 id=\"\ud83d\udfe5-cryptographic-mathematics-of-a-bcrypt-hash-generator\" class=\"wp-block-heading\">\ud83d\udfe5 Cryptographic Mathematics of a Bcrypt Hash Generator<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In backend database engineering, storing raw credential strings directly exposes systems to catastrophic breaches. A Bcrypt Hash Generator acts as an irreversible mathematical compiler, applying the Blowfish block cipher algorithm against plaintext inputs. By evaluating a string through a Bcrypt Hash Generator, developers compute a secure 60-character output that combines algorithmic versioning, workload cost factors, randomized salting, and the final encrypted checksum sequence into a single identifiable string.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe7-adaptive-hashing-and-brute-force-defenses\" class=\"wp-block-heading\">\ud83d\udfe7 Adaptive Hashing and Brute-Force Defenses<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When operating this Bcrypt Hash Generator, the system calculates cryptographic defense mechanisms computationally. Unlike older MD5 or SHA1 algorithms that resolve instantly, this engine implements an adaptive processing constraint. The Bcrypt Hash Generator allows administrators to configure the computational &#8216;cost&#8217; parametrically.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ud83d\udfe2 A baseline cost factor of 10 triggers exactly 1,024 algorithmic iterations.<\/li>\n\n\n\n<li>\ud83d\udd35 Pushing the cost slider higher forces the local CPU to perform exponentially more calculations, deliberately causing slower completion times.<\/li>\n\n\n\n<li>\ud83d\udfe3 This intentional latency nullifies the effectiveness of hardware-accelerated dictionary attacks and GPU hash-cracking farms.<\/li>\n\n\n\n<li>\ud83d\udfe4 The engine automatically randomizes a unique 22-character salt matrix per execution, ensuring identical inputs generate entirely distinct outputs.<\/li>\n<\/ul>\n\n\n\n<h2 id=\"\ud83d\udfe8-memory-security-and-offline-compilation\" class=\"wp-block-heading\">\ud83d\udfe8 Memory Security and Offline Compilation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Submitting sensitive credentials to external computing grids is a foundational security flaw. Therefore, this Bcrypt Hash Generator executes 100% offline. Rather than posting your plaintext variables to a remote server, the application computes the mathematics entirely within the active browser environment. Because the Bcrypt Hash Generator isolates operations inside the local memory buffer, unauthorized external APIs can never log or cache the unencrypted data.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe9-verification-standards-and-tool-integration\" class=\"wp-block-heading\">\ud83d\udfe9 Verification Standards and Tool Integration<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Implementing adaptive hashing requires strict understanding of the underlying cipher protocols. For an academic analysis of the Blowfish architecture powering these computations, developers should review the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bcrypt\" target=\"_blank\" rel=\"noreferrer noopener\">Wikipedia documentation on Bcrypt<\/a>. Should your security pipeline require additional offline validations, you can explore the extensive <a href=\"https:\/\/schoolict.net\/tools\/free-web-tools-directory-prime-tool-hub\/\">SchoolICT Tool Hub directory<\/a> to locate compatible credential analyzers alongside this Bcrypt Hash Generator.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Free Bcrypt Hash Generator &#038; Verifier &#8211; Offline Tool Generate and verify Bcrypt hashes securely with our 100% offline Bcrypt Hash Generator. Adjust cost factors and test password matches instantly. \ud83d\udfe2 Cryptographic Salting The Bcrypt Hash Generator automatically computes a randomized 22-character salt matrix internally, attaching it directly to the payload before hashing. \ud83d\udd35 Adaptive &#8230; <a title=\"Free Bcrypt Hash Generator &amp; Verifier &#8211; Offline Tool\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/bcrypt-hash-generator-verifier\/\" aria-label=\"Read more about Free Bcrypt Hash Generator &amp; Verifier &#8211; Offline Tool\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":3456,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-2183","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2183","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/comments?post=2183"}],"version-history":[{"count":2,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2183\/revisions"}],"predecessor-version":[{"id":6943,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2183\/revisions\/6943"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/3456"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=2183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}