AA

Welcome to MS SQL Server Simulator

A free, browser-based SSMS-inspired enterprise workbench
v10 ENTERPRISE EDITION

Built by Adewale Samson Adeagbo

Adewale Samson Adeagbo — a Lagos-based educator turned data scientist who built this entire application on an Android tablet to give learners worldwide a real SSMS experience without the install, the licence, or the cost.

Data Scientist EdTech Builder Virtual Tutor AI-Augmented Developer DataTech Builder FaithTech Builder

15+ years teaching in Nigerian classrooms · Founder of HMG Concepts (est. 2015) · 3MTT Nigeria · WorldQuant University · 12 deployed ML/EdTech projects · This app is one of them.

"I did not wait to become a developer. I used clear thinking and AI leverage to build the tools my students needed."

MS SQL Server Simulator v10 ENTERPRISE
Initialising SQLite WebAssembly engine…
by Adewale Samson Adeagbo · HMG Concepts · 2026
Data Scientist · EdTech Builder · AI-Augmented Solutions Developer
Built on an Android tablet in Lagos, Nigeria · MIT Licence
'; mime = 'text/html'; ext = 'html'; } else if (fmt === 'md') { content = withBuilderAttribution('| ' + columns.join(' | ') + ' |\n|' + columns.map(() => '---').join('|') + '|\n' + values.map(r => '| ' + r.map(c => c == null ? '' : String(c)).join(' | ') + ' |').join('\n'), 'md'); mime = 'text/markdown'; ext = 'md'; } else if (fmt === 'sql') { const m = editor().value.match(/from\s+(\w+)/i); const tname = m ? m[1] : 'results'; content = withBuilderAttribution(values.map(r => 'INSERT INTO '+tname+' ('+columns.join(',')+') VALUES ('+r.map(c => c == null ? 'NULL' : typeof c === 'number' ? c : "'" + String(c).replace(/'/g, "''") + "'").join(',')+');').join('\n'), 'sql'); mime = 'text/sql'; ext = 'sql'; } const blob = new Blob([content], { type: mime }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'results_' + Date.now() + '.' + ext; a.click(); if (typeof closeModal === 'function') closeModal('export-modal'); toast('Exported as '+ext.toUpperCase()+' (with builder attribution)', 'success'); }; const _origExportSchemaDDL = exportSchemaDDL; window.exportSchemaDDL = function () { try { const r = db.exec("SELECT name,sql FROM sqlite_master WHERE type='table' AND name NOT LIKE '\\_%' ESCAPE '\\\\' ORDER BY name"); if (!r.length) { toast('No tables', 'warn'); return; } let ddl = ''; r[0].values.forEach(row => { ddl += '-- Table: ' + row[0] + '\n' + row[1] + ';\n\n'; }); ddl = withBuilderAttribution(ddl, 'sql'); const blob = new Blob([ddl], { type: 'text/sql' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'schema_ddl.sql'; a.click(); toast('Schema exported (with builder attribution)', 'success'); } catch (e) { toast(e.message, 'error'); } }; const _origRenderOE = renderObjectExplorer; window.renderObjectExplorer = function () { _origRenderOE(); const tree = document.getElementById('oe-tree'); if (!tree) return; const extra = document.createElement('div'); extra.innerHTML = '
·👤Builder: Adewale Adeagbo
' + '
·Programmability('+storedObjects.length+')
' + '
·🔒Security & Logins('+logins.length+')
' + '
·🔁Always On (Visual)
' + '
·📊Activity Monitor
'; tree.appendChild(extra); }; /* ═══════════════════════════════════════════════════════════════════════════ MODAL RENDERERS (Builder, Activity, Profiler, Query Store, etc.) ═══════════════════════════════════════════════════════════════════════════ */ function renderBuilderModal() { const b = document.getElementById('builder-body'); if (!b) return; b.innerHTML = '
' + '
AA
' + '

Adewale Samson Adeagbo

' + '
Data Scientist · EdTech Builder · Virtual Tutor · AI-Augmented Solutions Developer · DataTech Builder · FaithTech Builder
' + '
Builder of MS SQL Server Simulator v10
' + '
' + '

🇳🇬 The Story

' + '

15+ years standing in Nigerian classrooms — Nursery, Primary, JSS, SSS — teaching Mathematics, Further Mathematics, Physics, Chemistry, and Computer Science across His Marvellous Grace, Fredaks, Anchor Heights, Dave Model School, Lifeline, De Glorious College, Chrisville, Angel High School, God of Seed Academy, and more.

' + '

In 2023, completed a B.Sc(Ed) Computer Science Education at Lagos State University. In 2025, the breakthrough through 3MTT (3 Million Technical Talent) Nigeria unlocked data science capability.

' + '

"I did not wait to become a developer. I used clear thinking and AI leverage to build the tools my students needed."

' + '

🏛 HMG Concepts — Founded 2015

' + '
' + '
HMG Academy
Virtual learning institution
Nursery → SSS3 · WAEC · NECO · JAMB · IGCSE · IELTS · JUPEB · SAT
' + '
HMG Technologies
EdTech & data solutions
CBT Pro · MS SQL Server Simulator · ML tools
' + '
HMG Media
Content & community
YouTube, social media, articles
' + '
' + '

📚 Currently Enrolled

' + '' + '

🛠 Skills

' + '

Data / ML: Python · Pandas · NumPy · scikit-learn · XGBoost · Gradient Boosting · Random Forest · SHAP · SMOTE · TF-IDF · VADER · Streamlit · Joblib
' + 'BI / Analytics: SQL · Power BI · Tableau · Excel (Adv) · Google Sheets · EDA · Statistics
' + 'Web / EdTech: HTML5 · CSS3 · Vanilla JS · Supabase (PostgreSQL + RLS) · GitHub Pages · Cloudflare Pages · Acode (mobile IDE)
' + 'Tools: Git · GitHub · Jupyter · Google Colab · VS Code · Formspree

' + '

🚀 12 Live Projects

