{"claude_md":"# Regex Playground\n\nInteractive regex tester with live match highlighting, named group extraction, and a library of common patterns. Pre-loaded with email, URL, UUID, and date patterns.\n\n## Quick Reference\n\n# Regex Playground\n\n> **Purpose:** A live, interactive regular expression tester. Type a pattern on the left and watch matches highlight in the test string in real time. Includes named group extraction, match count, a library of common presets, and flag toggles (g, i, m, s).\n\n---\n\n## How to Use\n\n1. **Type a pattern** in the `/pattern/` input at the top\n2. **Toggle flags** — `g` (global), `i` (case-insensitive), `m` (multiline), `s` (dotAll)\n3. **Edit the test string** — paste any text to test against\n4. **Click a preset** in the right panel to load a common pattern instantly\n\n---\n\n## Preset Patterns Included\n\n| Preset | Pattern matches |\n|--------|----------------|\n| Email | Standard email addresses |\n| URL | HTTP and HTTPS URLs |\n| UUID | RFC 4122 UUIDs |\n| Hex Color | CSS hex colors (#fff, #7c3aed) |\n| ISO Date | YYYY-MM-DD date strings |\n| IP Address | IPv4 addresses |\n| Phone (US) | US phone numbers with country code |\n| Markdown Link | `[text](url)` link syntax |\n\n---\n\n## Reading Results\n\n- **Purple highlight** — a match in the test string\n- **Brighter purple** — the first match\n- **Match list** — shows each match text and its character index\n- Named capture groups are shown in the match list as `groups: {name: value}`\n\n---\n\n## Common Flags\n\n| Flag | Meaning |\n|------|---------|\n| `g` | Global — find all matches, not just the first |\n| `i` | Case-insensitive match |\n| `m` | Multiline — `^` and `$` match line boundaries |\n| `s` | Dotall — `.` matches newlines |\n\n\n## Agent Docs (read when relevant)\n\n| File | When to read |\n|------|-------------|\n| `agent_docs/regex-playground.html` | regex playground |\n","agent_docs":{"agent_docs/regex-playground.html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Regex Playground</title>\n<style>\n* { box-sizing: border-box; margin: 0; padding: 0; }\nbody { background: #0a0a14; color: #e2e8f0; font-family: system-ui, sans-serif; height: 100vh; display: flex; flex-direction: column; }\nheader { background: #1a1a2e; border-bottom: 1px solid #2d2d4e; padding: 11px 20px; flex-shrink: 0; }\nh1 { font-size: 15px; color: #a78bfa; font-weight: 700; }\n.layout { display: flex; flex: 1; overflow: hidden; }\n.left { flex: 1; display: flex; flex-direction: column; padding: 18px; gap: 14px; overflow-y: auto; }\n.right { width: 210px; background: #0d0d1c; border-left: 1px solid #1e1e3a; padding: 14px; overflow-y: auto; flex-shrink: 0; }\n.label { font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: #4b5563; margin-bottom: 6px; display: block; }\n.pat-row { display: flex; align-items: center; background: #12121e; border: 1px solid #2d2d4e; border-radius: 8px; overflow: hidden; }\n.sl { color: #4b5563; padding: 0 8px; font-size: 20px; font-family: monospace; }\n#pat { flex: 1; background: transparent; border: none; outline: none; font-family: monospace; font-size: 16px; color: #c4b5fd; padding: 10px 0; }\n.flags { display: flex; gap: 4px; padding: 8px; border-left: 1px solid #2d2d4e; }\n.flag { padding: 4px 8px; border-radius: 4px; cursor: pointer; font-family: monospace; font-size: 12px; font-weight: 800; background: #1e1e3a; color: #4b5563; border: 1px solid transparent; user-select: none; transition: all 0.1s; }\n.flag.on { background: #2d1b69; color: #c4b5fd; border-color: #6d28d9; }\n.test-wrap { position: relative; }\n#hl { position: absolute; inset: 0; padding: 11px 12px; font-family: monospace; font-size: 13px; line-height: 1.65; pointer-events: none; border-radius: 8px; white-space: pre-wrap; word-wrap: break-word; color: transparent; overflow: hidden; }\nmark { background: rgba(109,40,217,0.45); color: transparent; border-radius: 2px; }\nmark.first { background: rgba(109,40,217,0.8); }\n#tstr { width: 100%; min-height: 150px; background: #12121e; border: 1px solid #2d2d4e; border-radius: 8px; padding: 11px 12px; font-family: monospace; font-size: 13px; color: #e2e8f0; resize: vertical; outline: none; line-height: 1.65; }\n#tstr:focus { border-color: #4c1d95; }\n.status { display: flex; align-items: center; gap: 14px; min-height: 20px; }\n.count { font-size: 13px; font-weight: 700; }\n.found { color: #6ee7b7; }\n.none  { color: #f87171; }\n.err   { color: #fcd34d; font-size: 12px; }\n.mlist { background: #12121e; border: 1px solid #1e1e3a; border-radius: 8px; padding: 10px 12px; font-family: monospace; font-size: 11px; max-height: 130px; overflow-y: auto; }\n.mi { color: #a78bfa; padding: 3px 0; border-bottom: 1px solid #1a1a2e; }\n.right-lbl { font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: #4b5563; margin-bottom: 10px; }\n.preset { padding: 7px 9px; border-radius: 6px; cursor: pointer; margin-bottom: 5px; border: 1px solid #1e1e3a; transition: background 0.1s; }\n.preset:hover { background: #1a1a2e; }\n.pname { font-size: 12px; font-weight: 600; color: #94a3b8; margin-bottom: 2px; }\n.ppat  { font-family: monospace; font-size: 9px; color: #4b5563; word-break: break-all; }\n</style>\n</head>\n<body>\n<header><h1>&#10033; Regex Playground</h1></header>\n<div class=\"layout\">\n<div class=\"left\">\n  <div>\n    <span class=\"label\">Pattern</span>\n    <div class=\"pat-row\">\n      <span class=\"sl\">/</span>\n      <input id=\"pat\" placeholder=\"enter a regex...\" oninput=\"upd()\">\n      <span class=\"sl\">/</span>\n      <div class=\"flags\">\n        <span class=\"flag on\" data-f=\"g\" onclick=\"togFlag(this)\">g</span>\n        <span class=\"flag\" data-f=\"i\" onclick=\"togFlag(this)\">i</span>\n        <span class=\"flag\" data-f=\"m\" onclick=\"togFlag(this)\">m</span>\n        <span class=\"flag\" data-f=\"s\" onclick=\"togFlag(this)\">s</span>\n      </div>\n    </div>\n  </div>\n  <div class=\"test-wrap\">\n    <span class=\"label\">Test String</span>\n    <div id=\"hl\"></div>\n    <textarea id=\"tstr\" oninput=\"upd()\" spellcheck=\"false\">Contact us at hello@example.com or support@skillslap.com\nVisit https://skillslap.com or https://dev.skillslap.com\nUser ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890\nColor: #7c3aed or #fff or #a1b2c3\nDate: 2026-02-20 | IP: 192.168.1.100\nPhone: +1 (555) 123-4567</textarea>\n  </div>\n  <div class=\"status\">\n    <span id=\"cnt\" class=\"count\"></span>\n    <span id=\"errmsg\" class=\"err\"></span>\n  </div>\n  <div>\n    <span class=\"label\">Matches</span>\n    <div id=\"mlist\" class=\"mlist\"><span style=\"color:#2d2d4e\">No pattern entered</span></div>\n  </div>\n</div>\n<div class=\"right\">\n  <div class=\"right-lbl\">Presets</div>\n  <div id=\"presets\"></div>\n</div>\n</div>\n<script>\nvar P = [\n  {n:'Email',   p:'[a-zA-Z0-9._%+\\\\-]+@[a-zA-Z0-9.\\\\-]+\\\\.[a-zA-Z]{2,}', f:'gi'},\n  {n:'URL',     p:'https?:\\\\/\\\\/[\\\\w\\\\-]+(\\\\.[\\\\w\\\\-]+)+(\\\\/[^\\\\s]*)?', f:'gi'},\n  {n:'UUID',    p:'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', f:'gi'},\n  {n:'Hex Color',  p:'#[0-9a-fA-F]{6}\\\\b|#[0-9a-fA-F]{3}\\\\b', f:'g'},\n  {n:'ISO Date',   p:'\\\\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\\\d|3[01])', f:'g'},\n  {n:'IP Address', p:'\\\\b(?:\\\\d{1,3}\\\\.){3}\\\\d{1,3}\\\\b', f:'g'},\n  {n:'Phone (US)', p:'(?:\\\\+1\\\\s?)?\\\\(?\\\\d{3}\\\\)?[\\\\s.\\\\-]?\\\\d{3}[\\\\s.\\\\-]?\\\\d{4}', f:'g'},\n  {n:'Markdown Link', p:'\\\\[([^\\\\]]+)\\\\]\\\\(([^)]+)\\\\)', f:'g'},\n];\n\nfunction esc(s){ return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }\nfunction flags(){ return Array.from(document.querySelectorAll('.flag.on')).map(function(f){return f.dataset.f;}).join(''); }\nfunction setFlags(f){ document.querySelectorAll('.flag').forEach(function(el){ el.classList.toggle('on', f.indexOf(el.dataset.f)>=0); }); }\nfunction togFlag(el){ el.classList.toggle('on'); upd(); }\n\nfunction renderPresets(){\n  document.getElementById('presets').innerHTML = P.map(function(p,i){\n    return '<div class=\"preset\" onclick=\"applyP('+i+')\">'\n      +'<div class=\"pname\">'+p.n+'</div>'\n      +'<div class=\"ppat\">/'+p.p.slice(0,25)+(p.p.length>25?'...':'')+'/'+p.f+'</div></div>';\n  }).join('');\n}\n\nfunction applyP(i){\n  document.getElementById('pat').value = P[i].p;\n  setFlags(P[i].f);\n  upd();\n}\n\nfunction upd(){\n  var patStr = document.getElementById('pat').value;\n  var testStr = document.getElementById('tstr').value;\n  var fl = flags();\n  var cntEl = document.getElementById('cnt');\n  var errEl = document.getElementById('errmsg');\n  var hl = document.getElementById('hl');\n  var ml = document.getElementById('mlist');\n\n  if(!patStr){\n    hl.innerHTML = esc(testStr);\n    cntEl.textContent=''; errEl.textContent='';\n    ml.innerHTML = '<span style=\"color:#2d2d4e\">No pattern entered</span>';\n    return;\n  }\n\n  var re;\n  try { re = new RegExp(patStr, fl); errEl.textContent=''; }\n  catch(e){ errEl.textContent = e.message; cntEl.textContent=''; hl.innerHTML=esc(testStr); ml.innerHTML=''; return; }\n\n  var matches = [];\n  var gfl = fl.indexOf('g')>=0 ? fl : fl+'g';\n  var gr = new RegExp(patStr, gfl);\n  var m;\n  while((m = gr.exec(testStr)) !== null){\n    matches.push({idx:m.index, txt:m[0], grps:m.groups});\n    if(!fl.indexOf('g')>=0) break;\n  }\n\n  var res='', last=0;\n  matches.forEach(function(m,i){\n    res += esc(testStr.slice(last, m.idx));\n    res += '<mark class=\"'+(i===0?'first':'')+'\">' + esc(m.txt) + '</mark>';\n    last = m.idx + m.txt.length;\n  });\n  res += esc(testStr.slice(last));\n  hl.innerHTML = res;\n\n  cntEl.className = 'count '+(matches.length>0?'found':'none');\n  cntEl.textContent = matches.length + (matches.length===1?' match':' matches');\n\n  if(matches.length===0){\n    ml.innerHTML='<span style=\"color:#2d2d4e\">No matches found</span>';\n  } else {\n    ml.innerHTML = matches.slice(0,20).map(function(m,i){\n      return '<div class=\"mi\">['+i+'] \"'+esc(m.txt)+'\" at '+m.idx+(m.grps?' groups:'+JSON.stringify(m.grps):'')+' </div>';\n    }).join('') + (matches.length>20?'<div style=\"color:#2d2d4e\">...and '+(matches.length-20)+' more</div>':'');\n  }\n}\n\ndocument.getElementById('tstr').addEventListener('scroll', function(){\n  document.getElementById('hl').scrollTop = this.scrollTop;\n});\n\nrenderPresets();\napplyP(0);\n</script>\n</body>\n</html>"}}