{"id":841,"date":"2026-03-18T10:10:43","date_gmt":"2026-03-18T10:10:43","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=841"},"modified":"2026-08-08T09:47:11","modified_gmt":"2026-08-08T09:47:11","slug":"uuid-guid-generator-validator","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/uuid-guid-generator-validator\/","title":{"rendered":"GUID Generator &amp; Validator"},"content":{"rendered":"\n<div class=\"pth-hero-section\">\n    <div class=\"pth-hero-content\">\n        <h2> Fast and Developer ready GUID Generator &amp; Validator<\/h2>\n        <p>Use our offline GUID Generator &amp; Validator to create cryptographically secure Version 4 UUIDs. Validate up to 10,000 identifiers locally with zero server uploads.<\/p>\n\n        <div id=\"pth-toc-placeholder\"><\/div>\n    <\/div>\n\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\/03\/UUID-GUID-Generator-1024x572.jpeg\" alt=\"GUID Generator &amp; Validator\">\n    <\/div>\n<\/div>\n\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\udd34-what-changed-and-why\">\ud83d\udd34 What Changed and Why<\/a><ul><li><a href=\"#generate-pick-the-version-that-fits-the-job\">Generate \u2014 pick the version that fits the job<\/a><\/li><li><a href=\"#inspector-read-what-is-inside-an-identifier\">Inspector \u2014 read what is inside an identifier<\/a><\/li><li><a href=\"#other-formats-five-schemes-that-are-not-uui-ds\">Other Formats \u2014 five schemes that are not UUIDs<\/a><\/li><li><a href=\"#validate-convert-bulk-work\">Validate &amp; Convert \u2014 bulk work<\/a><\/li><\/ul><\/li><li><a href=\"#\ud83d\udfe1-where-people-get-this-wrong\">\ud83d\udfe1 Where People Get This Wrong<\/a><ul><li><a href=\"#a-uuid-is-not-a-secret\">A UUID is not a secret<\/a><\/li><li><a href=\"#time-based-versions-reveal-their-creation-time\">Time-based versions reveal their creation time<\/a><\/li><li><a href=\"#storing-uui-ds-as-text\">Storing UUIDs as text<\/a><\/li><li><a href=\"#what-this-page-does-not-do\">What this page does not do<\/a><\/li><li><a href=\"#honest-limits\">Honest limits<\/a><\/li><\/ul><\/li><li><a href=\"#\ud83d\udfe2-the-reasoning-behind-it\">\ud83d\udfe2 The Reasoning Behind It<\/a><\/li><\/ul><\/nav><\/div>\n\n\n<style>\r\n\/* ==========================================================================\r\n   PRIME TOOL HUB - ID STUDIO PRO v3.0 (UUID \/ GUID + modern ID formats)\r\n   All-in-One: Generate \/ Inspect \/ Other Formats \/ Validate & Convert\r\n   ========================================================================== *\/\r\n#pth-id-studio-wrapper { font-family: 'Inter', system-ui, -apple-system, sans-serif; max-width: 1400px; margin: 0 auto; background: #f8fafc; padding: 20px; border-radius: 16px; color: #0f172a; line-height: 1.6; opacity: 1; }\r\n#pth-id-studio-wrapper * { box-sizing: border-box; min-width: 0; }\r\n\r\n#pth-id-studio-wrapper .pth-head { display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 12px; margin-bottom: 18px; }\r\n#pth-id-studio-wrapper .pth-h2 { font-size: 30px; font-weight: 800; color: #1d4ed8; margin: 0 0 8px 0; letter-spacing: -0.5px; }\r\n#pth-id-studio-wrapper .pth-sub { font-size: 15px; color: #475569; margin: 0 0 10px 0; font-weight: 500; }\r\n#pth-id-studio-wrapper .pth-badges { display: flex; gap: 8px; flex-wrap: wrap; }\r\n#pth-id-studio-wrapper .pth-version-badge { background: #dbeafe; color: #1e40af; border: 1px solid #bfdbfe; padding: 4px 10px; border-radius: 999px; font-size: 12px; font-weight: 700; }\r\n#pth-id-studio-wrapper .pth-status-offline { background: #dcfce7; color: #166534; border: 1px solid #bbf7d0; padding: 4px 10px; border-radius: 999px; font-size: 12px; font-weight: 700; }\r\n#pth-id-studio-wrapper .pth-head-btns { display: flex; gap: 8px; flex-wrap: wrap; }\r\n\r\n#pth-id-studio-wrapper .pth-btn { padding: 9px 16px; border-radius: 8px; font-weight: 700; cursor: pointer; border: 1px solid #e2e8f0; font-family: inherit; font-size: 14px; transition: 0.15s; background: #ffffff; color: #334155; }\r\n#pth-id-studio-wrapper .pth-btn:hover { background: #f1f5f9; color: #0f172a; }\r\n#pth-id-studio-wrapper .pth-btn.primary { background: #1d4ed8; color: #ffffff; border-color: #1d4ed8; }\r\n#pth-id-studio-wrapper .pth-btn.primary:hover { background: #1e40af; color: #ffffff; }\r\n#pth-id-studio-wrapper .pth-btn.success { background: #047857; color: #ffffff; border-color: #047857; }\r\n#pth-id-studio-wrapper .pth-btn.success:hover { background: #065f46; color: #ffffff; }\r\n#pth-id-studio-wrapper .pth-btn.danger { background: #fee2e2; color: #991b1b; border-color: #fecaca; }\r\n#pth-id-studio-wrapper .pth-btn.danger:hover { background: #fecaca; color: #7f1d1d; }\r\n#pth-id-studio-wrapper .pth-btn:focus-visible { outline: 3px solid #93c5fd; outline-offset: 2px; }\r\n\r\n\/* Tabs *\/\r\n#pth-id-studio-wrapper .pth-tabbar { display: flex; gap: 6px; flex-wrap: wrap; border-bottom: 2px solid #e2e8f0; margin-bottom: 20px; }\r\n#pth-id-studio-wrapper .pth-tab { padding: 11px 18px; border: none; background: transparent; font-family: inherit; font-size: 14px; font-weight: 700; color: #64748b; cursor: pointer; border-bottom: 3px solid transparent; margin-bottom: -2px; transition: 0.15s; }\r\n#pth-id-studio-wrapper .pth-tab:hover { color: #1d4ed8; }\r\n#pth-id-studio-wrapper .pth-tab.active { color: #1d4ed8; border-bottom-color: #1d4ed8; }\r\n#pth-id-studio-wrapper .pth-tab:focus-visible { outline: 3px solid #93c5fd; outline-offset: -3px; }\r\n#pth-id-studio-wrapper .pth-panel { display: none; }\r\n#pth-id-studio-wrapper .pth-panel.active { display: block; }\r\n\r\n\/* Grid *\/\r\n#pth-id-studio-wrapper .pth-grid { display: grid; grid-template-columns: 1.8fr 1fr; gap: 22px; align-items: start; transition: 0.25s ease; }\r\n#pth-id-studio-wrapper .pth-grid.pth-full-width { grid-template-columns: 1fr; }\r\n#pth-id-studio-wrapper .pth-card { background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 22px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); }\r\n\r\n\/* Controls *\/\r\n#pth-id-studio-wrapper .pth-ctrlbar { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 18px; padding-bottom: 16px; border-bottom: 1px solid #f1f5f9; }\r\n#pth-id-studio-wrapper .pth-field { display: flex; flex-direction: column; gap: 6px; }\r\n#pth-id-studio-wrapper .pth-label { font-size: 13px; font-weight: 700; color: #334155; }\r\n#pth-id-studio-wrapper .pth-select, #pth-id-studio-wrapper .pth-textbox { padding: 9px 12px; border: 1px solid #cbd5e1; border-radius: 8px; font-family: inherit; font-size: 14px; color: #0f172a; background: #ffffff; }\r\n#pth-id-studio-wrapper .pth-select:focus, #pth-id-studio-wrapper .pth-textbox:focus { outline: 3px solid #93c5fd; outline-offset: 1px; border-color: #1d4ed8; }\r\n#pth-id-studio-wrapper .pth-checkwrap { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; }\r\n#pth-id-studio-wrapper .pth-checkrow { display: inline-flex; align-items: center; gap: 7px; font-size: 13.5px; color: #334155; font-weight: 600; }\r\n#pth-id-studio-wrapper .pth-checkrow input { width: 16px; height: 16px; accent-color: #1d4ed8; cursor: pointer; }\r\n\r\n#pth-id-studio-wrapper .pth-io { margin-bottom: 18px; }\r\n#pth-id-studio-wrapper .pth-io-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 7px; }\r\n#pth-id-studio-wrapper .pth-textarea { width: 100%; min-height: 250px; padding: 13px; border: 1px solid #cbd5e1; border-radius: 8px; font-family: 'Consolas', 'Monaco', monospace; font-size: 13.5px; line-height: 1.8; color: #0f172a; background: #ffffff; resize: vertical; }\r\n#pth-id-studio-wrapper .pth-textarea:focus { outline: 3px solid #93c5fd; outline-offset: 1px; border-color: #1d4ed8; }\r\n#pth-id-studio-wrapper .pth-textarea.output { background: #f8fafc; color: #1e293b; }\r\n#pth-id-studio-wrapper .pth-stat { background: #f1f5f9; color: #475569; padding: 3px 10px; border-radius: 999px; font-size: 12px; font-weight: 700; }\r\n\r\n\/* Quick copy card *\/\r\n#pth-id-studio-wrapper .pth-quick { background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 10px; padding: 16px; margin-bottom: 20px; cursor: pointer; transition: 0.15s; width: 100%; text-align: left; font-family: inherit; }\r\n#pth-id-studio-wrapper .pth-quick:hover { background: #dbeafe; }\r\n#pth-id-studio-wrapper .pth-quick:focus-visible { outline: 3px solid #93c5fd; outline-offset: 2px; }\r\n#pth-id-studio-wrapper .pth-quick-id { font-family: 'Consolas', 'Monaco', monospace; font-size: 15px; font-weight: 800; color: #1e40af; word-break: break-all; margin-bottom: 5px; min-height: 22px; }\r\n#pth-id-studio-wrapper .pth-quick-label { font-size: 12px; color: #3b82f6; font-weight: 700; }\r\n\r\n\/* Tables & results *\/\r\n#pth-id-studio-wrapper .pth-tablewrap { border: 1px solid #e2e8f0; border-radius: 8px; overflow: auto; max-height: 470px; min-height: 120px; }\r\n#pth-id-studio-wrapper table { width: 100%; border-collapse: collapse; font-size: 13px; }\r\n#pth-id-studio-wrapper th { background: #f1f5f9; color: #334155; text-align: left; padding: 9px 12px; font-weight: 800; font-size: 12px; text-transform: uppercase; letter-spacing: 0.4px; position: sticky; top: 0; }\r\n#pth-id-studio-wrapper td { padding: 9px 12px; border-top: 1px solid #f1f5f9; color: #334155; font-family: 'Consolas', 'Monaco', monospace; word-break: break-all; }\r\n#pth-id-studio-wrapper td.lbl { font-family: inherit; font-weight: 700; color: #0f172a; width: 34%; }\r\n#pth-id-studio-wrapper tr:hover td { background: #f8fafc; }\r\n\r\n#pth-id-studio-wrapper .pth-statgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 18px; }\r\n#pth-id-studio-wrapper .pth-statbox { border: 1px solid #e2e8f0; border-radius: 8px; padding: 13px; text-align: center; background: #f8fafc; }\r\n#pth-id-studio-wrapper .pth-statbox .n { font-size: 22px; font-weight: 800; color: #0f172a; font-family: 'Consolas', monospace; }\r\n#pth-id-studio-wrapper .pth-statbox .t { font-size: 12px; color: #64748b; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; }\r\n#pth-id-studio-wrapper .pth-statbox.good { background: #f0fdf4; border-color: #bbf7d0; }\r\n#pth-id-studio-wrapper .pth-statbox.good .n { color: #166534; }\r\n#pth-id-studio-wrapper .pth-statbox.bad { background: #fef2f2; border-color: #fecaca; }\r\n#pth-id-studio-wrapper .pth-statbox.bad .n { color: #991b1b; }\r\n\r\n#pth-id-studio-wrapper .pth-verdict { padding: 12px 15px; border-radius: 8px; font-size: 14px; font-weight: 700; margin-bottom: 16px; }\r\n#pth-id-studio-wrapper .pth-verdict.ok { background: #f0fdf4; border: 1px solid #bbf7d0; color: #166534; }\r\n#pth-id-studio-wrapper .pth-verdict.err { background: #fef2f2; border: 1px solid #fecaca; color: #991b1b; }\r\n#pth-id-studio-wrapper .pth-verdict.neutral { background: #f1f5f9; border: 1px solid #e2e8f0; color: #475569; }\r\n\r\n\/* Sidebar *\/\r\n#pth-id-studio-wrapper .pth-side h3 { font-size: 15px; font-weight: 800; color: #1e293b; margin: 0 0 9px 0; }\r\n#pth-id-studio-wrapper .pth-side h3.spaced { margin-top: 22px; }\r\n#pth-id-studio-wrapper .pth-side p { font-size: 13.5px; color: #475569; margin: 0 0 12px 0; }\r\n#pth-id-studio-wrapper .pth-side ul { margin: 0 0 12px 0; padding-left: 18px; }\r\n#pth-id-studio-wrapper .pth-side li { font-size: 13.5px; color: #475569; margin-bottom: 6px; }\r\n#pth-id-studio-wrapper .pth-side a { color: #1d4ed8; font-weight: 700; text-decoration: none; }\r\n#pth-id-studio-wrapper .pth-side a:hover { text-decoration: underline; }\r\n#pth-id-studio-wrapper code { background: #f1f5f9; padding: 2px 6px; border-radius: 4px; font-family: 'Consolas', monospace; font-size: 12.5px; color: #1e293b; }\r\n#pth-id-studio-wrapper .pth-tip { background: #eff6ff; border: 1px solid #bfdbfe; padding: 13px; border-radius: 8px; font-size: 13px; color: #1e40af; line-height: 1.6; }\r\n\r\n\/* Toast *\/\r\n#pth-id-studio-wrapper .pth-toast { position: fixed; bottom: 24px; right: 24px; background: #0f172a; color: #ffffff; padding: 13px 22px; border-radius: 10px; font-size: 14px; font-weight: 700; box-shadow: 0 10px 25px rgba(0,0,0,0.2); z-index: 99999; display: none; }\r\n#pth-id-studio-wrapper .pth-toast.err { background: #991b1b; }\r\n\r\n@media (max-width: 900px) {\r\n    #pth-id-studio-wrapper { padding: 14px; }\r\n    #pth-id-studio-wrapper .pth-grid { grid-template-columns: 1fr; }\r\n    #pth-id-studio-wrapper .pth-h2 { font-size: 24px; }\r\n    #pth-id-studio-wrapper .pth-tab { padding: 10px 13px; font-size: 13px; }\r\n    #pth-id-studio-wrapper .pth-statgrid { grid-template-columns: 1fr; }\r\n}\r\n<\/style>\r\n\r\n<div id=\"pth-id-studio-wrapper\">\r\n\r\n    <div id=\"pth-toast-id\" class=\"pth-toast\" role=\"status\" aria-live=\"polite\">Copied to clipboard<\/div>\r\n\r\n    <div class=\"pth-head\">\r\n        <div>\r\n            <h2 class=\"pth-h2\">\ud83c\udd94 ID Studio Pro<\/h2>\r\n            <p class=\"pth-sub\">Generate, inspect and validate UUIDs, ULIDs, NanoIDs and other unique identifiers \u2014 entirely in your browser.<\/p>\r\n            <div class=\"pth-badges\">\r\n                <span class=\"pth-version-badge\">v3.0<\/span>\r\n                <span class=\"pth-status-offline\">\ud83d\udd12 100% Offline<\/span>\r\n            <\/div>\r\n        <\/div>\r\n        <div class=\"pth-head-btns\">\r\n            <button type=\"button\" class=\"pth-btn\" id=\"pth-id-sample-btn\">\ud83d\udca1 Load Sample<\/button>\r\n            <button type=\"button\" class=\"pth-btn\" id=\"pth-id-fw-btn\">\u26f6 Full Width<\/button>\r\n            <button type=\"button\" class=\"pth-btn danger\" id=\"pth-id-clear-btn\">\ud83d\uddd1\ufe0f Clear<\/button>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"pth-tabbar\" role=\"tablist\">\r\n        <button type=\"button\" class=\"pth-tab active\" data-pth-panel=\"gen\" role=\"tab\">\ud83c\udfb2 Generate<\/button>\r\n        <button type=\"button\" class=\"pth-tab\" data-pth-panel=\"inspect\" role=\"tab\">\ud83d\udd0e Inspector<\/button>\r\n        <button type=\"button\" class=\"pth-tab\" data-pth-panel=\"other\" role=\"tab\">\ud83c\udd94 Other Formats<\/button>\r\n        <button type=\"button\" class=\"pth-tab\" data-pth-panel=\"validate\" role=\"tab\">\u2705 Validate &amp; Convert<\/button>\r\n    <\/div>\r\n\r\n    <div class=\"pth-grid\" id=\"pth-id-grid\">\r\n\r\n        <div>\r\n            <!-- ============ PANEL 1: GENERATE ============ -->\r\n            <div class=\"pth-panel active\" id=\"pth-panel-gen\" role=\"tabpanel\">\r\n                <div class=\"pth-card\">\r\n                    <div class=\"pth-ctrlbar\">\r\n                        <div class=\"pth-field\" style=\"min-width:230px;\">\r\n                            <label class=\"pth-label\" for=\"pth-uuid-version\">UUID Version<\/label>\r\n                            <select id=\"pth-uuid-version\" class=\"pth-select\" aria-label=\"UUID version\">\r\n                                <option value=\"4\">v4 \u2014 random (the common default)<\/option>\r\n                                <option value=\"7\">v7 \u2014 time-ordered (best for database keys)<\/option>\r\n                                <option value=\"1\">v1 \u2014 time and node based<\/option>\r\n                                <option value=\"6\">v6 \u2014 reordered v1, sortable<\/option>\r\n                                <option value=\"8\">v8 \u2014 vendor \/ experimental<\/option>\r\n                                <option value=\"nil\">NIL \u2014 all zeros<\/option>\r\n                                <option value=\"max\">MAX \u2014 all ones<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                        <div class=\"pth-field\" style=\"width:130px;\">\r\n                            <label class=\"pth-label\" for=\"pth-qty\">How many<\/label>\r\n                            <input type=\"number\" id=\"pth-qty\" class=\"pth-textbox\" value=\"10\" min=\"1\" max=\"10000\" aria-label=\"Quantity to generate\">\r\n                        <\/div>\r\n                        <button type=\"button\" class=\"pth-btn primary\" id=\"pth-gen-btn\" style=\"margin-left:auto;\">\u26a1 Generate<\/button>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-checkwrap\" style=\"margin-bottom:18px;\">\r\n                        <label class=\"pth-checkrow\"><input type=\"checkbox\" id=\"pth-opt-hyphens\" checked> Hyphens<\/label>\r\n                        <label class=\"pth-checkrow\"><input type=\"checkbox\" id=\"pth-opt-upper\"> Uppercase<\/label>\r\n                        <label class=\"pth-checkrow\"><input type=\"checkbox\" id=\"pth-opt-braces\"> Braces { }<\/label>\r\n                        <label class=\"pth-checkrow\"><input type=\"checkbox\" id=\"pth-opt-quotes\"> Quoted \"\u2026\"<\/label>\r\n                        <label class=\"pth-checkrow\"><input type=\"checkbox\" id=\"pth-opt-commas\"> Comma separated<\/label>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-io\">\r\n                        <div class=\"pth-io-head\">\r\n                            <label class=\"pth-label\" for=\"pth-gen-output\">Generated Identifiers<\/label>\r\n                            <div style=\"display:flex; gap:8px; align-items:center; flex-wrap:wrap;\">\r\n                                <span class=\"pth-stat\" id=\"pth-gen-count\">0 generated<\/span>\r\n                                <button type=\"button\" class=\"pth-btn\" id=\"pth-gen-copy\">Copy<\/button>\r\n                                <button type=\"button\" class=\"pth-btn success\" id=\"pth-gen-download\">Save .txt<\/button>\r\n                            <\/div>\r\n                        <\/div>\r\n                        <textarea id=\"pth-gen-output\" class=\"pth-textarea output\" readonly placeholder=\"Press Generate and your identifiers appear here...\" aria-label=\"Generated identifiers\"><\/textarea>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- ============ PANEL 2: INSPECTOR ============ -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-inspect\" role=\"tabpanel\">\r\n                <div class=\"pth-card\">\r\n                    <div class=\"pth-field\" style=\"margin-bottom:16px;\">\r\n                        <label class=\"pth-label\" for=\"pth-inspect-input\">Paste a single UUID to decode<\/label>\r\n                        <input type=\"text\" id=\"pth-inspect-input\" class=\"pth-textbox\" placeholder=\"e.g. 018f1c2a-7b3d-7c4e-9a1b-2c3d4e5f6a7b\" aria-label=\"UUID to inspect\">\r\n                    <\/div>\r\n\r\n                    <div id=\"pth-inspect-verdict\" class=\"pth-verdict neutral\">Paste a UUID above and it is decoded straight away.<\/div>\r\n\r\n                    <div class=\"pth-tablewrap\">\r\n                        <table>\r\n                            <thead><tr><th>Field<\/th><th>Value<\/th><\/tr><\/thead>\r\n                            <tbody id=\"pth-inspect-body\"><\/tbody>\r\n                        <\/table>\r\n                    <\/div>\r\n                    <p style=\"font-size:12.5px; color:#64748b; margin:11px 0 0 0;\">Versions 1, 6 and 7 carry a creation time inside them, so the timestamp row shows a real date. Version 4 does not \u2014 it is random from end to end.<\/p>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- ============ PANEL 3: OTHER FORMATS ============ -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-other\" role=\"tabpanel\">\r\n                <div class=\"pth-card\">\r\n                    <div class=\"pth-ctrlbar\">\r\n                        <div class=\"pth-field\" style=\"min-width:230px;\">\r\n                            <label class=\"pth-label\" for=\"pth-other-format\">Identifier Format<\/label>\r\n                            <select id=\"pth-other-format\" class=\"pth-select\" aria-label=\"Identifier format\">\r\n                                <option value=\"ulid\">ULID \u2014 26 chars, sortable by time<\/option>\r\n                                <option value=\"nanoid\">NanoID \u2014 short and URL-safe<\/option>\r\n                                <option value=\"objectid\">MongoDB ObjectID \u2014 24 hex chars<\/option>\r\n                                <option value=\"snowflake\">Snowflake \u2014 64-bit numeric<\/option>\r\n                                <option value=\"cuid\">CUID2-style \u2014 collision resistant<\/option>\r\n                                <option value=\"short\">Short UUID \u2014 base58 encoded<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                        <div class=\"pth-field\" style=\"width:130px;\">\r\n                            <label class=\"pth-label\" for=\"pth-other-qty\">How many<\/label>\r\n                            <input type=\"number\" id=\"pth-other-qty\" class=\"pth-textbox\" value=\"10\" min=\"1\" max=\"10000\" aria-label=\"Quantity\">\r\n                        <\/div>\r\n                        <div class=\"pth-field\" style=\"width:130px;\" id=\"pth-nano-len-wrap\">\r\n                            <label class=\"pth-label\" for=\"pth-nano-len\">NanoID length<\/label>\r\n                            <input type=\"number\" id=\"pth-nano-len\" class=\"pth-textbox\" value=\"21\" min=\"6\" max=\"64\" aria-label=\"NanoID length\">\r\n                        <\/div>\r\n                        <button type=\"button\" class=\"pth-btn primary\" id=\"pth-other-btn\" style=\"margin-left:auto;\">\u26a1 Generate<\/button>\r\n                    <\/div>\r\n\r\n                    <div id=\"pth-other-note\" class=\"pth-verdict neutral\" style=\"font-weight:500;\"><\/div>\r\n\r\n                    <div class=\"pth-io\">\r\n                        <div class=\"pth-io-head\">\r\n                            <label class=\"pth-label\" for=\"pth-other-output\">Generated Identifiers<\/label>\r\n                            <div style=\"display:flex; gap:8px; align-items:center; flex-wrap:wrap;\">\r\n                                <span class=\"pth-stat\" id=\"pth-other-count\">0 generated<\/span>\r\n                                <button type=\"button\" class=\"pth-btn\" id=\"pth-other-copy\">Copy<\/button>\r\n                                <button type=\"button\" class=\"pth-btn success\" id=\"pth-other-download\">Save .txt<\/button>\r\n                            <\/div>\r\n                        <\/div>\r\n                        <textarea id=\"pth-other-output\" class=\"pth-textarea output\" readonly placeholder=\"Pick a format and press Generate...\" aria-label=\"Generated identifiers\"><\/textarea>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- ============ PANEL 4: VALIDATE & CONVERT ============ -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-validate\" role=\"tabpanel\">\r\n                <div class=\"pth-card\">\r\n                    <div class=\"pth-io\">\r\n                        <div class=\"pth-io-head\">\r\n                            <label class=\"pth-label\" for=\"pth-val-input\">Paste identifiers, one per line<\/label>\r\n                            <button type=\"button\" class=\"pth-btn\" id=\"pth-val-clear\">Clear list<\/button>\r\n                        <\/div>\r\n                        <textarea id=\"pth-val-input\" class=\"pth-textarea\" style=\"min-height:170px;\" placeholder=\"550e8400-e29b-41d4-a716-446655440000&#10;not-a-real-uuid&#10;{6ba7b810-9dad-11d1-80b4-00c04fd430c8}\" aria-label=\"Identifiers to validate\"><\/textarea>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-statgrid\">\r\n                        <div class=\"pth-statbox\"><div class=\"n\" id=\"pth-val-total\">0<\/div><div class=\"t\">Lines<\/div><\/div>\r\n                        <div class=\"pth-statbox good\"><div class=\"n\" id=\"pth-val-good\">0<\/div><div class=\"t\">Valid<\/div><\/div>\r\n                        <div class=\"pth-statbox bad\"><div class=\"n\" id=\"pth-val-bad\">0<\/div><div class=\"t\">Invalid<\/div><\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-ctrlbar\" style=\"border-bottom:none; padding-bottom:0;\">\r\n                        <div class=\"pth-field\" style=\"min-width:220px;\">\r\n                            <label class=\"pth-label\" for=\"pth-convert-format\">Convert valid UUIDs to<\/label>\r\n                            <select id=\"pth-convert-format\" class=\"pth-select\" aria-label=\"Conversion format\">\r\n                                <option value=\"plain\">Canonical form (with hyphens)<\/option>\r\n                                <option value=\"hex\">Raw hex (no hyphens)<\/option>\r\n                                <option value=\"int\">128-bit integer (decimal)<\/option>\r\n                                <option value=\"base58\">Base58 short form<\/option>\r\n                                <option value=\"csv\">CSV rows<\/option>\r\n                                <option value=\"json\">JSON array<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                        <button type=\"button\" class=\"pth-btn primary\" id=\"pth-convert-btn\">\ud83d\udd01 Convert<\/button>\r\n                        <button type=\"button\" class=\"pth-btn\" id=\"pth-convert-copy\">Copy result<\/button>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-io\" style=\"margin-top:18px; margin-bottom:0;\">\r\n                        <div class=\"pth-io-head\"><label class=\"pth-label\" for=\"pth-convert-output\">Result<\/label><\/div>\r\n                        <textarea id=\"pth-convert-output\" class=\"pth-textarea output\" style=\"min-height:170px;\" readonly placeholder=\"Converted output appears here...\" aria-label=\"Converted result\"><\/textarea>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- ============ SIDEBAR ============ -->\r\n        <div class=\"pth-card pth-side\" id=\"pth-id-side\">\r\n\r\n            <button type=\"button\" class=\"pth-quick\" id=\"pth-quick-btn\" aria-label=\"Copy a fresh v4 UUID\">\r\n                <div class=\"pth-quick-id\" id=\"pth-quick-id\">Loading...<\/div>\r\n                <div class=\"pth-quick-label\">Click to copy a fresh v4 UUID<\/div>\r\n            <\/button>\r\n\r\n            <div id=\"pth-side-gen\">\r\n                <h3>Which version should you pick?<\/h3>\r\n                <p><strong>v4<\/strong> is 122 random bits and the safe default when you just need something unique and unguessable.<\/p>\r\n                <p><strong>v7<\/strong> starts with a millisecond timestamp, so generated values sort in creation order. That single property makes a large difference as a database primary key: v4 keys scatter across a B-tree index and cause page splits on every insert, while v7 keys append in order.<\/p>\r\n                <p><strong>v1<\/strong> and <strong>v6<\/strong> also embed a timestamp. v1 places the time fields in an order that does not sort correctly as text; v6 rearranges the same data so it does.<\/p>\r\n                <div class=\"pth-tip\"><strong>Worth knowing:<\/strong> v1, v6 and v7 all reveal roughly when they were created. If an identifier is exposed publicly and that leak matters, use v4.<\/div>\r\n            <\/div>\r\n\r\n            <div id=\"pth-side-inspect\" style=\"display:none;\">\r\n                <h3>What the fields mean<\/h3>\r\n                <p>The <strong>version<\/strong> lives in the first digit of the third group. The <strong>variant<\/strong> sits in the first digit of the fourth group and marks the layout as the standard RFC one.<\/p>\r\n                <p>For v1 and v6, the <strong>node<\/strong> field was originally the machine's MAC address. Browsers cannot read hardware addresses, so any UUID generated on a web page uses random bits with the multicast flag set instead \u2014 which is exactly what the specification asks for.<\/p>\r\n                <div class=\"pth-tip\"><strong>Handy check:<\/strong> if a supposedly random identifier decodes as v1 with a real timestamp, it is more predictable than whoever chose it may realise.<\/div>\r\n            <\/div>\r\n\r\n            <div id=\"pth-side-other\" style=\"display:none;\">\r\n                <h3>Beyond UUID<\/h3>\r\n                <p><strong>ULID<\/strong> packs a 48-bit timestamp plus 80 random bits into 26 Crockford base32 characters. It sorts by time as plain text and avoids the letters I, L, O and U so it cannot spell anything awkward.<\/p>\r\n                <p><strong>NanoID<\/strong> trades length for compactness \u2014 21 characters from a URL-safe alphabet, which is shorter than a UUID while keeping a similar collision profile.<\/p>\r\n                <p><strong>ObjectID<\/strong> is MongoDB's 12-byte identifier, and <strong>Snowflake<\/strong> is the 64-bit numeric scheme popularised by Twitter for ordered IDs that still fit a bigint column.<\/p>\r\n                <div class=\"pth-tip\"><strong>Honest note:<\/strong> the CUID2 option here produces a CUID2-shaped identifier from browser randomness. It is fine for local testing, but for production use the official library rather than any web page.<\/div>\r\n            <\/div>\r\n\r\n            <div id=\"pth-side-validate\" style=\"display:none;\">\r\n                <h3>What counts as valid<\/h3>\r\n                <p>The checker accepts the canonical hyphenated form, the bare 32-character hex form, and values wrapped in braces or quotes. It reports the version it found rather than only passing or failing.<\/p>\r\n                <p>The <strong>integer<\/strong> conversion prints the full 128-bit value in decimal \u2014 useful when a system stores UUIDs in a numeric column. <strong>Base58<\/strong> shortens the same value to about 22 characters using an alphabet with no look-alike glyphs.<\/p>\r\n                <div class=\"pth-tip\"><strong>Common trap:<\/strong> a UUID stored as text takes 36 bytes; stored as binary it takes 16. On a table with millions of rows that difference shows up in index size and query speed.<\/div>\r\n            <\/div>\r\n\r\n            <h3 class=\"spaced\">Related tools<\/h3>\r\n            <ul>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/free-strong-password-generator\/\">Strong Password Generator<\/a> \u2014 for human secrets, not machine IDs<\/li>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/free-secure-hash-generator\/\">Secure Hash Generator<\/a> \u2014 SHA-256 and MD5 checksums<\/li>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/jwt-decoder-inspector\/\">JWT Decoder &amp; Inspector<\/a> \u2014 for tokens carrying an ID<\/li>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/lorem-ipsum-and-json-dummy-data-generator-pro\/\">Dummy Data Generator<\/a> \u2014 full fake records, not just IDs<\/li>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/csv-to-sql-query-converter\/\">CSV to SQL Converter<\/a> \u2014 turn an ID list into INSERT statements<\/li>\r\n            <\/ul>\r\n        <\/div>\r\n\r\n    <\/div>\r\n<\/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\r\n    window.pthIdStudioApp = {\r\n        initialized: false,\r\n        currentTab: 'gen',\r\n        quickTimer: null,\r\n\r\n        B58: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz',\r\n        B32: '0123456789ABCDEFGHJKMNPQRSTVWXYZ',\r\n        NANO: 'useandom26T198340PXJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrict_-',\r\n        objectCounter: 0,\r\n        lastV7Ms: 0,\r\n        v7Seq: 0,\r\n        lastUlidMs: 0,\r\n        ulidTail: null,\r\n\r\n        \/* ================= Random ================= *\/\r\n        randomBytes: function(n) {\r\n            var arr = new Uint8Array(n);\r\n            var i;\r\n            if (typeof crypto !== 'undefined' && crypto.getRandomValues) {\r\n                crypto.getRandomValues(arr);\r\n            } else {\r\n                for (i = 0; i < n; i++) { arr[i] = Math.floor(Math.random() * 256); }\r\n            }\r\n            return arr;\r\n        },\r\n\r\n        randomInt: function(max) {\r\n            var arr = this.randomBytes(4);\r\n            var v = ((arr[0] << 24) >>> 0) + (arr[1] << 16) + (arr[2] << 8) + arr[3];\r\n            return v % max;\r\n        },\r\n\r\n        hex2: function(b) {\r\n            return (b < 16 ? '0' : '') + b.toString(16);\r\n        },\r\n\r\n        bytesToHex: function(bytes) {\r\n            var s = '';\r\n            var i;\r\n            for (i = 0; i < bytes.length; i++) { s += this.hex2(bytes[i]); }\r\n            return s;\r\n        },\r\n\r\n        hexToCanonical: function(h) {\r\n            return h.substring(0, 8) + '-' + h.substring(8, 12) + '-' + h.substring(12, 16) + '-' + h.substring(16, 20) + '-' + h.substring(20, 32);\r\n        },\r\n\r\n        \/* ================= UUID builders ================= *\/\r\n        setVariant: function(bytes) {\r\n            bytes[8] = (bytes[8] & 0x3F) | 0x80;\r\n            return bytes;\r\n        },\r\n\r\n        setVersion: function(bytes, v) {\r\n            bytes[6] = (bytes[6] & 0x0F) | (v << 4);\r\n            return bytes;\r\n        },\r\n\r\n        uuidV4: function() {\r\n            var b = this.randomBytes(16);\r\n            this.setVersion(b, 4);\r\n            this.setVariant(b);\r\n            return this.hexToCanonical(this.bytesToHex(b));\r\n        },\r\n\r\n        uuidV8: function() {\r\n            var b = this.randomBytes(16);\r\n            this.setVersion(b, 8);\r\n            this.setVariant(b);\r\n            return this.hexToCanonical(this.bytesToHex(b));\r\n        },\r\n\r\n        \/* 60-bit Gregorian tick count, split into two 32-bit halves.\r\n           ES5 has no BigInt, so the arithmetic is done on safe-range numbers. *\/\r\n        gregorianTicks: function(ms) {\r\n            var lo = (ms % 4294967296) * 10000;\r\n            var hi = Math.floor(ms \/ 4294967296) * 10000;\r\n            var carry = Math.floor(lo \/ 4294967296);\r\n            lo = lo - (carry * 4294967296);\r\n            hi = hi + carry;\r\n\r\n            lo = lo + 0x13814000;\r\n            if (lo >= 4294967296) { lo = lo - 4294967296; hi = hi + 1; }\r\n            hi = hi + 0x01B21DD2;\r\n\r\n            return { hi: hi, lo: lo };\r\n        },\r\n\r\n        uuidV1: function(seq) {\r\n            var t = this.gregorianTicks(new Date().getTime());\r\n            var extra = seq % 10000;\r\n            var lo = t.lo + extra;\r\n            var hi = t.hi;\r\n            if (lo >= 4294967296) { lo = lo - 4294967296; hi = hi + 1; }\r\n\r\n            var rnd = this.randomBytes(8);\r\n            var clockSeq = (((rnd[0] << 8) | rnd[1]) & 0x3FFF) | 0x8000;\r\n            var timeLow = this.padHex(lo.toString(16), 8);\r\n            var timeMid = this.padHex((hi % 65536).toString(16), 4);\r\n            var timeHi = this.padHex((0x1000 | (Math.floor(hi \/ 65536) % 4096)).toString(16), 4);\r\n\r\n            var node = '';\r\n            var i;\r\n            node += this.hex2(rnd[2] | 0x01);\r\n            for (i = 3; i < 8; i++) { node += this.hex2(rnd[i]); }\r\n\r\n            return timeLow + '-' + timeMid + '-' + timeHi + '-' + this.padHex(clockSeq.toString(16), 4) + '-' + node;\r\n        },\r\n\r\n        uuidV6: function(seq) {\r\n            var t = this.gregorianTicks(new Date().getTime());\r\n            var extra = seq % 10000;\r\n            var lo = t.lo + extra;\r\n            var hi = t.hi;\r\n            if (lo >= 4294967296) { lo = lo - 4294967296; hi = hi + 1; }\r\n\r\n            var timeHigh32 = (hi * 16) + Math.floor(lo \/ 268435456);\r\n            var timeMid16 = Math.floor(lo \/ 4096) % 65536;\r\n            var timeLow12 = lo % 4096;\r\n\r\n            var rnd = this.randomBytes(8);\r\n            var clockSeq = (((rnd[0] << 8) | rnd[1]) & 0x3FFF) | 0x8000;\r\n\r\n            var node = '';\r\n            var i;\r\n            node += this.hex2(rnd[2] | 0x01);\r\n            for (i = 3; i < 8; i++) { node += this.hex2(rnd[i]); }\r\n\r\n            return this.padHex((timeHigh32 % 4294967296).toString(16), 8) + '-' +\r\n                this.padHex(timeMid16.toString(16), 4) + '-' +\r\n                this.padHex((0x6000 | timeLow12).toString(16), 4) + '-' +\r\n                this.padHex(clockSeq.toString(16), 4) + '-' + node;\r\n        },\r\n\r\n        \/* RFC 9562 recommends a monotonic counter so that identifiers created\r\n           inside the same millisecond still sort in creation order. The 12-bit\r\n           rand_a field is used as that counter. *\/\r\n        uuidV7: function() {\r\n            var ms = new Date().getTime();\r\n            var b = this.randomBytes(16);\r\n\r\n            if (ms === this.lastV7Ms) {\r\n                this.v7Seq = this.v7Seq + 1;\r\n                if (this.v7Seq > 4095) {\r\n                    this.lastV7Ms = ms + 1;\r\n                    ms = this.lastV7Ms;\r\n                    this.v7Seq = 0;\r\n                }\r\n            } else if (ms > this.lastV7Ms) {\r\n                this.lastV7Ms = ms;\r\n                this.v7Seq = 0;\r\n            } else {\r\n                ms = this.lastV7Ms;\r\n                this.v7Seq = this.v7Seq + 1;\r\n            }\r\n\r\n            b[0] = Math.floor(ms \/ 1099511627776) % 256;\r\n            b[1] = Math.floor(ms \/ 4294967296) % 256;\r\n            b[2] = Math.floor(ms \/ 16777216) % 256;\r\n            b[3] = Math.floor(ms \/ 65536) % 256;\r\n            b[4] = Math.floor(ms \/ 256) % 256;\r\n            b[5] = ms % 256;\r\n\r\n            b[6] = 0x70 | ((this.v7Seq >> 8) & 0x0F);\r\n            b[7] = this.v7Seq & 0xFF;\r\n\r\n            this.setVariant(b);\r\n            return this.hexToCanonical(this.bytesToHex(b));\r\n        },\r\n\r\n        padHex: function(s, len) {\r\n            while (s.length < len) { s = '0' + s; }\r\n            return s;\r\n        },\r\n\r\n        \/* ================= Big-number helpers (no BigInt) ================= *\/\r\n        bytesToDecimal: function(bytes) {\r\n            var digits = [0];\r\n            var i, j, carry;\r\n            for (i = 0; i < bytes.length; i++) {\r\n                carry = bytes[i];\r\n                for (j = 0; j < digits.length; j++) {\r\n                    carry = carry + digits[j] * 256;\r\n                    digits[j] = carry % 10;\r\n                    carry = Math.floor(carry \/ 10);\r\n                }\r\n                while (carry > 0) {\r\n                    digits.push(carry % 10);\r\n                    carry = Math.floor(carry \/ 10);\r\n                }\r\n            }\r\n            var out = '';\r\n            for (i = digits.length - 1; i >= 0; i--) { out += digits[i]; }\r\n            return out === '' ? '0' : out;\r\n        },\r\n\r\n        bytesToBase58: function(bytes) {\r\n            var input = [];\r\n            var i;\r\n            for (i = 0; i < bytes.length; i++) { input.push(bytes[i]); }\r\n\r\n            var out = '';\r\n            var zeros = 0;\r\n            while (zeros < input.length && input[zeros] === 0) { zeros++; }\r\n\r\n            var start = zeros;\r\n            var remainder, div, j;\r\n            while (start < input.length) {\r\n                remainder = 0;\r\n                div = [];\r\n                for (j = start; j < input.length; j++) {\r\n                    var acc = remainder * 256 + input[j];\r\n                    div.push(Math.floor(acc \/ 58));\r\n                    remainder = acc % 58;\r\n                }\r\n                out = this.B58.charAt(remainder) + out;\r\n                var trimmed = [];\r\n                var k = 0;\r\n                while (k < div.length && div[k] === 0) { k++; }\r\n                for (; k < div.length; k++) { trimmed.push(div[k]); }\r\n                input = trimmed;\r\n                start = 0;\r\n                if (input.length === 0) { break; }\r\n            }\r\n            for (i = 0; i < zeros; i++) { out = '1' + out; }\r\n            return out === '' ? '1' : out;\r\n        },\r\n\r\n        u64ToDecimal: function(hi, lo) {\r\n            var bytes = [\r\n                Math.floor(hi \/ 16777216) % 256, Math.floor(hi \/ 65536) % 256,\r\n                Math.floor(hi \/ 256) % 256, hi % 256,\r\n                Math.floor(lo \/ 16777216) % 256, Math.floor(lo \/ 65536) % 256,\r\n                Math.floor(lo \/ 256) % 256, lo % 256\r\n            ];\r\n            return this.bytesToDecimal(bytes);\r\n        },\r\n\r\n        \/* ================= Other ID formats ================= *\/\r\n        \/* The ULID specification asks for the random component to be incremented\r\n           when several identifiers are produced inside the same millisecond, so\r\n           that plain text sorting still reflects creation order. *\/\r\n        ulid: function() {\r\n            var ms = new Date().getTime();\r\n            var i, rnd;\r\n            var chars = [];\r\n            var remaining = ms;\r\n\r\n            for (i = 0; i < 10; i++) {\r\n                chars.unshift(this.B32.charAt(remaining % 32));\r\n                remaining = Math.floor(remaining \/ 32);\r\n            }\r\n\r\n            if (ms === this.lastUlidMs && this.ulidTail) {\r\n                i = this.ulidTail.length - 1;\r\n                while (i >= 0) {\r\n                    if (this.ulidTail[i] < 31) { this.ulidTail[i] = this.ulidTail[i] + 1; break; }\r\n                    this.ulidTail[i] = 0;\r\n                    i = i - 1;\r\n                }\r\n            } else {\r\n                this.lastUlidMs = ms;\r\n                rnd = this.randomBytes(16);\r\n                this.ulidTail = [];\r\n                for (i = 0; i < 16; i++) { this.ulidTail.push(rnd[i] % 32); }\r\n            }\r\n\r\n            var rand = '';\r\n            for (i = 0; i < 16; i++) { rand += this.B32.charAt(this.ulidTail[i]); }\r\n            return chars.join('') + rand;\r\n        },\r\n\r\n        nanoid: function(len) {\r\n            var bytes = this.randomBytes(len);\r\n            var out = '';\r\n            var i;\r\n            for (i = 0; i < len; i++) { out += this.NANO.charAt(bytes[i] % this.NANO.length); }\r\n            return out;\r\n        },\r\n\r\n        objectId: function() {\r\n            var secs = Math.floor(new Date().getTime() \/ 1000);\r\n            var rnd = this.randomBytes(5);\r\n            var out = this.padHex(secs.toString(16), 8);\r\n            var i;\r\n            for (i = 0; i < 5; i++) { out += this.hex2(rnd[i]); }\r\n            this.objectCounter = (this.objectCounter + 1) % 16777216;\r\n            out += this.padHex(this.objectCounter.toString(16), 6);\r\n            return out;\r\n        },\r\n\r\n        snowflake: function(seq) {\r\n            var epoch = 1288834974657;\r\n            var ms = new Date().getTime() - epoch;\r\n            var machine = this.randomInt(1024);\r\n            var counter = seq % 4096;\r\n\r\n            var hi = Math.floor(ms \/ 2097152);\r\n            var loPart = (ms % 2097152) * 4194304;\r\n            var lo = loPart + (machine * 4096) + counter;\r\n            var carry = Math.floor(lo \/ 4294967296);\r\n            lo = lo - (carry * 4294967296);\r\n            hi = hi + carry;\r\n\r\n            return this.u64ToDecimal(hi, lo);\r\n        },\r\n\r\n        cuid2: function() {\r\n            var letters = 'abcdefghijklmnopqrstuvwxyz';\r\n            var first = letters.charAt(this.randomInt(26));\r\n            var time = new Date().getTime().toString(36);\r\n            var rnd = this.randomBytes(24);\r\n            var body = '';\r\n            var alphabet = '0123456789abcdefghijklmnopqrstuvwxyz';\r\n            var i;\r\n            for (i = 0; i < 24 - 1 - time.length; i++) {\r\n                body += alphabet.charAt(rnd[i] % 36);\r\n            }\r\n            return first + time + body;\r\n        },\r\n\r\n        shortUuid: function() {\r\n            var b = this.randomBytes(16);\r\n            this.setVersion(b, 4);\r\n            this.setVariant(b);\r\n            return this.bytesToBase58(b);\r\n        },\r\n\r\n        \/* ================= UI plumbing ================= *\/\r\n        init: function() {\r\n            this.bindHeader();\r\n            this.bindTabs();\r\n            this.bindGenerate();\r\n            this.bindInspect();\r\n            this.bindOther();\r\n            this.bindValidate();\r\n            this.refreshQuick();\r\n            this.runGenerate();\r\n            this.updateOtherNote();\r\n        },\r\n\r\n        bindHeader: function() {\r\n            var self = this;\r\n            var b;\r\n            b = document.getElementById('pth-id-sample-btn');\r\n            if (b) { b.addEventListener('click', function() { self.loadSample(); }); }\r\n            b = document.getElementById('pth-id-fw-btn');\r\n            if (b) { b.addEventListener('click', function() { self.toggleWidth(); }); }\r\n            b = document.getElementById('pth-id-clear-btn');\r\n            if (b) { b.addEventListener('click', function() { self.clearAll(); }); }\r\n            b = document.getElementById('pth-quick-btn');\r\n            if (b) {\r\n                b.addEventListener('click', function() {\r\n                    var el = document.getElementById('pth-quick-id');\r\n                    self.copyText(el ? el.innerHTML : '', 'UUID');\r\n                    self.refreshQuick();\r\n                });\r\n            }\r\n        },\r\n\r\n        refreshQuick: function() {\r\n            var el = document.getElementById('pth-quick-id');\r\n            if (el) { el.innerHTML = this.uuidV4(); }\r\n        },\r\n\r\n        bindTabs: function() {\r\n            var self = this;\r\n            var tabs = document.querySelectorAll('#pth-id-studio-wrapper .pth-tab');\r\n            var i;\r\n            for (i = 0; i < tabs.length; i++) {\r\n                tabs[i].addEventListener('click', function() {\r\n                    self.switchTab(this.getAttribute('data-pth-panel'));\r\n                });\r\n            }\r\n        },\r\n\r\n        switchTab: function(name) {\r\n            var tabs = document.querySelectorAll('#pth-id-studio-wrapper .pth-tab');\r\n            var panels = document.querySelectorAll('#pth-id-studio-wrapper .pth-panel');\r\n            var sides = ['gen', 'inspect', 'other', 'validate'];\r\n            var i, el;\r\n\r\n            for (i = 0; i < tabs.length; i++) {\r\n                tabs[i].classList.remove('active');\r\n                if (tabs[i].getAttribute('data-pth-panel') === name) { tabs[i].classList.add('active'); }\r\n            }\r\n            for (i = 0; i < panels.length; i++) { panels[i].classList.remove('active'); }\r\n            el = document.getElementById('pth-panel-' + name);\r\n            if (el) { el.classList.add('active'); }\r\n\r\n            for (i = 0; i < sides.length; i++) {\r\n                el = document.getElementById('pth-side-' + sides[i]);\r\n                if (el) { el.style.display = (sides[i] === name) ? 'block' : 'none'; }\r\n            }\r\n            this.currentTab = name;\r\n        },\r\n\r\n        toggleWidth: function() {\r\n            var grid = document.getElementById('pth-id-grid');\r\n            var side = document.getElementById('pth-id-side');\r\n            var btn = document.getElementById('pth-id-fw-btn');\r\n            if (!grid || !side || !btn) { return; }\r\n\r\n            if (grid.classList.contains('pth-full-width')) {\r\n                grid.classList.remove('pth-full-width');\r\n                side.style.display = 'block';\r\n                btn.innerHTML = '\u26f6 Full Width';\r\n            } else {\r\n                grid.classList.add('pth-full-width');\r\n                side.style.display = 'none';\r\n                btn.innerHTML = '\u25e8 Split View';\r\n            }\r\n        },\r\n\r\n        toast: function(msg, isError) {\r\n            var t = document.getElementById('pth-toast-id');\r\n            if (!t) { return; }\r\n            t.innerHTML = msg;\r\n            t.className = isError ? 'pth-toast err' : 'pth-toast';\r\n            t.style.display = 'block';\r\n            if (this.toastTimer) { clearTimeout(this.toastTimer); }\r\n            this.toastTimer = setTimeout(function() { t.style.display = 'none'; }, 3000);\r\n        },\r\n\r\n        copyText: function(value, label) {\r\n            var self = this;\r\n            if (!value) { this.toast('Nothing to copy yet', true); return; }\r\n            if (navigator.clipboard && navigator.clipboard.writeText) {\r\n                navigator.clipboard.writeText(value).then(function() {\r\n                    self.toast(label + ' copied to clipboard');\r\n                })['catch'](function() { self.fallbackCopy(value, label); });\r\n            } else {\r\n                this.fallbackCopy(value, label);\r\n            }\r\n        },\r\n\r\n        fallbackCopy: function(value, label) {\r\n            var ta = document.createElement('textarea');\r\n            ta.value = value;\r\n            ta.setAttribute('readonly', 'readonly');\r\n            ta.style.position = 'fixed';\r\n            ta.style.left = '-9999px';\r\n            document.body.appendChild(ta);\r\n            ta.select();\r\n            try {\r\n                document.execCommand('copy');\r\n                this.toast(label + ' copied to clipboard');\r\n            } catch (err) {\r\n                this.toast('Copy failed \u2014 select and copy manually', true);\r\n            }\r\n            document.body.removeChild(ta);\r\n        },\r\n\r\n        downloadText: function(text, filename) {\r\n            if (!text) { this.toast('Nothing to save yet', true); return; }\r\n            try {\r\n                var blob = new Blob([text], { type: 'text\/plain;charset=utf-8' });\r\n                var url = URL.createObjectURL(blob);\r\n                var a = document.createElement('a');\r\n                a.href = url;\r\n                a.download = filename;\r\n                document.body.appendChild(a);\r\n                a.click();\r\n                document.body.removeChild(a);\r\n                setTimeout(function() { URL.revokeObjectURL(url); }, 1000);\r\n                this.toast('File saved');\r\n            } catch (err) {\r\n                this.toast('Your browser blocked the download', true);\r\n            }\r\n        },\r\n\r\n        \/* ================= Generate tab ================= *\/\r\n        bindGenerate: function() {\r\n            var self = this;\r\n            var el;\r\n            el = document.getElementById('pth-gen-btn');\r\n            if (el) { el.addEventListener('click', function() { self.runGenerate(); }); }\r\n            el = document.getElementById('pth-gen-copy');\r\n            if (el) {\r\n                el.addEventListener('click', function() {\r\n                    var o = document.getElementById('pth-gen-output');\r\n                    self.copyText(o ? o.value : '', 'List');\r\n                });\r\n            }\r\n            el = document.getElementById('pth-gen-download');\r\n            if (el) {\r\n                el.addEventListener('click', function() {\r\n                    var o = document.getElementById('pth-gen-output');\r\n                    self.downloadText(o ? o.value : '', 'identifiers.txt');\r\n                });\r\n            }\r\n            var ids = ['pth-opt-hyphens', 'pth-opt-upper', 'pth-opt-braces', 'pth-opt-quotes', 'pth-opt-commas', 'pth-uuid-version'];\r\n            var i;\r\n            for (i = 0; i < ids.length; i++) {\r\n                el = document.getElementById(ids[i]);\r\n                if (el) { el.addEventListener('change', function() { self.runGenerate(); }); }\r\n            }\r\n        },\r\n\r\n        formatUuid: function(u) {\r\n            var opt = function(id) {\r\n                var el = document.getElementById(id);\r\n                return el ? el.checked : false;\r\n            };\r\n            var out = u;\r\n            if (!opt('pth-opt-hyphens')) { out = out.replace(\/-\/g, ''); }\r\n            if (opt('pth-opt-upper')) { out = out.toUpperCase(); }\r\n            if (opt('pth-opt-braces')) { out = '{' + out + '}'; }\r\n            if (opt('pth-opt-quotes')) { out = '\"' + out + '\"'; }\r\n            return out;\r\n        },\r\n\r\n        runGenerate: function() {\r\n            var verEl = document.getElementById('pth-uuid-version');\r\n            var qtyEl = document.getElementById('pth-qty');\r\n            var outEl = document.getElementById('pth-gen-output');\r\n            var countEl = document.getElementById('pth-gen-count');\r\n            if (!verEl || !qtyEl || !outEl) { return; }\r\n\r\n            var version = verEl.value;\r\n            var qty = parseInt(qtyEl.value, 10);\r\n            if (isNaN(qty) || qty < 1) { qty = 1; }\r\n            if (qty > 10000) { qty = 10000; qtyEl.value = 10000; this.toast('Capped at 10,000 per run'); }\r\n\r\n            var list = [];\r\n            var i, u;\r\n            for (i = 0; i < qty; i++) {\r\n                if (version === '4') { u = this.uuidV4(); }\r\n                else if (version === '7') { u = this.uuidV7(); }\r\n                else if (version === '1') { u = this.uuidV1(i); }\r\n                else if (version === '6') { u = this.uuidV6(i); }\r\n                else if (version === '8') { u = this.uuidV8(); }\r\n                else if (version === 'nil') { u = '00000000-0000-0000-0000-000000000000'; }\r\n                else { u = 'ffffffff-ffff-ffff-ffff-ffffffffffff'; }\r\n                list.push(this.formatUuid(u));\r\n            }\r\n\r\n            var sep = document.getElementById('pth-opt-commas');\r\n            outEl.value = (sep && sep.checked) ? list.join(',\\n') : list.join('\\n');\r\n            if (countEl) { countEl.innerHTML = qty + ' generated'; }\r\n        },\r\n\r\n        \/* ================= Inspector tab ================= *\/\r\n        bindInspect: function() {\r\n            var self = this;\r\n            var el = document.getElementById('pth-inspect-input');\r\n            if (el) { el.addEventListener('input', function() { self.runInspect(); }); }\r\n        },\r\n\r\n        normaliseUuid: function(raw) {\r\n            var s = String(raw).trim().replace(\/^[{\"']+|[}\"',]+$\/g, '').replace(\/-\/g, '').toLowerCase();\r\n            return \/^[0-9a-f]{32}$\/.test(s) ? s : null;\r\n        },\r\n\r\n        variantName: function(byte8) {\r\n            if ((byte8 & 0x80) === 0x00) { return 'Reserved \u2014 NCS backward compatibility'; }\r\n            if ((byte8 & 0xC0) === 0x80) { return 'RFC 4122 \/ RFC 9562 (standard)'; }\r\n            if ((byte8 & 0xE0) === 0xC0) { return 'Reserved \u2014 Microsoft COM'; }\r\n            return 'Reserved \u2014 future definition';\r\n        },\r\n\r\n        versionName: function(v) {\r\n            var names = {\r\n                1: 'Version 1 \u2014 time and node based',\r\n                2: 'Version 2 \u2014 DCE security',\r\n                3: 'Version 3 \u2014 name based, MD5',\r\n                4: 'Version 4 \u2014 random',\r\n                5: 'Version 5 \u2014 name based, SHA-1',\r\n                6: 'Version 6 \u2014 reordered time, sortable',\r\n                7: 'Version 7 \u2014 Unix time ordered',\r\n                8: 'Version 8 \u2014 vendor defined'\r\n            };\r\n            return names[v] || ('Version ' + v + ' \u2014 unrecognised');\r\n        },\r\n\r\n        runInspect: function() {\r\n            var inEl = document.getElementById('pth-inspect-input');\r\n            var verdict = document.getElementById('pth-inspect-verdict');\r\n            var body = document.getElementById('pth-inspect-body');\r\n            if (!inEl || !verdict || !body) { return; }\r\n\r\n            var raw = inEl.value;\r\n            if (!raw) {\r\n                verdict.className = 'pth-verdict neutral';\r\n                verdict.innerHTML = 'Paste a UUID above and it is decoded straight away.';\r\n                body.innerHTML = '';\r\n                return;\r\n            }\r\n\r\n            var hex = this.normaliseUuid(raw);\r\n            if (!hex) {\r\n                verdict.className = 'pth-verdict err';\r\n                verdict.innerHTML = '\u274c Not a valid UUID \u2014 expected 32 hexadecimal characters.';\r\n                body.innerHTML = '';\r\n                return;\r\n            }\r\n\r\n            var bytes = [];\r\n            var i;\r\n            for (i = 0; i < 16; i++) { bytes.push(parseInt(hex.substring(i * 2, i * 2 + 2), 16)); }\r\n\r\n            var version = (bytes[6] >> 4) & 0x0F;\r\n            var isNil = \/^0{32}$\/.test(hex);\r\n            var isMax = \/^f{32}$\/.test(hex);\r\n\r\n            verdict.className = 'pth-verdict ok';\r\n            if (isNil) { verdict.innerHTML = '\u2705 Valid \u2014 this is the NIL UUID (all zeros).'; }\r\n            else if (isMax) { verdict.innerHTML = '\u2705 Valid \u2014 this is the MAX UUID (all ones).'; }\r\n            else { verdict.innerHTML = '\u2705 Valid UUID \u2014 ' + this.versionName(version); }\r\n\r\n            var rows = '';\r\n            var self = this;\r\n            var addRow = function(label, value) {\r\n                rows += '<tr><td class=\"lbl\">' + label + '<\/td><td>' + value + '<\/td><\/tr>';\r\n            };\r\n\r\n            addRow('Canonical form', this.hexToCanonical(hex));\r\n            addRow('Version', isNil || isMax ? 'not applicable' : version + ' \u2014 ' + this.versionName(version).split(' \u2014 ')[1]);\r\n            addRow('Variant', isNil || isMax ? 'not applicable' : this.variantName(bytes[8]));\r\n            addRow('Raw hex', hex);\r\n            addRow('128-bit integer', this.bytesToDecimal(bytes));\r\n            addRow('Base58 short form', this.bytesToBase58(bytes));\r\n\r\n            if (version === 7 && !isNil && !isMax) {\r\n                var ms = bytes[0] * 1099511627776 + bytes[1] * 4294967296 + bytes[2] * 16777216 + bytes[3] * 65536 + bytes[4] * 256 + bytes[5];\r\n                addRow('Embedded timestamp', new Date(ms).toISOString().replace('T', ' ').replace('Z', ' UTC'));\r\n                addRow('Timestamp (ms)', ms);\r\n                addRow('Random bits', '74 bits after the timestamp and version fields');\r\n            } else if ((version === 1 || version === 6) && !isNil && !isMax) {\r\n                var tHi, tLo;\r\n                if (version === 1) {\r\n                    tLo = bytes[0] * 16777216 + bytes[1] * 65536 + bytes[2] * 256 + bytes[3];\r\n                    tHi = ((bytes[6] & 0x0F) * 256 + bytes[7]) * 65536 + (bytes[4] * 256 + bytes[5]);\r\n                } else {\r\n                    var high32 = bytes[0] * 16777216 + bytes[1] * 65536 + bytes[2] * 256 + bytes[3];\r\n                    var mid16 = bytes[4] * 256 + bytes[5];\r\n                    var low12 = (bytes[6] & 0x0F) * 256 + bytes[7];\r\n                    tHi = Math.floor(high32 \/ 16);\r\n                    tLo = ((high32 % 16) * 268435456) + (mid16 * 4096) + low12;\r\n                }\r\n                var ticks = tHi * 4294967296 + tLo;\r\n                var unixMs = Math.round((ticks - 122192928000000000) \/ 10000);\r\n                if (unixMs > 0 && unixMs < 253402300800000) {\r\n                    addRow('Embedded timestamp', new Date(unixMs).toISOString().replace('T', ' ').replace('Z', ' UTC'));\r\n                } else {\r\n                    addRow('Embedded timestamp', 'outside a sensible date range');\r\n                }\r\n                addRow('Clock sequence', (((bytes[8] & 0x3F) << 8) | bytes[9]));\r\n                var node = '';\r\n                for (i = 10; i < 16; i++) { node += (i > 10 ? ':' : '') + self.hex2(bytes[i]); }\r\n                addRow('Node field', node + ((bytes[10] & 0x01) ? ' (random, multicast bit set)' : ' (looks like a real MAC address)'));\r\n            } else if (version === 4 && !isNil && !isMax) {\r\n                addRow('Embedded timestamp', 'none \u2014 version 4 carries no time information');\r\n                addRow('Random bits', '122 bits');\r\n            }\r\n\r\n            body.innerHTML = rows;\r\n        },\r\n\r\n        \/* ================= Other formats tab ================= *\/\r\n        bindOther: function() {\r\n            var self = this;\r\n            var el;\r\n            el = document.getElementById('pth-other-btn');\r\n            if (el) { el.addEventListener('click', function() { self.runOther(); }); }\r\n            el = document.getElementById('pth-other-format');\r\n            if (el) {\r\n                el.addEventListener('change', function() {\r\n                    self.updateOtherNote();\r\n                    self.runOther();\r\n                });\r\n            }\r\n            el = document.getElementById('pth-other-copy');\r\n            if (el) {\r\n                el.addEventListener('click', function() {\r\n                    var o = document.getElementById('pth-other-output');\r\n                    self.copyText(o ? o.value : '', 'List');\r\n                });\r\n            }\r\n            el = document.getElementById('pth-other-download');\r\n            if (el) {\r\n                el.addEventListener('click', function() {\r\n                    var o = document.getElementById('pth-other-output');\r\n                    self.downloadText(o ? o.value : '', 'identifiers.txt');\r\n                });\r\n            }\r\n        },\r\n\r\n        updateOtherNote: function() {\r\n            var sel = document.getElementById('pth-other-format');\r\n            var note = document.getElementById('pth-other-note');\r\n            var lenWrap = document.getElementById('pth-nano-len-wrap');\r\n            if (!sel || !note) { return; }\r\n\r\n            var notes = {\r\n                ulid: '26 characters: a 48-bit millisecond timestamp followed by 80 random bits, in Crockford base32. Sorts by creation time as plain text.',\r\n                nanoid: 'A short URL-safe identifier. At the default 21 characters it offers a collision profile close to a UUID in far less space.',\r\n                objectid: \"MongoDB's 12-byte identifier: 4 bytes of Unix seconds, 5 random bytes, then a 3-byte counter.\",\r\n                snowflake: 'A 64-bit number that fits a bigint column: 41 timestamp bits, 10 machine bits and a 12-bit counter.',\r\n                cuid: 'A CUID2-shaped identifier built from browser randomness. Fine for local testing; use the official library in production.',\r\n                short: 'A standard v4 UUID encoded in base58, which shortens 36 characters to about 22 without losing any bits.'\r\n            };\r\n            note.innerHTML = notes[sel.value] || '';\r\n            if (lenWrap) { lenWrap.style.display = (sel.value === 'nanoid') ? 'flex' : 'none'; }\r\n        },\r\n\r\n        runOther: function() {\r\n            var sel = document.getElementById('pth-other-format');\r\n            var qtyEl = document.getElementById('pth-other-qty');\r\n            var lenEl = document.getElementById('pth-nano-len');\r\n            var outEl = document.getElementById('pth-other-output');\r\n            var countEl = document.getElementById('pth-other-count');\r\n            if (!sel || !qtyEl || !outEl) { return; }\r\n\r\n            var qty = parseInt(qtyEl.value, 10);\r\n            if (isNaN(qty) || qty < 1) { qty = 1; }\r\n            if (qty > 10000) { qty = 10000; qtyEl.value = 10000; this.toast('Capped at 10,000 per run'); }\r\n\r\n            var len = lenEl ? parseInt(lenEl.value, 10) : 21;\r\n            if (isNaN(len) || len < 6) { len = 6; }\r\n            if (len > 64) { len = 64; }\r\n\r\n            var kind = sel.value;\r\n            var list = [];\r\n            var i;\r\n            for (i = 0; i < qty; i++) {\r\n                if (kind === 'ulid') { list.push(this.ulid()); }\r\n                else if (kind === 'nanoid') { list.push(this.nanoid(len)); }\r\n                else if (kind === 'objectid') { list.push(this.objectId()); }\r\n                else if (kind === 'snowflake') { list.push(this.snowflake(i)); }\r\n                else if (kind === 'cuid') { list.push(this.cuid2()); }\r\n                else { list.push(this.shortUuid()); }\r\n            }\r\n            outEl.value = list.join('\\n');\r\n            if (countEl) { countEl.innerHTML = qty + ' generated'; }\r\n        },\r\n\r\n        \/* ================= Validate tab ================= *\/\r\n        bindValidate: function() {\r\n            var self = this;\r\n            var el;\r\n            el = document.getElementById('pth-val-input');\r\n            if (el) { el.addEventListener('input', function() { self.runValidate(); }); }\r\n            el = document.getElementById('pth-val-clear');\r\n            if (el) {\r\n                el.addEventListener('click', function() {\r\n                    var t = document.getElementById('pth-val-input');\r\n                    if (t) { t.value = ''; }\r\n                    self.runValidate();\r\n                });\r\n            }\r\n            el = document.getElementById('pth-convert-btn');\r\n            if (el) { el.addEventListener('click', function() { self.runConvert(); }); }\r\n            el = document.getElementById('pth-convert-copy');\r\n            if (el) {\r\n                el.addEventListener('click', function() {\r\n                    var o = document.getElementById('pth-convert-output');\r\n                    self.copyText(o ? o.value : '', 'Result');\r\n                });\r\n            }\r\n        },\r\n\r\n        collectValid: function() {\r\n            var inEl = document.getElementById('pth-val-input');\r\n            if (!inEl) { return { total: 0, valid: [], invalid: 0 }; }\r\n            var lines = inEl.value.split('\\n');\r\n            var valid = [];\r\n            var total = 0;\r\n            var invalid = 0;\r\n            var i, hex;\r\n            for (i = 0; i < lines.length; i++) {\r\n                if (lines[i].replace(\/\\s\/g, '') === '') { continue; }\r\n                total++;\r\n                hex = this.normaliseUuid(lines[i]);\r\n                if (hex) { valid.push(hex); } else { invalid++; }\r\n            }\r\n            return { total: total, valid: valid, invalid: invalid };\r\n        },\r\n\r\n        runValidate: function() {\r\n            var r = this.collectValid();\r\n            var t = document.getElementById('pth-val-total');\r\n            var g = document.getElementById('pth-val-good');\r\n            var b = document.getElementById('pth-val-bad');\r\n            if (t) { t.innerHTML = r.total; }\r\n            if (g) { g.innerHTML = r.valid.length; }\r\n            if (b) { b.innerHTML = r.invalid; }\r\n        },\r\n\r\n        runConvert: function() {\r\n            var r = this.collectValid();\r\n            var fmtEl = document.getElementById('pth-convert-format');\r\n            var outEl = document.getElementById('pth-convert-output');\r\n            if (!fmtEl || !outEl) { return; }\r\n\r\n            if (!r.valid.length) {\r\n                outEl.value = '';\r\n                this.toast('No valid UUIDs found in the list', true);\r\n                return;\r\n            }\r\n\r\n            var fmt = fmtEl.value;\r\n            var lines = [];\r\n            var i, j, hex, bytes;\r\n\r\n            for (i = 0; i < r.valid.length; i++) {\r\n                hex = r.valid[i];\r\n                bytes = [];\r\n                for (j = 0; j < 16; j++) { bytes.push(parseInt(hex.substring(j * 2, j * 2 + 2), 16)); }\r\n\r\n                if (fmt === 'plain') { lines.push(this.hexToCanonical(hex)); }\r\n                else if (fmt === 'hex') { lines.push(hex); }\r\n                else if (fmt === 'int') { lines.push(this.bytesToDecimal(bytes)); }\r\n                else if (fmt === 'base58') { lines.push(this.bytesToBase58(bytes)); }\r\n                else if (fmt === 'csv') { lines.push((i + 1) + ',' + this.hexToCanonical(hex) + ',' + ((bytes[6] >> 4) & 0x0F)); }\r\n                else { lines.push('  \"' + this.hexToCanonical(hex) + '\"'); }\r\n            }\r\n\r\n            if (fmt === 'csv') { lines.unshift('row,uuid,version'); }\r\n            if (fmt === 'json') { outEl.value = '[\\n' + lines.join(',\\n') + '\\n]'; }\r\n            else { outEl.value = lines.join('\\n'); }\r\n\r\n            this.toast(r.valid.length + ' identifiers converted');\r\n        },\r\n\r\n        \/* ================= Shared ================= *\/\r\n        loadSample: function() {\r\n            var tab = this.currentTab;\r\n            var el;\r\n            if (tab === 'gen') {\r\n                el = document.getElementById('pth-uuid-version');\r\n                if (el) { el.value = '7'; }\r\n                el = document.getElementById('pth-qty');\r\n                if (el) { el.value = '10'; }\r\n                this.runGenerate();\r\n            } else if (tab === 'inspect') {\r\n                el = document.getElementById('pth-inspect-input');\r\n                if (el) { el.value = this.uuidV7(); }\r\n                this.runInspect();\r\n            } else if (tab === 'other') {\r\n                el = document.getElementById('pth-other-format');\r\n                if (el) { el.value = 'ulid'; }\r\n                this.updateOtherNote();\r\n                this.runOther();\r\n            } else {\r\n                el = document.getElementById('pth-val-input');\r\n                if (el) {\r\n                    el.value = '550e8400-e29b-41d4-a716-446655440000\\n' +\r\n                        '{6ba7b810-9dad-11d1-80b4-00c04fd430c8}\\n' +\r\n                        '6ba7b8109dad11d180b400c04fd430c8\\n' +\r\n                        'definitely-not-a-uuid\\n' +\r\n                        '00000000-0000-0000-0000-000000000000';\r\n                }\r\n                this.runValidate();\r\n            }\r\n            this.toast('Sample loaded');\r\n        },\r\n\r\n        clearAll: function() {\r\n            var ids = ['pth-gen-output', 'pth-inspect-input', 'pth-other-output', 'pth-val-input', 'pth-convert-output'];\r\n            var i, el;\r\n            for (i = 0; i < ids.length; i++) {\r\n                el = document.getElementById(ids[i]);\r\n                if (el) { el.value = ''; }\r\n            }\r\n            el = document.getElementById('pth-gen-count');\r\n            if (el) { el.innerHTML = '0 generated'; }\r\n            el = document.getElementById('pth-other-count');\r\n            if (el) { el.innerHTML = '0 generated'; }\r\n            this.runInspect();\r\n            this.runValidate();\r\n            this.toast('All fields cleared');\r\n        }\r\n    };\r\n\r\n    \/* ================= 4-layer bootstrap ================= *\/\r\n    function pthIdRunInit() {\r\n        if (window.pthIdStudioApp.initialized) { return; }\r\n        if (!document.getElementById('pth-id-studio-wrapper')) { return; }\r\n        window.pthIdStudioApp.initialized = true;\r\n        try {\r\n            window.pthIdStudioApp.init();\r\n        } catch (err) {\r\n            window.pthIdStudioApp.initialized = false;\r\n        }\r\n    }\r\n\r\n    pthIdRunInit();\r\n\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', pthIdRunInit);\r\n    }\r\n\r\n    window.addEventListener('load', function() {\r\n        setTimeout(pthIdRunInit, 50);\r\n    });\r\n\r\n    if (typeof MutationObserver !== 'undefined') {\r\n        var pthIdObserver = new MutationObserver(function() {\r\n            if (document.getElementById('pth-id-studio-wrapper')) { pthIdRunInit(); }\r\n        });\r\n        if (document.body) {\r\n            pthIdObserver.observe(document.body, { childList: true, subtree: true });\r\n            setTimeout(function() { pthIdObserver.disconnect(); }, 10000);\r\n        }\r\n    }\r\n})();\r\n<\/script>\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 Generation<\/div>\n        <p class=\"pth-feat-text\">Calculates mathematically secure random numbers to generate Version 4 identifiers with practically zero collision probability.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udd35 Regular Expression Validation<\/div>\n        <p class=\"pth-feat-text\">Executes complex regex parsing to instantly authenticate strings containing hyphens, braces, and standard hexadecimal formatting.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udfe3 High-Volume Processing<\/div>\n        <p class=\"pth-feat-text\">Capable of calculating and formatting up to 10,000 unique 128-bit strings locally within a single execution cycle.<\/p>\n    <\/div>\n<\/div>\n<div class=\"pth-steps-wrap\">\n    <div class=\"pth-steps-title\">How to Use the GUID Generator &#038; Validator<\/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\">Select Operation<\/div>\n            <p class=\"pth-step-desc\">Choose between calculating new 128-bit identifiers or authenticating an existing list of hexadecimal strings.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">2<\/div>\n            <div class=\"pth-step-name\">Configure Syntax<\/div>\n            <p class=\"pth-step-desc\">Determine the exact output formatting by toggling hyphens, uppercase lettering, or surrounding braces.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">3<\/div>\n            <div class=\"pth-step-name\">Execute Engine<\/div>\n            <p class=\"pth-step-desc\">Specify your desired array length up to 10,000 items and trigger the local cryptographic number generator.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">4<\/div>\n            <div class=\"pth-step-name\">Extract or Authenticate<\/div>\n            <p class=\"pth-step-desc\">Download the generated array as a raw text file, or review the parsed results table to identify invalid strings.<\/p>\n        <\/div>\n    <\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Last Updated: August 2026<\/strong><\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-what-changed-and-why\" class=\"wp-block-heading\">\ud83d\udd34 What Changed and Why<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This page used to be a version 4 uuid generator with a validator attached. That covers the common case, but it left out the question people actually arrive with:&nbsp;<em>which<\/em>&nbsp;kind of identifier should I be using here? So the page now generates seven UUID variants plus five other identifier schemes, and it can pull a UUID apart to show you what is inside it.<\/p>\n\n\n\n<h3 id=\"generate-pick-the-version-that-fits-the-job\" class=\"wp-block-heading\">Generate \u2014 pick the version that fits the job<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Version 4 stays the default because it is the right answer most of the time: 122 random bits, no structure, nothing leaked. Version 7 is the one worth knowing about if you are choosing a database primary key, and the reason is worth spelling out.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A v4 UUID is random from the first character. Insert a million of them into an indexed column and each row lands at an unpredictable point in the B-tree, so the database keeps splitting pages and the index grows far larger than the data warrants. A v7 UUID starts with a 48-bit millisecond timestamp, so newly created rows sort to the end and append cleanly. Same uniqueness guarantee, very different write behaviour.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Generate ten of each and the difference is visible immediately. Ten v4 values look like noise. Ten v7 values share a common prefix that ticks upward:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>019f75da-1b74-7000-a186-9d6b5d28ef0c<\/code><br><code>019f75da-1b74-7001-b2c4-3f8a1e5d7b90<\/code><br><code>019f75da-1b74-7002-8e13-6a2f9c4d1e58<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note the fourth group climbing 7000, 7001, 7002. That is a monotonic counter, not an accident. When several identifiers are created inside the same millisecond the timestamp alone cannot separate them, so the counter keeps the sort order intact. Generate all ten thousand at once and they still come out in order.<\/p>\n\n\n\n<h3 id=\"inspector-read-what-is-inside-an-identifier\" class=\"wp-block-heading\">Inspector \u2014 read what is inside an identifier<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Paste any UUID and the panel reports its version, its variant, the raw hex, the full 128-bit integer, and a base58 short form. For versions 1, 6 and 7 it also decodes the embedded timestamp into a readable date.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That last row answers a question that comes up more often than you would expect:&nbsp;<em>when was this record actually created?<\/em>&nbsp;If the ID is a v7 and the created_at column is missing or untrustworthy, the answer is sitting inside the key itself, accurate to the millisecond.<\/p>\n\n\n\n<h3 id=\"other-formats-five-schemes-that-are-not-uui-ds\" class=\"wp-block-heading\">Other Formats \u2014 five schemes that are not UUIDs<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udd35&nbsp;<strong>ULID<\/strong>&nbsp;\u2014 26 characters, timestamp first, sorts as plain text. Its alphabet drops I, L, O and U, so a generated value cannot accidentally spell something unfortunate and cannot be misread over the phone.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udfe0&nbsp;<strong>NanoID<\/strong>&nbsp;\u2014 21 URL-safe characters by default, adjustable from 6 to 64. Shorter than a UUID with a similar collision profile, which is why it turns up in URLs and share links.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udfe3&nbsp;<strong>MongoDB ObjectID<\/strong>&nbsp;\u2014 24 hex characters: four bytes of Unix seconds, five random bytes, then a three-byte counter.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udd35&nbsp;<strong>Snowflake<\/strong>&nbsp;\u2014 a 64-bit number that fits a bigint column, which a 128-bit UUID does not.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udfe0&nbsp;<strong>Short UUID<\/strong>&nbsp;\u2014 an ordinary v4 encoded in base58, trimming 36 characters to roughly 22 without discarding a single bit.<\/p>\n\n\n\n<h3 id=\"validate-convert-bulk-work\" class=\"wp-block-heading\">Validate &amp; Convert \u2014 bulk work<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Paste a list and it counts valid against invalid, accepting hyphenated, bare hex, braced and quoted forms. Then convert the valid ones to canonical form, raw hex, a 128-bit decimal integer, base58, CSV rows or a JSON array.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe1-where-people-get-this-wrong\" class=\"wp-block-heading\">\ud83d\udfe1 Where People Get This Wrong<\/h2>\n\n\n\n<h3 id=\"a-uuid-is-not-a-secret\" class=\"wp-block-heading\">A UUID is not a secret<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This is the mistake with real consequences. A v4 UUID is unguessable, which tempts people into using one as a password reset token or an API key. It is the wrong tool. It has no expiry, no revocation, no rate limiting, and it frequently ends up in server logs, browser history and referrer headers. For anything that grants access, use the&nbsp;<a href=\"https:\/\/schoolict.net\/tools\/free-strong-password-generator\/\">Strong Password Generator<\/a>&nbsp;or a purpose-built token scheme.<\/p>\n\n\n\n<h3 id=\"time-based-versions-reveal-their-creation-time\" class=\"wp-block-heading\">Time-based versions reveal their creation time<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">v1, v6 and v7 all carry a timestamp that anyone can read \u2014 the Inspector tab proves it in one paste. Usually harmless. Occasionally not: a public v7 identifier tells the world exactly when the account, order or document behind it was created, and sequential v7 keys in a URL make it trivial to estimate how many records exist. If either matters, v4 is the version to pick.<\/p>\n\n\n\n<h3 id=\"storing-uui-ds-as-text\" class=\"wp-block-heading\">Storing UUIDs as text<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A UUID stored as a 36-character string takes 36 bytes. The same value as binary takes 16. Across millions of rows that difference lands squarely on index size and query speed. Most databases have a native type for this \u2014 use it rather than a VARCHAR.<\/p>\n\n\n\n<h3 id=\"what-this-page-does-not-do\" class=\"wp-block-heading\">What this page does not do<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udd35&nbsp;<strong>Versions 3 and 5<\/strong>&nbsp;are absent on purpose. They derive a UUID by hashing a name inside a namespace, which needs MD5 or SHA-1, and hashing has its own page here rather than being duplicated inside this one. See the&nbsp;<a href=\"https:\/\/schoolict.net\/tools\/free-secure-hash-generator\/\">Secure Hash Generator<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udfe0&nbsp;<strong>Real MAC addresses<\/strong>&nbsp;in v1 and v6 are impossible from a browser, which cannot read network hardware. The node field is filled with random bits and the multicast flag is set \u2014 exactly what the specification instructs implementations to do when no hardware address is available. The Inspector labels which of the two it found.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udfe3&nbsp;<strong>The CUID2 option<\/strong>&nbsp;produces a correctly shaped identifier from browser randomness, not the reference algorithm. It is good for seeding test data; for production, install the official library.<\/p>\n\n\n\n<h3 id=\"honest-limits\" class=\"wp-block-heading\">Honest limits<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Generation is capped at 10,000 per run. It is a soft ceiling \u2014 the browser copes, but a textarea holding a hundred thousand lines becomes unpleasant to scroll on any device. For a larger batch, run it a few times and save each file. The v7 monotonic counter allows 4,096 values per millisecond; beyond that the timestamp rolls forward by one millisecond, so ordering holds either way.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe2-the-reasoning-behind-it\" class=\"wp-block-heading\">\ud83d\udfe2 The Reasoning Behind It<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For the deeper background \u2014 how 128 bits produces a practical collision probability of zero, what the birthday problem actually says about it, and why the original MAC-address design became a privacy problem \u2014 there is a companion article:&nbsp;<a href=\"https:\/\/schoolict.net\/tools\/free-offline-uuid-guid-generator-validatorarticle\/\">UUID and GUID explained: versions, collisions and safe use<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The current specification is&nbsp;<a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9562.html\" rel=\"noreferrer noopener\" target=\"_blank\">IETF RFC 9562<\/a>, published in 2024, which replaced RFC 4122 and introduced versions 6, 7 and 8. Browsers also ship a built-in v4 generator documented at&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Crypto\/randomUUID\" rel=\"noreferrer noopener\" target=\"_blank\">MDN&#8217;s crypto.randomUUID reference<\/a>.<\/p>\n\n\n\n\n<style>\n.pth-faq-wrap { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin: 24px 0; }\n.pth-faq-card { background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); }\n.pth-faq-q { font-size: 15px; font-weight: 800; color: #0f172a; margin: 0 0 8px 0; line-height: 1.45; }\n.pth-faq-a { font-size: 14px; color: #475569; margin: 0; line-height: 1.65; font-weight: 500; }\n@media (max-width: 992px) { .pth-faq-wrap { grid-template-columns: repeat(2, 1fr); } }\n@media (max-width: 640px) { .pth-faq-wrap { grid-template-columns: 1fr; } }\n<\/style>\n \n<h2>\u2753 Frequently Asked Questions<\/h2>\n \n<div class=\"pth-faq-wrap\">\n \n  <div class=\"pth-faq-card\">\n    <p class=\"pth-faq-q\">Are these UUIDs generated on your server?<\/p>\n    <p class=\"pth-faq-a\">No. Every value comes from your browser&#8217;s own cryptographic random source. Nothing is sent anywhere, and no record of what you generated exists outside your tab.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n    <p class=\"pth-faq-q\">Should I use v4 or v7?<\/p>\n    <p class=\"pth-faq-a\">v7 for database primary keys, because it sorts by creation time and keeps the index tidy. v4 anywhere the identifier is public and you would rather not reveal when it was made.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n    <p class=\"pth-faq-q\">Can two UUIDs ever be the same?<\/p>\n    <p class=\"pth-faq-a\">In principle yes, in practice no. You would need to generate around 2.7 quintillion v4 values before a collision reached a one-in-a-billion chance.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n    <p class=\"pth-faq-q\">Is a UUID safe to use as an API key?<\/p>\n    <p class=\"pth-faq-a\">No. It is unguessable but it never expires, cannot be revoked cleanly and leaks into logs and referrer headers. Use a token scheme designed for authentication.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n    <p class=\"pth-faq-q\">Why does the tool not offer v3 or v5?<\/p>\n    <p class=\"pth-faq-a\">Both are name-based and require MD5 or SHA-1. Hashing lives in its own tool on this site rather than being repeated here.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n    <p class=\"pth-faq-q\">What is the difference between a UUID and a GUID?<\/p>\n    <p class=\"pth-faq-a\">Nothing structural. GUID is Microsoft&#8217;s name for the same 128-bit value, which is why you often see it wrapped in braces in Windows tooling.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n    <p class=\"pth-faq-q\">Why do my v1 UUIDs not contain my MAC address?<\/p>\n    <p class=\"pth-faq-a\">Browsers cannot read network hardware. The node field uses random bits with the multicast flag set, which is what the specification requires when no hardware address is available.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n    <p class=\"pth-faq-q\">What is ULID good for?<\/p>\n    <p class=\"pth-faq-a\">Cases where you want v7&#8217;s time ordering but shorter, case-insensitive text. Its 26-character base32 form is easier to read aloud and to type by hand.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n    <p class=\"pth-faq-q\">Does the 10,000 limit mean bigger batches are unsafe?<\/p>\n    <p class=\"pth-faq-a\">Not at all \u2014 it is a usability cap. Uniqueness and ordering hold at any size; a textarea with a hundred thousand lines simply becomes awkward to use.<\/p>\n  <\/div>\n \n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Fast and Developer ready GUID Generator &amp; Validator Use our offline GUID Generator &amp; Validator to create cryptographically secure Version 4 UUIDs. Validate up to 10,000 identifiers locally with zero server uploads. \ud83d\udfe2 Cryptographic Generation Calculates mathematically secure random numbers to generate Version 4 identifiers with practically zero collision probability. \ud83d\udd35 Regular Expression Validation Executes &#8230; <a title=\"GUID Generator &amp; Validator\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/uuid-guid-generator-validator\/\" aria-label=\"Read more about GUID Generator &amp; Validator\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":843,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-841","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/841","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=841"}],"version-history":[{"count":3,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/841\/revisions"}],"predecessor-version":[{"id":6958,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/841\/revisions\/6958"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/843"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=841"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}