' + '
    ' + '
  1. MS SQL Server Simulator v10 (this app)
  2. ' + '
  3. QueryForge v8 — original engine
  4. ' + '
  5. CBT Pro — browser CBT platform with anti-cheat, live in Nigerian schools
  6. ' + '
  7. Insurance Claim Prediction — Random Forest · SHAP · ROC-AUC 0.6144
  8. ' + '
  9. Staff Promotion Prediction (Yakub Trading Group) — Random Forest · ROC-AUC 0.891
  10. ' + '
  11. Bank Customer Churn — Gradient Boosting · ROC-AUC 0.8675 · F1 0.6091
  12. ' + '
  13. Income Level Prediction (US Census) — Random Forest · SMOTE
  14. ' + '
  15. TruthLens Fake News Detector (3MTT Capstone) — XGBoost · TF-IDF · Acc 86.75%
  16. ' + '
  17. SwiftChain Delivery Prediction — Gradient Boosting multiclass
  18. ' + '
  19. NeuroWell Burnout Predictor — Gradient Boosting · R² 0.855 · RMSE 0.072
  20. ' + '
  21. HMG Academy site — full virtual school
  22. ' + '
  23. HMG Concepts site — brand homepage
  24. ' + '
' + '

📡 Reach Out

' + '' + '

'+BUILDER.tagline+' · MIT Licence · © 2026

'; } let amInterval = null; function renderActivityMonitor() { const b = document.getElementById('activitymonitor-body'); if (!b) return; const recent = perfLog.slice(-20); const avgMs = recent.length ? Math.round(recent.reduce((a, x) => a + x.ms, 0) / recent.length) : 0; const totalQueries = perfLog.length; const totalRows = perfLog.reduce((a, x) => a + (x.rows || 0), 0); const errors = traceEvents.filter(e => !e.success).length; const uptime = Math.round((Date.now() - dbStartTime) / 1000); const upH = Math.floor(uptime / 3600), upM = Math.floor((uptime % 3600) / 60), upS = uptime % 60; let tableCount = 0; try { const r = db.exec("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name NOT LIKE '\\_%' ESCAPE '\\\\'"); tableCount = r.length ? r[0].values[0][0] : 0; } catch(e){} const maxMs = Math.max(1, ...perfLog.slice(-30).map(p => p.ms)); const sparks = perfLog.slice(-30).map(p => '
').join(''); let recentRows = perfLog.slice(-10).reverse().map(p => ''+new Date(p.t).toTimeString().slice(0,8)+'SQL'+esc(p.sql.slice(0,100))+''+p.ms+'ms'+(p.rows||0)+'').join(''); if (!recentRows) recentRows = 'No queries executed yet.'; b.innerHTML = '
Overview· Auto-refresh every 2 secondsServer: localhost\\SQLEXPRESS · User: adewale · DB: master
' + '
' + '
Total Queries
'+totalQueries+'
since session start
'+(sparks||'
No data yet
')+'
' + '
Avg Query Time
'+avgMs+'ms
last '+recent.length+' queries
' + '
Total Rows Returned
'+totalRows.toLocaleString()+'
across all queries
' + '
Failed Queries
'+errors+'
'+(errors===0?'no errors':'check Profiler')+'
' + '
Database Uptime
'+String(upH).padStart(2,'0')+':'+String(upM).padStart(2,'0')+':'+String(upS).padStart(2,'0')+'
hh:mm:ss this session
' + '
Tables in master
'+tableCount+'
user tables
' + '
Active Connections
1
adewale@localhost
' + '
SQL Engine
SQLite WASM
v1.10.2 (SQLite 3.43)
' + '
' + '
Top 10 Recent Queries
' + ''+recentRows+'
TimeEventSQL (first 100 chars)DurationRows
' + '
Activity Monitor · MS SQL Server Simulator v10 by Adewale Samson Adeagbo · cssadewale.pages.dev
'; if (amInterval) clearInterval(amInterval); amInterval = setInterval(() => { const m = document.getElementById('activitymonitor-modal'); if (m && m.classList.contains('show')) renderActivityMonitor(); else { clearInterval(amInterval); amInterval = null; } }, 2000); } function renderProfiler() { const b = document.getElementById('profiler-body'); if (!b) return; const rows = traceEvents.slice(0,100).map(e => ''+e.t.toTimeString().slice(0,8)+'.'+String(e.t.getMilliseconds()).padStart(3,'0')+''+e.spid+''+e.event.replace('SQL:','')+''+esc(e.sql)+''+e.ms+'ms'+e.rows+''+esc(e.user)+''+esc(e.db)+'').join(''); b.innerHTML = '
' + '' + '' + '' + ''+traceEvents.length+' events captured · max 500' + '
' + ''+(rows||'')+'
TimeSPIDEventSQLDurationRowsUserDB
No trace events. Run a query to capture.
' + '
SQL Server Profiler · MS SQL Server Simulator v10 · Built by Adewale Samson Adeagbo
'; } function exportTrace() { if (!traceEvents.length) { toast('No trace events to export', 'warn'); return; } const hdr = 'Time,SPID,Event,SQL,Duration_ms,Rows,Success,User,DB'; const rows = traceEvents.map(e => '"'+e.t.toISOString()+'",'+e.spid+',"'+e.event+'","'+e.sql.replace(/"/g,'""')+'",'+e.ms+','+e.rows+','+e.success+',"'+e.user+'","'+e.db+'"').join('\n'); const content = withBuilderAttribution(hdr + '\n' + rows, 'sql').replace(/^-- /gm, '# '); const blob = new Blob([content], { type: 'text/csv' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'profiler_trace_' + Date.now() + '.csv'; a.click(); toast('Trace exported', 'success'); } function renderQueryStore() { const b = document.getElementById('querystore-body'); if (!b) return; const agg = {}; perfLog.forEach(p => { const key = p.sql.replace(/\s+/g,' ').toLowerCase().slice(0,80); if (!agg[key]) agg[key] = { count: 0, totalMs: 0, maxMs: 0, sample: p.sql }; agg[key].count++; agg[key].totalMs += p.ms; agg[key].maxMs = Math.max(agg[key].maxMs, p.ms); }); const top = Object.entries(agg).map(([k,v]) => ({ pattern: k, count: v.count, totalMs: v.totalMs, maxMs: v.maxMs, sample: v.sample, avgMs: Math.round(v.totalMs/v.count) })).sort((a,b) => b.totalMs - a.totalMs).slice(0,20); const rows = top.map((t,i) => { const heatClass = t.avgMs>100?'qs-hot':t.avgMs>30?'qs-warm':'qs-cold'; const heatLbl = t.avgMs>100?'🔥 HOT':t.avgMs>30?'🟧 WARM':'🟦 COLD'; return ''+(i+1)+''+esc(t.pattern)+''+t.count+''+t.totalMs+''+t.avgMs+''+t.maxMs+''+heatLbl+''; }).join(''); b.innerHTML = '
Query Store — captured '+perfLog.length+' executions across '+Object.keys(agg).length+' distinct query patterns.
' + ''+(rows||'')+'
#Query Pattern (normalized)ExecutionsTotal msAvg msMax msHeat
No queries captured yet.
' + '
Query Store · MS SQL Server Simulator v10 · cssadewale.pages.dev
'; } function renderPerfDash() { const b = document.getElementById('perfdash-body'); if (!b) return; const last50 = perfLog.slice(-50); const maxMs = Math.max(1, ...last50.map(p => p.ms)); const avg = last50.length ? Math.round(last50.reduce((a, x) => a + x.ms, 0) / last50.length) : 0; const sorted = last50.map(p => p.ms).sort((a, b) => a - b); const p95 = sorted.length ? sorted[Math.floor(sorted.length * 0.95)] : 0; const slowRows = perfLog.slice().sort((a, b) => b.ms - a.ms).slice(0, 10).map((p, i) => ''+(i+1)+''+esc(p.sql)+''+p.ms+'ms'+(p.rows||0)+''+new Date(p.t).toTimeString().slice(0,8)+'').join(''); b.innerHTML = '
' + '
Queries Logged
'+perfLog.length+'
total
' + '
Average
'+avg+'ms
' + '
95th Percentile
'+p95+'ms
' + '
Slowest
'+maxMs+'ms
' + '
' + '
' + '
Slowest 10 queries (this session)
' + ''+(slowRows||'')+'
#SQLDurationRowsTime
No queries logged.
' + '
Performance Dashboard · MS SQL Server Simulator v10 by Adewale Samson Adeagbo
'; setTimeout(() => { const c = document.getElementById('perfdash-chart'); if (!c || !last50.length) return; const ctx = c.getContext('2d'); const isDark = document.documentElement.getAttribute('data-theme') === 'dark'; new Chart(ctx, { type: 'line', data: { labels: last50.map((_, i) => i + 1), datasets: [{ label: 'Duration (ms)', data: last50.map(p => p.ms), borderColor: '#0078d4', backgroundColor: 'rgba(0,120,212,.15)', fill: true, tension: .3 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: isDark ? '#ccc' : '#333' } } }, scales: { x: { ticks: { color: isDark ? '#aaa' : '#666' }, grid: { color: isDark ? '#333' : '#eee' } }, y: { ticks: { color: isDark ? '#aaa' : '#666' }, grid: { color: isDark ? '#333' : '#eee' } } } } }); }, 80); } function renderStoredObjects() { const b = document.getElementById('storedobjects-body'); if (!b) return; b.innerHTML = '
' + '
📜 Stored Procedures ('+storedObjects.filter(o => o.kind === 'PROCEDURE').length+')
' + '
👁 Views ('+storedObjects.filter(o => o.kind === 'VIEW').length+')
' + '
⚡ Triggers ('+storedObjects.filter(o => o.kind === 'TRIGGER').length+')
' + '
' + '
Programmability · MS SQL Server Simulator v10 by Adewale Samson Adeagbo
'; renderSOList('procedures'); } function switchSOTab(kind, el) { document.querySelectorAll('#storedobjects-body .stab').forEach(s => s.classList.remove('active')); el.classList.add('active'); renderSOList(kind); } function renderSOList(kind) { const map = { procedures: 'PROCEDURE', views: 'VIEW', triggers: 'TRIGGER' }; const k = map[kind]; const items = storedObjects.filter(o => o.kind === k); let html = '
'; if (!items.length) html += '
No '+kind+' defined yet. Click ➕ to create one.
'; items.forEach(it => { html += '
' + ''+(k==='PROCEDURE'?'📜':k==='VIEW'?'👁':'⚡')+'' + '
'+esc(it.name)+'
'+esc((it.body||it.sql).slice(0,80))+'…
' + ''+it.kind+'' + '
' + (k==='PROCEDURE'?'':'') + (k==='VIEW'?'':'') + '' + '' + '
'; }); html += '
'; document.getElementById('so-tab-content').innerHTML = html; } function openCreateSO(kind) { const name = prompt('Name of new ' + kind + ':'); if (!name) return; if (kind === 'VIEW') { const sql = prompt('SELECT query for this view:\n(e.g. SELECT department, AVG(salary) FROM employees GROUP BY department)'); if (!sql) return; createView(name, sql); renderStoredObjects(); } else if (kind === 'PROCEDURE') { const params = prompt('Parameters (comma-separated, e.g. @dept, @minSalary):') || ''; const body = prompt('Procedure body (SQL using @params):'); if (!body) return; createStoredProcedure(name, params.split(',').map(p => p.trim()).filter(Boolean), body); renderStoredObjects(); } else if (kind === 'TRIGGER') { const table = prompt('Trigger on which table?'); if (!table) return; const event = prompt('Event (AFTER INSERT / AFTER UPDATE / AFTER DELETE):', 'AFTER INSERT'); if (!event) return; const body = prompt('Trigger body SQL:'); if (!body) return; createTrigger(name, table, event, body); renderStoredObjects(); } } function promptExecSP(name) { const sp = storedObjects.find(o => o.kind === 'PROCEDURE' && o.name === name); if (!sp) return; const args = sp.params.map(p => prompt('Value for ' + p + ':') || ''); executeStoredProcedure(name, args); closeModal('storedobjects-modal'); } function dropSO(name, kind) { if (!confirm('DROP ' + kind + ' ' + name + '?')) return; if (kind === 'VIEW') { try { db.run('DROP VIEW IF EXISTS "' + name + '"'); } catch (e) {} } if (kind === 'TRIGGER') { try { db.run('DROP TRIGGER IF EXISTS "' + name + '"'); } catch (e) {} } storedObjects = storedObjects.filter(o => !(o.kind === kind && o.name === name)); saveStoredObjects(); renderObjectExplorer(); renderStoredObjects(); toast(kind + ' ' + name + ' dropped', 'success'); } function renderSecurityModal() { const b = document.getElementById('security-body'); if (!b) return; const lrows = logins.map(l => '
' + '
'+l.name.charAt(0).toUpperCase()+'
' + '
'+esc(l.name)+'
'+l.role+' · '+l.type+' · '+(l.enabled?'✓ Enabled':'✗ Disabled')+' · since '+l.created+(l.note?' · '+esc(l.note)+'':'')+'
' + '
' + (l.name!=='sa'&&l.name!=='adewale'?'':'') + '
').join(''); const roles = ['sysadmin','serveradmin','securityadmin','processadmin','setupadmin','bulkadmin','diskadmin','dbcreator','public'].map(r => '
'+r+'
'+logins.filter(l => l.role === r).length+' member(s)
').join(''); b.innerHTML = '

Manage logins, users, and roles (simulated — for educational purposes; not enforced by SQLite WASM).

' + '
' + '

Logins ('+logins.length+')

'+lrows + '

Server Roles

'+roles+'
' + '
Security · MS SQL Server Simulator v10 by Adewale Samson Adeagbo
'; } function newLoginPrompt() { const name = prompt('Login name:'); if (!name) return; const role = prompt('Role (sysadmin/db_datareader/db_datawriter/public):', 'public') || 'public'; logins.push({ id: Date.now(), name, type: 'SQL Login', role, enabled: true, created: new Date().toISOString().slice(0,10) }); saveLogins(); renderSecurityModal(); toast('Login created', 'success'); } function toggleLogin(id) { const l = logins.find(x => x.id === id); if (l) { l.enabled = !l.enabled; saveLogins(); renderSecurityModal(); } } function deleteLogin(id) { if (!confirm('Delete this login?')) return; logins = logins.filter(x => x.id !== id); saveLogins(); renderSecurityModal(); } function renderBackupModal() { const b = document.getElementById('backup-body'); if (!b) return; b.innerHTML = '

Backup and restore the entire master database as a .bak file (binary SQLite format).

' + '

1 Backup Type

' + '

2 Source Database

' + '

3 Destination

File will be downloaded to your device as master_backup_TIMESTAMP.bak

' + '

4 Verification

' + '
' + '

Backup files contain the full schema, data, indexes, views, and triggers — fully round-trippable.

' + '
Backup & Restore · MS SQL Server Simulator v10 by Adewale Samson Adeagbo
'; } function renderMaintenance() { const b = document.getElementById('maintenance-body'); if (!b) return; const steps = MAINT_TASKS.map((t,i) => '
'+(i+1)+'
'+t.icon+' '+esc(t.name)+'
'+esc(t.desc)+(t.sql.startsWith('/*')?'':' · SQL: '+esc(t.sql)+'')+'
').join(''); b.innerHTML = '

Common maintenance tasks. Click a task to run it now, or check multiple and click Run Selected.

' + '
' + steps + '
Maintenance Plan · MS SQL Server Simulator v10 by Adewale Samson Adeagbo
'; } function runMaint(id, idx) { const el = document.getElementById('mp-step-' + idx); const ok = executeMaintenanceTask(id); if (el) el.classList.add(ok ? 'done' : 'failed'); toast((ok?'✓ ':'✗ ') + MAINT_TASKS.find(t => t.id === id).name, ok ? 'success' : 'error'); } function runSelectedMaint() { const checks = document.querySelectorAll('[id^="mpchk-"]'); let any = false; checks.forEach((c, i) => { if (c.checked) { runMaint(c.dataset.id, i); any = true; } }); if (!any) toast('Select at least one task', 'warn'); } function runAllMaint() { if (!confirm('Run ALL maintenance tasks?')) return; MAINT_TASKS.forEach((t, i) => setTimeout(() => runMaint(t.id, i), i * 300)); } function renderImportExport() { const b = document.getElementById('importexport-body'); if (!b) return; b.innerHTML = '

📥 Import Sources

' + '
' + '' + '' + '' + '' + '' + '' + '
' + '

📤 Export Targets

' + '
' + '' + '' + '' + '' + '' + '' + '' + '' + '
' + '

All exports include builder attribution headers (Adewale Samson Adeagbo · cssadewale.pages.dev) for proper credit.

'; } function renderDbDiagram() { const b = document.getElementById('dbdiagram-body'); if (!b) return; b.innerHTML = '
Database Diagram — Auto-generated from loaded tables.
Database Diagrams · MS SQL Server Simulator v10 by Adewale Samson Adeagbo
'; setTimeout(() => { const canvas = document.getElementById('dbdiag-canvas'); if (!canvas) return; const ctx = canvas.getContext('2d'); const rect = canvas.getBoundingClientRect(); canvas.width = rect.width; canvas.height = 480; let tres; try { tres = db.exec("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE '\\_%' ESCAPE '\\\\' ORDER BY name"); } catch(e) { return; } if (!tres.length) { ctx.fillStyle='#888'; ctx.font='14px Segoe UI'; ctx.fillText('No tables to diagram',20,40); return; } const tables = tres[0].values.map(r => r[0]); const isDark = document.documentElement.getAttribute('data-theme') === 'dark'; ctx.fillStyle = isDark ? '#1e1e1e' : '#fff'; ctx.fillRect(0,0,canvas.width,canvas.height); const cols = Math.ceil(Math.sqrt(tables.length)); const bw = 200, bh = 130, gx = 50, gy = 50; const positions = {}; tables.forEach((t, i) => { positions[t] = { x: 30 + (i % cols) * (bw + gx), y: 30 + Math.floor(i / cols) * (bh + gy), w: bw, h: bh }; }); const colsMap = {}; tables.forEach(t => { try { const r = db.exec('PRAGMA table_info("'+t+'")'); colsMap[t] = r.length ? r[0].values.map(c => c[1]) : []; } catch(e){ colsMap[t]=[]; } }); ctx.strokeStyle = '#0078d4'; ctx.lineWidth = 2; for (let i = 0; i < tables.length; i++) for (let j = i + 1; j < tables.length; j++) { const ta = tables[i], tb = tables[j]; const shared = colsMap[ta].filter(c => colsMap[tb].includes(c) && (c.endsWith('_id') || ['department','customer_id','employee_id','product_name','course_id'].includes(c))); if (shared.length) { const pa = positions[ta], pb = positions[tb]; ctx.beginPath(); ctx.moveTo(pa.x + pa.w/2, pa.y + pa.h/2); ctx.lineTo(pb.x + pb.w/2, pb.y + pb.h/2); ctx.stroke(); } } tables.forEach(t => { const p = positions[t]; ctx.fillStyle = isDark ? '#252526' : '#f5f5f5'; ctx.fillRect(p.x, p.y, p.w, p.h); ctx.strokeStyle = '#0078d4'; ctx.lineWidth = 2; ctx.strokeRect(p.x, p.y, p.w, p.h); ctx.fillStyle = '#0078d4'; ctx.fillRect(p.x, p.y, p.w, 22); ctx.fillStyle = '#fff'; ctx.font = 'bold 12px Segoe UI'; ctx.fillText('⊞ dbo.' + t, p.x + 8, p.y + 15); ctx.fillStyle = isDark ? '#ccc' : '#333'; ctx.font = '10px JetBrains Mono'; colsMap[t].slice(0, 9).forEach((c, i) => { ctx.fillText(c, p.x + 10, p.y + 36 + i * 11); }); if (colsMap[t].length > 9) { ctx.fillStyle = '#888'; ctx.fillText('… +' + (colsMap[t].length - 9) + ' more', p.x + 10, p.y + 36 + 9 * 11); } }); }, 80); } function renderAlwaysOn() { const b = document.getElementById('alwayson-body'); if (!b) return; b.innerHTML = '
Always On Availability Group: AG_HMG_PROD· Visual simulation — for educational purposes only. SQLite is single-node, but this UI mirrors real SQL Server Always On dashboards.
' + '
' + '
🟢
localhost\\SQLPRIMARY
PRIMARY (read-write)
Synchronized · 0 ms lag
' + '
🔵
localhost\\SQLSEC01
SECONDARY (read-only)
Synchronized · 4 ms lag
' + '
🔵
localhost\\SQLSEC02
SECONDARY (read-only)
Synchronized · 7 ms lag
' + '
🟡
localhost\\SQLSEC03
RESOLVING (failover)
Synchronizing · 142 ms lag
' + '
' + '

Availability Databases

' + '' + '' + '' + '' + '' + '
DatabaseReplicaStateSync StateLast Hardened
masterSQLPRIMARYONLINESYNCHRONIZEDjust now
masterSQLSEC01ONLINESYNCHRONIZED4 ms ago
masterSQLSEC02ONLINESYNCHRONIZED7 ms ago
masterSQLSEC03SYNCHRONIZINGNOT_SYNCHRONIZED142 ms ago
' + '

Listener

AG Listener
AGL_HMG_PROD.cssadewale.local:1433
IP: 192.168.1.100 · Routing: Read-Write → Primary, Read-Only → Round-robin secondaries
' + '
Always On Dashboard · MS SQL Server Simulator v10 by Adewale Samson Adeagbo
'; } function renderRegisteredServers() { const b = document.getElementById('regservers-body'); if (!b) return; b.innerHTML = '

Saved server connections.

' + '
' + '
📁Local Server Groups
' + '
' + '
·🖥localhost\\SQLEXPRESS (SQLite WASM, Active)
' + '
·🖥DEV-SRV01\\SQLDEV (Demo)
' + '
·🖥PROD-CLUSTER.SQL01 (Demo)
' + '
' + '
📁Central Management Servers
' + '
' + '
·🖥CMS.cssadewale.local (Demo)
' + '
' + '

In real SSMS, this lists every server you have connected to. Here it shows the simulated local instance plus mock demo servers.

'; } function renderSolutionExplorer() { const b = document.getElementById('solution-body'); if (!b) return; const queries = savedQueries.slice(0,10).map(q => '
·📜'+esc(q.name)+'.sql
').join(''); b.innerHTML = '

Solution & Project files (treat each saved query as a project item).

' + '
' + '
📁Solution \'MSSQLSimulator\' (1 project)
' + '
' + '
📦MyProject
' + '
' + '
·📂Connections (1)
' + '
📂Queries ('+savedQueries.length+')
' + '
'+(queries||'
No saved queries.
')+'
' + '
·📂Miscellaneous Files
' + '
'; } function renderTemplateExplorer() { const b = document.getElementById('templateexp-body'); if (!b) return; const folders = [ { folder: 'SQL Server Templates', items: ['Database / Create Database', 'Table / Create Table', 'View / Create View', 'Index / Create Index', 'Stored Procedure / Create Procedure'] }, { folder: 'DML', items: ['Basic SELECT', 'SELECT with JOIN', 'SELECT with CTE', 'SELECT with Window Function', 'INSERT row', 'UPDATE with WHERE', 'DELETE with WHERE'] }, { folder: 'DDL', items: ['CREATE TABLE', 'ALTER TABLE ADD COLUMN', 'DROP TABLE', 'CREATE INDEX', 'CREATE VIEW'] }, { folder: 'Reporting', items: ['Department Report', 'Sales Report', 'Customer LTV', 'Inventory Reorder', 'Academic Pass Rate'] }, { folder: 'Builder Examples', items: ['About the Builder Query', 'HMG Concepts Project List'] }, ]; const html = folders.map(f => '
▼ 📁 '+esc(f.folder)+'
'+f.items.map(it => '
📜 '+esc(it)+'
').join('')+'
').join(''); b.innerHTML = '

SSMS-style Template Explorer. Click any template to insert into the editor.

' + '
'+html+'
'; } function insertTemplate(name) { const templates = { 'Basic SELECT': 'SELECT * FROM employees LIMIT 10;', 'SELECT with JOIN': 'SELECT e.first_name, d.budget\nFROM employees e\nINNER JOIN departments d ON e.department = d.department;', 'SELECT with CTE': 'WITH dept_avg AS (\n SELECT department, AVG(salary) AS avg_sal\n FROM employees GROUP BY department\n)\nSELECT * FROM dept_avg WHERE avg_sal > 700000;', 'SELECT with Window Function': 'SELECT first_name, department, salary,\n RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rnk\nFROM employees;', 'INSERT row': "INSERT INTO employees (first_name, last_name, department, salary)\nVALUES ('Tunde', 'Bello', 'Sales', 500000);", 'UPDATE with WHERE': "UPDATE employees SET salary = salary * 1.10\nWHERE department = 'Engineering';", 'DELETE with WHERE': 'DELETE FROM employees WHERE perf_score < 2.5;', 'CREATE TABLE': 'CREATE TABLE example (\n id INTEGER PRIMARY KEY,\n name TEXT NOT NULL,\n amount REAL DEFAULT 0\n);', 'ALTER TABLE ADD COLUMN': 'ALTER TABLE employees ADD COLUMN bonus REAL DEFAULT 0;', 'DROP TABLE': 'DROP TABLE IF EXISTS example;', 'CREATE INDEX': 'CREATE INDEX idx_emp_dept ON employees(department);', 'CREATE VIEW': 'CREATE VIEW vw_dept_salary AS\nSELECT department, AVG(salary) AS avg_sal\nFROM employees GROUP BY department;', 'Department Report': "SELECT department, COUNT(*) AS headcount,\n ROUND(AVG(salary),0) AS avg_salary\nFROM employees\nGROUP BY department\nORDER BY avg_salary DESC;", 'Sales Report': "SELECT region, category, SUM(total_amount) AS revenue\nFROM orders\nWHERE status != 'Cancelled'\nGROUP BY region, category\nORDER BY revenue DESC;", 'Customer LTV': 'SELECT c.customer_name, COUNT(o.order_id) AS orders,\n COALESCE(SUM(o.total_amount),0) AS lifetime_value\nFROM customers c\nLEFT JOIN orders o ON c.customer_id = o.customer_id\nGROUP BY c.customer_id\nORDER BY lifetime_value DESC;', 'Inventory Reorder': "SELECT product_name, stock_qty, reorder_level\nFROM inventory\nWHERE stock_qty <= reorder_level;", 'Academic Pass Rate': "SELECT class, subject, ROUND(AVG(score),1) AS avg_score\nFROM students\nGROUP BY class, subject;", 'About the Builder Query': "-- About the Builder\nSELECT 'Adewale Samson Adeagbo' AS Name,\n 'Data Scientist | EdTech Builder | AI-Augmented Solutions Developer' AS Role,\n 'HMG Concepts (est. 2015)' AS Brand,\n 'Lagos, Nigeria' AS Location,\n 'https://cssadewale.pages.dev' AS Portfolio,\n 'https://linkedin.com/in/adewalesamsonadeagbo' AS LinkedIn,\n 'https://github.com/cssadewale' AS GitHub,\n 15 AS YearsTeaching,\n 12 AS LiveProjects;", 'HMG Concepts Project List': "-- HMG Concepts Subsidiaries\nSELECT * FROM (VALUES\n ('HMG Academy','Virtual learning institution','hmgacademy.pages.dev'),\n ('HMG Technologies','EdTech and data solutions','built-in-house'),\n ('HMG Media','Educational content and community','hmgconcepts.pages.dev')\n) AS subsidiaries(name, mission, url);", 'Database / Create Database': "-- SQLite WASM uses single 'master' database. This is a placeholder:\n-- CREATE DATABASE MyAppDB;", 'Table / Create Table': 'CREATE TABLE NewTable (\n ID INTEGER PRIMARY KEY,\n Name TEXT NOT NULL,\n CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP\n);', 'View / Create View': 'CREATE VIEW vw_TopEmployees AS\nSELECT first_name, last_name, salary FROM employees ORDER BY salary DESC LIMIT 10;', 'Index / Create Index': 'CREATE INDEX idx_orders_date ON orders(order_date);', 'Stored Procedure / Create Procedure': '-- Stored procedures simulated. Use Tools > Programmability > Create New Procedure\n-- Example body:\n-- SELECT * FROM employees WHERE department = @dept AND salary > @minSal', }; if (templates[name]) { editor().value = templates[name]; updateEditor(); markTabModified(); closeModal('templateexp-modal'); toast('Template inserted', 'success'); } } function renderTSQLXlat() { const b = document.getElementById('tsqlxlat-body'); if (!b) return; const rows = [ ['SELECT TOP 10 * FROM t', 'SELECT * FROM t LIMIT 10', 'Auto-appends LIMIT'], ['GETDATE()', "datetime('now','localtime')", 'Local server time'], ['GETUTCDATE()', "datetime('now')", 'UTC time'], ["ISNULL(x, 'N/A')", "IFNULL(x, 'N/A')", 'Default for NULL'], ['LEN(name)', 'LENGTH(name)', 'String length'], ["CHARINDEX('@', email)", "INSTR(email, '@')", 'Args flipped automatically'], ["CONVERT(INTEGER, '42')", "CAST('42' AS INTEGER)", 'Type conversion'], ["IIF(salary > 700000, 'High', 'Low')", "CASE WHEN salary > 700000 THEN 'High' ELSE 'Low' END", 'Recursive IIFs supported'], ["CHOOSE(2, 'A', 'B', 'C')", "CASE WHEN 2=1 THEN 'A' WHEN 2=2 THEN 'B' WHEN 2=3 THEN 'C' END", 'Index-based pick'], ['YEAR(hire_date)', "CAST(STRFTIME('%Y', hire_date) AS INTEGER)", 'Same for MONTH, DAY'], ['DATEPART(month, dt)', "CAST(STRFTIME('%m', dt) AS INTEGER)", 'year, month, day, hour, minute, second'], ['DATEDIFF(day, a, b)', 'CAST((julianday(b)-julianday(a))*1 AS INTEGER)', 'Day-level math'], ['DATEADD(day, 7, dt)', "datetime(dt, '+7 days')", 'Add/subtract intervals'], ['NEWID()', 'lower(hex(randomblob(16)))', 'UUID-like ID'], ['[bracket] identifiers', '"quoted" identifiers', 'Outside string literals'], ['DECLARE @x INT = 10', 'JS variable substitution', 'Later @x references replaced'], ['SET @x = 20', 'JS variable update', 'Persisted in this session'], ["PRINT 'Hello'", "SELECT 'Hello' AS [PRINT]", 'Shows as result'], ['GO batch separator', 'Each batch executed separately', 'Standard SSMS pattern'], ['sys.tables', 'Translated to sqlite_master subquery', 'Read-only catalog view'], ['sys.columns', 'Translated to pragma_table_info join', ''], ['INFORMATION_SCHEMA.TABLES', 'Mapped to sqlite_master', 'ANSI standard catalog'], ["sp_help 'tbl'", "PRAGMA table_info('tbl')", 'Schema introspection'], ['NVARCHAR(MAX) in DDL', 'TEXT', 'SQLite is type-flexible'], ['BIT column', 'INTEGER', '0/1 values'], ['MONEY', 'REAL', 'Floating point'], ['UNIQUEIDENTIFIER', 'TEXT', 'Store as string'], ['IDENTITY(1,1)', 'Dropped; use INTEGER PRIMARY KEY', 'SQLite uses rowid'], ['TRY_CAST / TRY_CONVERT', 'CAST', "SQLite does not fail; returns NULL"], ['OFFSET ... ROWS FETCH NEXT ...', 'LIMIT ... OFFSET ...', 'Pagination'], ['dbo.table', 'table', 'Schema prefix dropped'], ]; const rowsHTML = rows.map(r => ''+esc(r[0])+''+esc(r[1])+''+esc(r[2])+'').join(''); b.innerHTML = '

When you write Microsoft T-SQL syntax, the simulator auto-translates to SQLite equivalents. Status bar shows the current mode. Click the badge to cycle AUTO → STRICT → OFF.

' + ''+rowsHTML+'
T-SQL (what you type)SQLite (what runs)Notes
' + '

Toggle modes (click T-SQL: AUTO badge in status bar):
AUTO — translate every supported construct (recommended)
STRICT — still translate, but flag each substitution prominently in Messages
OFF — pass query straight to SQLite (will fail on T-SQL syntax)

' + '

T-SQL Translation Engine · MS SQL Server Simulator v10 · Built by Adewale Samson Adeagbo

'; } function renderFeaturesDoc() { const b = document.getElementById('featuresdoc-body'); if (!b) return; let html = '

📚 MS SQL Server Simulator — Complete Feature Documentation

' + '

Every feature, what it does, why it exists, how to use it. Press F1 anywhere for the searchable in-app help.

'; HELP_DATA.forEach(sec => { html += '

'+sec.icon+' '+esc(sec.section)+'

'; sec.items.forEach(it => { html += '
'+esc(it.name)+' '+(it.kb?''+esc(it.kb)+'':'')+'
'+esc(it.desc)+''+(it.tip?'
💡 '+esc(it.tip)+'':'')+'
'; }); }); html += '

Documentation for MS SQL Server Simulator v10 by Adewale Samson Adeagbo

'; b.innerHTML = html; } /* ═══════════════════════════════════════════════════════════════════════════ EXTEND HELP_DATA WITH V10 FEATURES ═══════════════════════════════════════════════════════════════════════════ */ HELP_DATA.unshift({ section: 'Meet the Builder', icon: '👤', items: [ { name: 'About Adewale Samson Adeagbo', desc: 'Click the title-bar avatar, the builder strip, the "Built by" link, or Help > Meet the Builder to see the full profile of the developer behind this app: Lagos-based data scientist, 15+ years educator, founder of HMG Concepts (2015), 3MTT Nigeria participant.', tip: 'Builder visibility is intentionally maximised so users can credit and contact the author.' }, { name: 'Builder Strip', desc: 'The blue strip above the status bar permanently displays the builder name, role, and quick links to portfolio, LinkedIn, GitHub, WhatsApp.', tip: 'Hide via View menu if needed.' }, { name: 'Welcome Splash', desc: 'A one-time welcome screen on first load presenting the builder. Tick "Don\'t show again" to disable.', tip: 'Clear browser data to see it again.' }, { name: 'Object Explorer Builder Node', desc: 'A dedicated "Builder: Adewale Adeagbo" node at the bottom of the tree opens the full bio.', tip: '' }, { name: 'Status Bar Builder Credit', desc: 'Bottom-right blue bar shows Adewale Adeagbo — click for instant bio access.', tip: '' }, { name: 'Attribution in Exports', desc: 'Every exported CSV, JSON, HTML, Markdown, SQL, and DDL file auto-includes a header crediting the builder with portfolio and contact links.', tip: '' }, ]}); HELP_DATA.push({ section: 'V10 Enterprise Features', icon: '🏢', items: [ { name: 'T-SQL Auto-Translation', desc: '30+ T-SQL constructs are auto-translated to SQLite at execution time. Write real T-SQL (TOP, GETDATE, ISNULL, IIF, DATEPART, etc.) and it just works. Status bar shows T-SQL: AUTO badge.', tip: 'Click the badge to cycle modes: AUTO > STRICT > OFF.' }, { name: 'Activity Monitor', desc: 'Tools > Activity Monitor. Real-time dashboard: total queries, average duration, errors, uptime, table count, active connections, sparkline of recent execution times. Auto-refreshes every 2 seconds.', tip: 'Just like SSMS Activity Monitor.' }, { name: 'SQL Server Profiler', desc: 'Tools > SQL Server Profiler. Trace-table of every executed query (last 500): time, SPID, event class (DDL/DML/SELECT/error), SQL text, duration, rows, user, db. Pause/clear/export trace as CSV.', tip: '' }, { name: 'Query Store', desc: 'Tools > Query Store. Aggregates queries by normalized pattern. Heat-coded by avg duration (HOT/WARM/COLD).', tip: 'Find your most-expensive query patterns at a glance.' }, { name: 'Performance Dashboard', desc: 'Tools > Performance Dashboard. Charts of duration over time, slowest-10 list, p95 / max statistics.', tip: '' }, { name: 'Programmability (Procs/Views/Triggers)', desc: 'Tools > Programmability. Tab interface to create, list, and execute Stored Procedures (JS-backed parameter substitution), Views (real SQLite VIEW), and Triggers (real SQLite TRIGGER). All listed in Object Explorer.', tip: 'Stored procedure parameters use @paramName syntax.' }, { name: 'Security and Logins', desc: 'Tools > Security and Logins. Manage simulated SQL logins, Windows logins, and roles (sysadmin, db_datareader, db_datawriter, public). Enable/disable, add/remove.', tip: 'The builder account "adewale" is pre-configured as sysadmin.' }, { name: 'Backup and Restore Wizard', desc: 'Tools > Backup and Restore Wizard. Multi-step wizard for full database backup (.bak file) and restore. Round-trips schema, data, indexes, views, triggers.', tip: '' }, { name: 'Maintenance Plan Wizard', desc: 'Tools > Maintenance Plan. Seven built-in tasks: Reorganize Indexes, Rebuild Indexes, Update Statistics (ANALYZE), Check Integrity, Vacuum/Shrink, Cleanup History, Full Backup.', tip: '' }, { name: 'Import / Export Wizard', desc: 'Tools > Import / Export Wizard. Single hub for all import sources (CSV, JSON, SQL, SQLite, .bak) and export targets.', tip: 'Every export includes builder attribution.' }, { name: 'Database Diagrams', desc: 'Tools > Database Diagrams. SSMS-style table relationship diagram.', tip: '' }, { name: 'Always On Dashboard (Visual)', desc: 'Tools > Always On Dashboard. Simulated HA cluster visualisation: Primary + Secondaries with sync state, lag, availability databases, listener config.', tip: 'Educational only.' }, { name: 'Registered Servers', desc: 'View > Registered Servers. Tree of saved server connections.', tip: '' }, { name: 'Solution Explorer', desc: 'View > Solution Explorer. Treats saved queries as a project.', tip: '' }, { name: 'Template Explorer', desc: 'View > Template Explorer. SSMS-style hierarchical template tree organized into folders.', tip: '' }, { name: 'GO Batch Separator', desc: 'Use GO on its own line to split a script into multiple batches that execute sequentially.', tip: '' }, { name: 'DECLARE / SET / @variables', desc: 'Write DECLARE @x INT = 10; SET @x = 20; and use @x in subsequent statements. Auto-substituted before execution.', tip: '' }, { name: 'sys.tables / INFORMATION_SCHEMA', desc: 'Query system catalogs as in real SQL Server. sys.tables, sys.columns, sys.databases, INFORMATION_SCHEMA.TABLES all work.', tip: '' }, { name: 'JSON Import', desc: 'File menu or Import/Export Wizard. Imports a JSON array of objects as a new table; auto-detects column types.', tip: '' }, { name: 'Builder Identity in New Tabs', desc: 'Every new query tab is pre-seeded with a builder-attribution comment header.', tip: '' }, ]}); /* Extend Palette */ PALETTE_ITEMS.push( { name: 'Meet the Builder', icon: '👤', cat: 'Help', fn: () => openModal('builder-modal') }, { name: 'Activity Monitor', icon: '📊', cat: 'Tools', fn: () => openModal('activitymonitor-modal') }, { name: 'SQL Server Profiler', icon: '🔬', cat: 'Tools', fn: () => openModal('profiler-modal') }, { name: 'Query Store', icon: '🗃', cat: 'Tools', fn: () => openModal('querystore-modal') }, { name: 'Performance Dashboard', icon: '📈', cat: 'Tools', fn: () => openModal('perfdash-modal') }, { name: 'Programmability (Procs/Views/Triggers)', icon: '⚙', cat: 'Tools', fn: () => openModal('storedobjects-modal') }, { name: 'Security and Logins', icon: '🔒', cat: 'Tools', fn: () => openModal('security-modal') }, { name: 'Backup and Restore Wizard', icon: '💾', cat: 'Tools', fn: () => openModal('backup-modal') }, { name: 'Maintenance Plan Wizard', icon: '🛠', cat: 'Tools', fn: () => openModal('maintenance-modal') }, { name: 'Import / Export Wizard', icon: '↔', cat: 'Tools', fn: () => openModal('importexport-modal') }, { name: 'Database Diagrams', icon: '🗺', cat: 'Tools', fn: () => openModal('dbdiagram-modal') }, { name: 'Always On Dashboard', icon: '🔁', cat: 'Tools', fn: () => openModal('alwayson-modal') }, { name: 'Registered Servers', icon: '🗄', cat: 'View', fn: () => openModal('regservers-modal') }, { name: 'Solution Explorer', icon: '📁', cat: 'View', fn: () => openModal('solution-modal') }, { name: 'Template Explorer', icon: '📋', cat: 'View', fn: () => openModal('templateexp-modal') }, { name: 'T-SQL Translation Map', icon: '🔄', cat: 'Help', fn: () => openModal('tsqlxlat-modal') }, { name: 'Full Feature Documentation', icon: '📚', cat: 'Help', fn: () => openModal('featuresdoc-modal') }, { name: 'Toggle T-SQL Translation Mode', icon: '🔄', cat: 'Tools', fn: toggleTSQLTranslation }, { name: 'Toggle Builder Strip', icon: '👤', cat: 'View', fn: toggleBuilderStrip }, { name: 'Full Backup (.bak)', icon: '💾', cat: 'File', fn: fullBackup }, { name: 'Restore from .bak', icon: '↶', cat: 'File', fn: () => document.getElementById('bak-file-input').click() }, { name: 'Import JSON', icon: '{ }', cat: 'File', fn: () => document.getElementById('json-file-input').click() } ); /* OVERRIDE openModal to dispatch to v10 renderers */ const _origOpenModal = openModal; window.openModal = function (id) { _origOpenModal(id); if (id === 'builder-modal') renderBuilderModal(); else if (id === 'activitymonitor-modal') renderActivityMonitor(); else if (id === 'profiler-modal') renderProfiler(); else if (id === 'querystore-modal') renderQueryStore(); else if (id === 'perfdash-modal') renderPerfDash(); else if (id === 'storedobjects-modal') renderStoredObjects(); else if (id === 'security-modal') renderSecurityModal(); else if (id === 'backup-modal') renderBackupModal(); else if (id === 'maintenance-modal') renderMaintenance(); else if (id === 'importexport-modal') renderImportExport(); else if (id === 'dbdiagram-modal') renderDbDiagram(); else if (id === 'alwayson-modal') renderAlwaysOn(); else if (id === 'regservers-modal') renderRegisteredServers(); else if (id === 'solution-modal') renderSolutionExplorer(); else if (id === 'templateexp-modal') renderTemplateExplorer(); else if (id === 'tsqlxlat-modal') renderTSQLXlat(); else if (id === 'featuresdoc-modal') renderFeaturesDoc(); }; /* INJECT all V10 modals into the document */ const V10_MODALS = '' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
'; setTimeout(() => { const host = document.getElementById('modals-host'); if (host) host.insertAdjacentHTML('beforeend', V10_MODALS); setTimeout(() => { try { renderObjectExplorer(); } catch (e) {} }, 200); }, 800); /* Ctrl+Alt+A for Activity Monitor */ document.addEventListener('keydown', e => { if (e.ctrlKey && e.altKey && e.key.toLowerCase() === 'a') { e.preventDefault(); openModal('activitymonitor-modal'); } }); /* Console signature */ console.log('%c MS SQL Server Simulator v10 Enterprise Edition ', 'background:#0078d4;color:#fff;font-weight:bold;font-size:14px;padding:4px 10px'); console.log('%c Built by: Adewale Samson Adeagbo (cssadewale) ', 'background:#107c10;color:#fff;font-size:12px;padding:3px 8px'); console.log('Portfolio: https://cssadewale.pages.dev'); console.log('LinkedIn: https://linkedin.com/in/adewalesamsonadeagbo'); console.log('GitHub: https://github.com/cssadewale'); console.log('HMG Academy: https://hmgacademy.pages.dev'); console.log('HMG Concepts: https://hmgconcepts.pages.dev'); console.log('WhatsApp: +234 810 086 6322'); console.log('100% free · No backend · No AI API · Built on an Android tablet in Lagos, Nigeria');