mm-math 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,885 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <script>
6
+ (function(){
7
+ var n=performance.getEntriesByType('navigation')[0];
8
+ if(n&&n.type==='reload'){sessionStorage.clear();window.location.replace('./index.html');return;}
9
+ if(sessionStorage.getItem('mm_auth')!=='true'){window.location.replace('./index.html');return;}
10
+ if(sessionStorage.getItem('mm_force_change')==='true'){window.location.replace('./change-password.html');return;}
11
+ var rank=sessionStorage.getItem('mm_rank');
12
+ if(rank==='administrator'){window.location.replace('./admin.html');return;}
13
+ if(rank!=='admin'){window.location.replace('./browse.html');}
14
+ })();
15
+ </script>
16
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
17
+ <title>Control Center — MM Systems</title>
18
+ <style>
19
+ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
20
+ :root{
21
+ --bg:#060d16;--panel:#0a1628;--border:#1a3a5c;
22
+ --accent:#00d4ff;--green:#00ff88;--red:#ff4757;--yellow:#ffd32a;--purple:#a855f7;
23
+ --text:#c8d8e8;--muted:#4a6a8a;
24
+ --glow:0 0 10px rgba(0,212,255,.3);
25
+ }
26
+ body{background:var(--bg);color:var(--text);font-family:'Courier New',monospace;font-size:13px;min-height:100vh;overflow-x:hidden;}
27
+
28
+ /* ── Header ── */
29
+ .cc-header{background:var(--panel);border-bottom:1px solid var(--border);padding:12px 24px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100;}
30
+ .cc-title{font-size:15px;font-weight:bold;color:var(--accent);letter-spacing:3px;text-transform:uppercase;text-shadow:var(--glow);}
31
+ .cc-right{display:flex;align-items:center;gap:24px;font-size:11px;color:var(--muted);}
32
+ .cc-clock{font-size:13px;color:var(--accent);letter-spacing:2px;font-variant-numeric:tabular-nums;}
33
+ .exit-btn{color:var(--muted);text-decoration:none;font-size:11px;letter-spacing:1px;border:1px solid var(--border);padding:4px 10px;border-radius:3px;transition:all .2s;}
34
+ .exit-btn:hover{color:var(--accent);border-color:var(--accent);}
35
+ .status-dot{width:8px;height:8px;border-radius:50%;background:var(--green);display:inline-block;margin-right:6px;animation:blink 2s infinite;}
36
+ @keyframes blink{0%,100%{opacity:1;}50%{opacity:.3;}}
37
+
38
+ /* ── Grid ── */
39
+ .cc-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;padding:20px;max-width:1500px;margin:0 auto;}
40
+
41
+ /* ── Panel ── */
42
+ .panel{background:var(--panel);border:1px solid var(--border);border-radius:4px;padding:16px;position:relative;overflow:hidden;}
43
+ .panel::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--accent),transparent);}
44
+ .panel-title{font-size:10px;letter-spacing:2px;text-transform:uppercase;color:var(--accent);margin-bottom:14px;display:flex;align-items:center;justify-content:space-between;}
45
+ .scan-line{position:absolute;left:0;right:0;height:1px;background:rgba(0,212,255,.1);animation:scan 5s linear infinite;pointer-events:none;}
46
+ @keyframes scan{0%{top:0;}100%{top:100%;}}
47
+
48
+ /* ── Metrics ── */
49
+ .metric{margin-bottom:12px;}
50
+ .metric-header{display:flex;justify-content:space-between;margin-bottom:4px;font-size:12px;}
51
+ .metric-label{color:var(--muted);}
52
+ .metric-val{color:var(--text);font-weight:bold;font-variant-numeric:tabular-nums;}
53
+ .metric-bar{height:6px;background:rgba(255,255,255,.05);border-radius:3px;overflow:hidden;}
54
+ .metric-fill{height:100%;border-radius:3px;background:linear-gradient(90deg,var(--accent),#0088ff);transition:width 1.2s ease;box-shadow:0 0 8px rgba(0,212,255,.4);}
55
+ .metric-fill.warn{background:linear-gradient(90deg,var(--yellow),#ff8800);box-shadow:0 0 8px rgba(255,211,42,.4);}
56
+ .metric-fill.danger{background:linear-gradient(90deg,var(--red),#c00);box-shadow:0 0 8px rgba(255,71,87,.4);}
57
+ .sparkline{display:flex;align-items:flex-end;gap:3px;height:44px;margin-top:14px;}
58
+ .spark-bar{flex:1;background:linear-gradient(180deg,var(--accent),rgba(0,212,255,.1));border-radius:2px 2px 0 0;transition:height .8s ease;}
59
+
60
+ /* ── Stat boxes ── */
61
+ .stat-row{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
62
+ .stat-box{background:rgba(0,212,255,.04);border:1px solid rgba(0,212,255,.1);border-radius:3px;padding:12px;text-align:center;}
63
+ .stat-number{font-size:26px;font-weight:bold;color:var(--accent);text-shadow:var(--glow);display:block;font-variant-numeric:tabular-nums;}
64
+ .stat-label{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:1px;margin-top:4px;}
65
+
66
+ /* ── Activity log ── */
67
+ .log-scroll{background:#020810;border:1px solid var(--border);border-radius:3px;padding:10px;height:180px;overflow:hidden;font-size:11px;line-height:1.6;}
68
+ .log-line{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
69
+ .log-time{color:var(--muted);}
70
+ .log-ok{color:var(--green);}
71
+ .log-warn{color:var(--yellow);}
72
+ .log-info{color:var(--accent);}
73
+ .log-err{color:var(--red);}
74
+
75
+ /* ── Security ── */
76
+ .sec-row{display:flex;align-items:center;justify-content:space-between;padding:7px 0;border-bottom:1px solid rgba(255,255,255,.04);font-size:11px;}
77
+ .sec-row:last-child{border-bottom:none;}
78
+ .sec-key{color:var(--muted);}
79
+ .sec-val{color:var(--green);}
80
+ .sec-val.warn{color:var(--yellow);}
81
+
82
+ /* ── Geo ── */
83
+ .geo-row{display:flex;align-items:center;gap:10px;margin-bottom:10px;font-size:11px;}
84
+ .geo-label{width:30px;color:var(--muted);}
85
+ .geo-bar-wrap{flex:1;height:8px;background:rgba(255,255,255,.05);border-radius:4px;overflow:hidden;}
86
+ .geo-bar-fill{height:100%;background:linear-gradient(90deg,var(--green),#00aa55);border-radius:4px;transition:width 1.5s ease;}
87
+ .geo-pct{width:35px;text-align:right;color:var(--text);font-variant-numeric:tabular-nums;}
88
+
89
+ /* ── Edge nodes ── */
90
+ .node-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:6px;}
91
+ .node{height:28px;border-radius:3px;background:rgba(0,255,136,.08);border:1px solid rgba(0,255,136,.2);display:flex;align-items:center;justify-content:center;font-size:9px;color:var(--green);letter-spacing:.5px;cursor:pointer;transition:all .3s;}
92
+ .node:hover{background:rgba(0,255,136,.18);}
93
+ .node.warn{background:rgba(255,211,42,.08);border-color:rgba(255,211,42,.2);color:var(--yellow);}
94
+ .node.down{background:rgba(255,71,87,.06);border-color:rgba(255,71,87,.2);color:var(--red);}
95
+ .node.down:hover{background:rgba(255,71,87,.18);}
96
+
97
+ /* ── System controls ── */
98
+ .ctrl-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;}
99
+ .ctrl-btn{background:rgba(0,212,255,.06);border:1px solid rgba(0,212,255,.2);color:var(--accent);font-family:'Courier New',monospace;font-size:11px;letter-spacing:1px;text-transform:uppercase;padding:10px 6px;border-radius:3px;cursor:pointer;transition:all .2s;}
100
+ .ctrl-btn:hover{background:rgba(0,212,255,.14);border-color:rgba(0,212,255,.4);box-shadow:var(--glow);}
101
+ .ctrl-btn:active{transform:scale(.97);}
102
+ .ctrl-btn.danger-btn{background:rgba(255,71,87,.08);border-color:rgba(255,71,87,.3);color:var(--red);}
103
+ .ctrl-btn.danger-btn:hover{background:rgba(255,71,87,.2);border-color:var(--red);box-shadow:0 0 10px rgba(255,71,87,.4);}
104
+
105
+ /* ── Feature flags ── */
106
+ .flag-row{display:flex;align-items:center;justify-content:space-between;padding:9px 0;border-bottom:1px solid rgba(255,255,255,.04);font-size:12px;}
107
+ .flag-row:last-child{border-bottom:none;}
108
+ .flag-name{color:var(--text);}
109
+ .flag-desc{font-size:10px;color:var(--muted);margin-top:2px;}
110
+ .toggle-wrap{position:relative;display:inline-block;width:36px;height:20px;flex-shrink:0;}
111
+ .toggle-wrap input{opacity:0;width:0;height:0;}
112
+ .toggle-track{position:absolute;inset:0;border-radius:10px;background:rgba(255,255,255,.08);border:1px solid var(--border);cursor:pointer;transition:all .3s;}
113
+ .toggle-wrap input:checked + .toggle-track{background:rgba(0,212,255,.3);border-color:var(--accent);}
114
+ .toggle-knob{position:absolute;top:3px;left:3px;width:12px;height:12px;border-radius:50%;background:var(--muted);transition:all .3s;}
115
+ .toggle-wrap input:checked ~ .toggle-knob{left:19px;background:var(--accent);box-shadow:var(--glow);}
116
+
117
+ /* ── Interactive terminal ── */
118
+ .iterm{background:#010a12;border:1px solid var(--border);border-radius:3px;display:flex;flex-direction:column;height:300px;}
119
+ .iterm-out{flex:1;overflow-y:auto;padding:10px;font-size:11px;line-height:1.7;scrollbar-width:thin;scrollbar-color:var(--border) transparent;}
120
+ .iterm-out::-webkit-scrollbar{width:4px;}
121
+ .iterm-out::-webkit-scrollbar-track{background:transparent;}
122
+ .iterm-out::-webkit-scrollbar-thumb{background:var(--border);border-radius:2px;}
123
+ .iterm-in{display:flex;align-items:center;gap:6px;padding:8px 10px;border-top:1px solid var(--border);}
124
+ .iterm-prompt{color:var(--green);white-space:nowrap;font-size:11px;}
125
+ .iterm-input{flex:1;background:transparent;border:none;outline:none;color:var(--text);font-family:'Courier New',monospace;font-size:11px;caret-color:var(--accent);}
126
+ .t-cmd{color:var(--accent);}
127
+ .t-ok{color:var(--green);}
128
+ .t-err{color:var(--red);}
129
+ .t-muted{color:var(--muted);}
130
+ .t-warn{color:var(--yellow);}
131
+ .t-b{font-weight:bold;}
132
+
133
+ /* ── User table ── */
134
+ .user-table{width:100%;border-collapse:collapse;font-size:11px;}
135
+ .user-table th{color:var(--muted);font-weight:normal;text-align:left;padding:6px 8px;border-bottom:1px solid var(--border);letter-spacing:1px;font-size:10px;text-transform:uppercase;}
136
+ .user-table td{padding:7px 8px;border-bottom:1px solid rgba(255,255,255,.03);}
137
+ .user-table tr:last-child td{border-bottom:none;}
138
+ .user-table tr:hover td{background:rgba(255,255,255,.02);}
139
+ .u-status{font-size:10px;padding:2px 8px;border-radius:10px;}
140
+ .u-status.active{background:rgba(0,255,136,.1);color:var(--green);border:1px solid rgba(0,255,136,.2);}
141
+ .u-status.banned{background:rgba(255,71,87,.1);color:var(--red);border:1px solid rgba(255,71,87,.2);}
142
+ .u-status.idle{background:rgba(255,211,42,.08);color:var(--yellow);border:1px solid rgba(255,211,42,.15);}
143
+ .u-btn{background:transparent;border:1px solid var(--border);color:var(--muted);font-family:'Courier New',monospace;font-size:10px;padding:2px 8px;border-radius:2px;cursor:pointer;transition:all .2s;margin-left:4px;}
144
+ .u-btn:hover{color:var(--accent);border-color:var(--accent);}
145
+ .u-btn.ban-btn:hover{color:var(--red);border-color:var(--red);}
146
+ .u-btn.kick-btn:hover{color:var(--yellow);border-color:var(--yellow);}
147
+
148
+ /* ── Deploy pipeline ── */
149
+ .deploy-stages{display:flex;align-items:center;gap:0;margin:16px 0 10px;}
150
+ .stage{flex:1;text-align:center;position:relative;}
151
+ .stage-dot{width:28px;height:28px;border-radius:50%;border:2px solid var(--border);background:var(--bg);margin:0 auto 6px;display:flex;align-items:center;justify-content:center;font-size:11px;transition:all .5s;position:relative;z-index:1;}
152
+ .stage-dot.done{background:var(--green);border-color:var(--green);color:#000;box-shadow:0 0 10px rgba(0,255,136,.4);}
153
+ .stage-dot.active{background:rgba(0,212,255,.2);border-color:var(--accent);color:var(--accent);animation:pulse-ring .8s infinite;}
154
+ .stage-dot.fail{background:rgba(255,71,87,.2);border-color:var(--red);color:var(--red);}
155
+ @keyframes pulse-ring{0%,100%{box-shadow:0 0 0 0 rgba(0,212,255,.4);}50%{box-shadow:0 0 0 6px rgba(0,212,255,0);}}
156
+ .stage-label{font-size:9px;color:var(--muted);letter-spacing:.5px;}
157
+ .stage::before{content:'';position:absolute;top:14px;left:0;right:50%;height:2px;background:var(--border);z-index:0;}
158
+ .stage:first-child::before{display:none;}
159
+ .stage.done::before{background:var(--green);}
160
+ .deploy-log{background:#010a12;border:1px solid var(--border);border-radius:3px;padding:8px;font-size:10px;height:80px;overflow-y:auto;line-height:1.6;scrollbar-width:thin;scrollbar-color:var(--border) transparent;}
161
+ .deploy-controls{display:flex;gap:10px;margin-bottom:14px;}
162
+ .deploy-select{background:var(--bg);border:1px solid var(--border);color:var(--text);font-family:'Courier New',monospace;font-size:11px;padding:6px 10px;border-radius:3px;outline:none;cursor:pointer;}
163
+ .deploy-select:focus{border-color:var(--accent);}
164
+
165
+ /* ── Incidents ── */
166
+ .incident{background:rgba(255,255,255,.02);border:1px solid var(--border);border-radius:3px;padding:10px 12px;margin-bottom:8px;display:flex;align-items:flex-start;gap:10px;transition:all .3s;}
167
+ .incident.resolved{opacity:.35;}
168
+ .inc-badge{font-size:9px;font-weight:bold;padding:2px 6px;border-radius:2px;white-space:nowrap;margin-top:1px;}
169
+ .inc-badge.p1{background:rgba(255,71,87,.2);color:var(--red);border:1px solid rgba(255,71,87,.3);}
170
+ .inc-badge.p2{background:rgba(255,211,42,.15);color:var(--yellow);border:1px solid rgba(255,211,42,.25);}
171
+ .inc-badge.p3{background:rgba(0,212,255,.1);color:var(--accent);border:1px solid rgba(0,212,255,.2);}
172
+ .inc-body{flex:1;}
173
+ .inc-title{font-size:12px;color:var(--text);}
174
+ .inc-meta{font-size:10px;color:var(--muted);margin-top:2px;}
175
+ .inc-resolve{background:transparent;border:1px solid var(--border);color:var(--muted);font-family:'Courier New',monospace;font-size:10px;padding:3px 10px;border-radius:2px;cursor:pointer;white-space:nowrap;transition:all .2s;margin-top:2px;}
176
+ .inc-resolve:hover{color:var(--green);border-color:var(--green);}
177
+ .inc-done{font-size:10px;color:var(--green);margin-top:2px;}
178
+ .inc-list{max-height:280px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--border) transparent;}
179
+
180
+ /* ── Emergency modal ── */
181
+ .modal-bg{position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .3s;}
182
+ .modal-bg.open{opacity:1;pointer-events:all;}
183
+ .modal-box{background:#0a0f1a;border:2px solid var(--red);border-radius:6px;padding:32px 40px;max-width:420px;width:90%;text-align:center;box-shadow:0 0 40px rgba(255,71,87,.3);}
184
+ .modal-title{font-size:20px;color:var(--red);letter-spacing:3px;text-transform:uppercase;margin-bottom:8px;}
185
+ .modal-sub{color:var(--muted);font-size:12px;margin-bottom:24px;line-height:1.7;}
186
+ .modal-countdown{font-size:56px;color:var(--red);font-weight:bold;text-shadow:0 0 20px rgba(255,71,87,.6);margin-bottom:24px;font-variant-numeric:tabular-nums;}
187
+ .modal-abort{background:rgba(255,71,87,.1);border:2px solid var(--red);color:var(--red);font-family:'Courier New',monospace;font-size:14px;letter-spacing:2px;text-transform:uppercase;padding:12px 32px;border-radius:4px;cursor:pointer;transition:all .2s;width:100%;}
188
+ .modal-abort:hover{background:rgba(255,71,87,.25);box-shadow:0 0 15px rgba(255,71,87,.4);}
189
+
190
+ /* ── Toast ── */
191
+ .toast{position:fixed;bottom:24px;right:24px;background:var(--panel);border:1px solid var(--accent);color:var(--accent);font-family:'Courier New',monospace;font-size:12px;padding:12px 20px;border-radius:4px;box-shadow:var(--glow),0 4px 20px rgba(0,0,0,.5);opacity:0;transform:translateY(10px);transition:all .3s;z-index:400;pointer-events:none;max-width:360px;}
192
+ .toast.show{opacity:1;transform:translateY(0);}
193
+ .toast.toast-err{border-color:var(--red);color:var(--red);}
194
+ .toast.toast-ok{border-color:var(--green);color:var(--green);}
195
+
196
+ /* ── Spans ── */
197
+ .span-2{grid-column:span 2;}
198
+ .span-3{grid-column:span 3;}
199
+
200
+ /* ── Scrollbar global ── */
201
+ ::-webkit-scrollbar{width:4px;height:4px;}
202
+ ::-webkit-scrollbar-track{background:transparent;}
203
+ ::-webkit-scrollbar-thumb{background:var(--border);border-radius:2px;}
204
+ </style>
205
+ <link rel="icon" type="image/png" href="/assets/favicon.png">
206
+ </head>
207
+ <body>
208
+
209
+ <header class="cc-header">
210
+ <div class="cc-title">&#11041; MM Control Center</div>
211
+ <div class="cc-right">
212
+ <span><span class="status-dot"></span><span style="color:var(--green);font-size:11px;letter-spacing:1px;">ALL SYSTEMS OPERATIONAL</span></span>
213
+ <span>CLEARANCE: LEVEL 4</span>
214
+ <span class="cc-clock" id="cc-clock">--:--:--</span>
215
+ <a href="./browse.html" class="exit-btn">EXIT</a>
216
+ </div>
217
+ </header>
218
+
219
+ <div class="cc-grid">
220
+
221
+ <!-- System resources -->
222
+ <div class="panel">
223
+ <div class="scan-line"></div>
224
+ <div class="panel-title">&#11041; System Resources</div>
225
+ <div class="metric">
226
+ <div class="metric-header"><span class="metric-label">CPU LOAD</span><span class="metric-val" id="m-cpu">78%</span></div>
227
+ <div class="metric-bar"><div class="metric-fill warn" id="b-cpu" style="width:78%"></div></div>
228
+ </div>
229
+ <div class="metric">
230
+ <div class="metric-header"><span class="metric-label">MEMORY</span><span class="metric-val" id="m-mem">61%</span></div>
231
+ <div class="metric-bar"><div class="metric-fill" id="b-mem" style="width:61%"></div></div>
232
+ </div>
233
+ <div class="metric">
234
+ <div class="metric-header"><span class="metric-label">DISK I/O</span><span class="metric-val" id="m-io">31%</span></div>
235
+ <div class="metric-bar"><div class="metric-fill" id="b-io" style="width:31%"></div></div>
236
+ </div>
237
+ <div class="metric">
238
+ <div class="metric-header"><span class="metric-label">NETWORK TX</span><span class="metric-val" id="m-net">89%</span></div>
239
+ <div class="metric-bar"><div class="metric-fill danger" id="b-net" style="width:89%"></div></div>
240
+ </div>
241
+ <div class="sparkline" id="sparkline"></div>
242
+ </div>
243
+
244
+ <!-- Live metrics -->
245
+ <div class="panel">
246
+ <div class="panel-title">&#11041; Live Metrics</div>
247
+ <div class="stat-row">
248
+ <div class="stat-box"><span class="stat-number" id="s-sessions">892</span><div class="stat-label">Active Sessions</div></div>
249
+ <div class="stat-box"><span class="stat-number" id="s-rps">1,247</span><div class="stat-label">Requests / sec</div></div>
250
+ <div class="stat-box"><span class="stat-number" id="s-bw">4.2</span><div class="stat-label">Bandwidth GB/s</div></div>
251
+ <div class="stat-box"><span class="stat-number" id="s-latency">14</span><div class="stat-label">Avg Latency ms</div></div>
252
+ </div>
253
+ </div>
254
+
255
+ <!-- Security -->
256
+ <div class="panel">
257
+ <div class="panel-title">&#11041; Security Status</div>
258
+ <div class="sec-row"><span class="sec-key">Firewall</span><span class="sec-val">ACTIVE</span></div>
259
+ <div class="sec-row"><span class="sec-key">Encryption</span><span class="sec-val">AES-256-GCM</span></div>
260
+ <div class="sec-row"><span class="sec-key">Last Threat Scan</span><span class="sec-val" id="s-scan">0s ago</span></div>
261
+ <div class="sec-row"><span class="sec-key">Intrusion Attempts</span><span class="sec-val warn" id="s-attempts">3 blocked</span></div>
262
+ <div class="sec-row"><span class="sec-key">TLS Certificate</span><span class="sec-val">Valid (247 days)</span></div>
263
+ <div class="sec-row"><span class="sec-key">2FA Enforcement</span><span class="sec-val">ACTIVE</span></div>
264
+ <div class="sec-row"><span class="sec-key">Audit Log</span><span class="sec-val">STREAMING</span></div>
265
+ </div>
266
+
267
+ <!-- Activity log -->
268
+ <div class="panel span-2">
269
+ <div class="panel-title">&#11041; Live Activity Log</div>
270
+ <div class="log-scroll" id="activity-log"></div>
271
+ </div>
272
+
273
+ <!-- Geographic -->
274
+ <div class="panel">
275
+ <div class="panel-title">&#11041; Traffic by Region</div>
276
+ <div class="geo-row"><span class="geo-label">US</span><div class="geo-bar-wrap"><div class="geo-bar-fill" id="g-us" style="width:45%"></div></div><span class="geo-pct" id="gp-us">45%</span></div>
277
+ <div class="geo-row"><span class="geo-label">EU</span><div class="geo-bar-wrap"><div class="geo-bar-fill" id="g-eu" style="width:28%"></div></div><span class="geo-pct" id="gp-eu">28%</span></div>
278
+ <div class="geo-row"><span class="geo-label">AS</span><div class="geo-bar-wrap"><div class="geo-bar-fill" id="g-as" style="width:18%"></div></div><span class="geo-pct" id="gp-as">18%</span></div>
279
+ <div class="geo-row"><span class="geo-label">SA</span><div class="geo-bar-wrap"><div class="geo-bar-fill" id="g-sa" style="width:6%"></div></div><span class="geo-pct" id="gp-sa">6%</span></div>
280
+ <div class="geo-row"><span class="geo-label">OT</span><div class="geo-bar-wrap"><div class="geo-bar-fill" id="g-ot" style="width:3%"></div></div><span class="geo-pct" id="gp-ot">3%</span></div>
281
+ </div>
282
+
283
+ <!-- Edge nodes -->
284
+ <div class="panel span-3">
285
+ <div class="panel-title">&#11041; Edge Node Status <span style="color:var(--muted);font-size:9px;letter-spacing:1px;">CLICK TO RESTART NODE</span></div>
286
+ <div class="node-grid" id="node-grid"></div>
287
+ </div>
288
+
289
+ <!-- Interactive terminal -->
290
+ <div class="panel span-2">
291
+ <div class="panel-title">&#11041; System Shell <span style="color:var(--muted);font-size:9px;">type "help" for commands</span></div>
292
+ <div class="iterm" id="iterm">
293
+ <div class="iterm-out" id="iterm-out"></div>
294
+ <div class="iterm-in">
295
+ <span class="iterm-prompt">root@mm-sys:~#</span>
296
+ <input class="iterm-input" id="iterm-input" type="text" autocomplete="off" spellcheck="false" autofocus>
297
+ </div>
298
+ </div>
299
+ </div>
300
+
301
+ <!-- Feature flags -->
302
+ <div class="panel">
303
+ <div class="panel-title">&#11041; Feature Flags</div>
304
+ <div id="flag-list"></div>
305
+ </div>
306
+
307
+ <!-- User management -->
308
+ <div class="panel span-2">
309
+ <div class="panel-title">&#11041; User Management</div>
310
+ <div style="overflow-x:auto;">
311
+ <table class="user-table">
312
+ <thead>
313
+ <tr>
314
+ <th>User</th><th>Last Active</th><th>Sessions</th><th>Status</th><th>Actions</th>
315
+ </tr>
316
+ </thead>
317
+ <tbody id="user-tbody"></tbody>
318
+ </table>
319
+ </div>
320
+ </div>
321
+
322
+ <!-- Incidents -->
323
+ <div class="panel">
324
+ <div class="panel-title">&#11041; Incident Tracker <span id="inc-count" style="color:var(--red);font-size:9px;"></span></div>
325
+ <div class="inc-list" id="inc-list"></div>
326
+ </div>
327
+
328
+ <!-- Deployment pipeline -->
329
+ <div class="panel span-2">
330
+ <div class="panel-title">&#11041; Deployment Pipeline</div>
331
+ <div class="deploy-controls">
332
+ <select class="deploy-select" id="deploy-branch">
333
+ <option>main (v0.0.1)</option>
334
+ <option>release/3.8-hotfix</option>
335
+ <option>staging/beta-features</option>
336
+ </select>
337
+ <select class="deploy-select" id="deploy-env">
338
+ <option>Production</option>
339
+ <option>Staging</option>
340
+ <option>Edge Preview</option>
341
+ </select>
342
+ <button class="ctrl-btn" id="deploy-btn" onclick="startDeploy()" style="flex-shrink:0;padding:6px 20px;">Deploy</button>
343
+ </div>
344
+ <div class="deploy-stages" id="deploy-stages"></div>
345
+ <div class="deploy-log" id="deploy-log"></div>
346
+ </div>
347
+
348
+ <!-- System controls -->
349
+ <div class="panel">
350
+ <div class="panel-title">&#11041; System Controls</div>
351
+ <div class="ctrl-grid">
352
+ <button class="ctrl-btn" onclick="toast('Cache flushed — 2.1 GB reclaimed','ok')">Flush Cache</button>
353
+ <button class="ctrl-btn" onclick="toast('Keys rotated. Next in 24h','ok')">Rotate Keys</button>
354
+ <button class="ctrl-btn" onclick="toast('Export queued — 2,847 records','ok')">Export Logs</button>
355
+ <button class="ctrl-btn" onclick="toast('CDN purge across 47 PoPs','ok')">Purge CDN</button>
356
+ <button class="ctrl-btn" onclick="toast('Health check: 47/47 OK','ok')">Health Check</button>
357
+ <button class="ctrl-btn danger-btn" onclick="openShutdown()">Emergency Shutdown</button>
358
+ </div>
359
+ </div>
360
+
361
+ </div>
362
+
363
+ <!-- Emergency shutdown modal -->
364
+ <div class="modal-bg" id="shutdown-modal">
365
+ <div class="modal-box">
366
+ <div class="modal-title">Emergency Shutdown</div>
367
+ <div class="modal-sub">All services will be terminated.<br>Active sessions will be dropped.<br>This cannot be undone.</div>
368
+ <div class="modal-countdown" id="shutdown-countdown">10</div>
369
+ <button class="modal-abort" onclick="abortShutdown()">ABORT SHUTDOWN</button>
370
+ </div>
371
+ </div>
372
+
373
+ <div class="toast" id="toast-el"></div>
374
+
375
+ <script>
376
+ // ── Helpers ────────────────────────────────────────────────────────────────
377
+ function rand(a,b){return Math.floor(Math.random()*(b-a+1))+a;}
378
+ function randF(a,b){return (Math.random()*(b-a)+a).toFixed(1);}
379
+ function now(){return new Date().toLocaleTimeString('en-US',{hour12:false});}
380
+
381
+ // ── Clock ─────────────────────────────────────────────────────────────────
382
+ setInterval(function(){document.getElementById('cc-clock').textContent=now();},1000);
383
+ document.getElementById('cc-clock').textContent=now();
384
+
385
+ // ── Toast ─────────────────────────────────────────────────────────────────
386
+ var toastTimer;
387
+ function toast(msg,type){
388
+ var el=document.getElementById('toast-el');
389
+ el.textContent='> '+msg;
390
+ el.className='toast show'+(type==='err'?' toast-err':type==='ok'?' toast-ok':'');
391
+ clearTimeout(toastTimer);
392
+ toastTimer=setTimeout(function(){el.classList.remove('show');},3200);
393
+ }
394
+
395
+ // ── Sparkline ─────────────────────────────────────────────────────────────
396
+ var sparks=[];for(var i=0;i<20;i++)sparks.push(rand(30,90));
397
+ function renderSpark(){
398
+ var max=Math.max.apply(null,sparks);
399
+ document.getElementById('sparkline').innerHTML=sparks.map(function(v){
400
+ return '<div class="spark-bar" style="height:'+(v/max*100)+'%"></div>';
401
+ }).join('');
402
+ }
403
+ renderSpark();
404
+
405
+ // ── System metrics ─────────────────────────────────────────────────────────
406
+ function updateMetrics(){
407
+ var cpu=rand(52,94),mem=rand(44,78),io=rand(12,65),net=rand(68,97);
408
+ document.getElementById('m-cpu').textContent=cpu+'%';
409
+ document.getElementById('m-mem').textContent=mem+'%';
410
+ document.getElementById('m-io').textContent=io+'%';
411
+ document.getElementById('m-net').textContent=net+'%';
412
+ document.getElementById('b-cpu').style.width=cpu+'%';
413
+ document.getElementById('b-mem').style.width=mem+'%';
414
+ document.getElementById('b-io').style.width=io+'%';
415
+ document.getElementById('b-net').style.width=net+'%';
416
+ document.getElementById('b-cpu').className='metric-fill'+(cpu>85?' danger':cpu>68?' warn':'');
417
+ document.getElementById('b-mem').className='metric-fill'+(mem>75?' warn':'');
418
+ document.getElementById('b-net').className='metric-fill'+(net>90?' danger':net>78?' warn':'');
419
+ document.getElementById('s-sessions').textContent=rand(780,1250).toLocaleString();
420
+ document.getElementById('s-rps').textContent=rand(900,1700).toLocaleString();
421
+ document.getElementById('s-bw').textContent=randF(1.8,7.2);
422
+ document.getElementById('s-latency').textContent=rand(7,38);
423
+ sparks.push(cpu);sparks.shift();renderSpark();
424
+ }
425
+ updateMetrics();
426
+ setInterval(updateMetrics,2200);
427
+
428
+ // ── Scan timer ────────────────────────────────────────────────────────────
429
+ var scanSecs=0;
430
+ setInterval(function(){
431
+ scanSecs++;
432
+ document.getElementById('s-scan').textContent=scanSecs<60?scanSecs+'s ago':Math.floor(scanSecs/60)+'m ago';
433
+ if(scanSecs>=45)scanSecs=0;
434
+ },1000);
435
+
436
+ var attempts=3;
437
+ setInterval(function(){
438
+ if(Math.random()<0.12){attempts++;document.getElementById('s-attempts').textContent=attempts+' blocked';}
439
+ },3500);
440
+
441
+ // ── Activity log ──────────────────────────────────────────────────────────
442
+ var logTpls=[
443
+ ['ok','GET /api/games 200 12ms'],['ok','Session validated uid:'],
444
+ ['info','Cache hit ratio: '],['ok','Game loaded: '],
445
+ ['info','CDN refresh: edge-'],['ok','Heartbeat OK: db.primary'],
446
+ ['warn','Rate limit hit: '],['ok','Auth success: session created'],
447
+ ['info','TLS 1.3 handshake 8ms'],['ok','Asset served 304: logo.png'],
448
+ ['info','Replication lag: '],['ok','Health check: 47/47 OK'],
449
+ ['warn','Retry #1: edge-'],['ok','Queue drained: 0 pending'],
450
+ ['ok','Backup completed: '],['info','GeoIP lookup: '],
451
+ ];
452
+ var lgames=['Tetris','Snake','Pac-Man','Chess','2048','Pong','Breakout','Asteroids','Minesweeper'];
453
+ var lnodes=['nyc-01','lax-02','lhr-01','ams-01','sin-01'];
454
+ var lips=['142.250.','104.21.','172.67.','185.60.','213.133.'];
455
+ function rndLine(){
456
+ var t=logTpls[Math.floor(Math.random()*logTpls.length)];
457
+ var type=t[0],text=t[1];
458
+ if(text.includes('uid:'))text+=Math.random().toString(36).slice(2,10);
459
+ if(text.includes('Cache hit ratio: '))text+=rand(91,99)+'%';
460
+ if(text.includes('Game loaded: '))text+=lgames[Math.floor(Math.random()*lgames.length)];
461
+ if(text.includes('CDN refresh: edge-'))text+=lnodes[Math.floor(Math.random()*lnodes.length)];
462
+ if(text.includes('Rate limit hit: '))text+=lips[Math.floor(Math.random()*lips.length)]+rand(1,255)+'.'+rand(1,254);
463
+ if(text.includes('Replication lag: '))text+=rand(0,4)+'ms';
464
+ if(text.includes('Retry #1: edge-'))text+=lnodes[Math.floor(Math.random()*lnodes.length)];
465
+ if(text.includes('Backup completed: '))text+=randF(0.8,3.4)+'GB';
466
+ if(text.includes('GeoIP lookup: '))text+=lips[Math.floor(Math.random()*lips.length)]+rand(1,255)+'.'+rand(1,254);
467
+ return{type:type,text:text};
468
+ }
469
+ var actLog=document.getElementById('activity-log');
470
+ var actLines=[];
471
+ function addLog(){
472
+ var e=rndLine();
473
+ var d=document.createElement('div');
474
+ d.className='log-line';
475
+ d.innerHTML='<span class="log-time">'+now()+'</span> <span class="log-'+e.type+'">'+e.text+'</span>';
476
+ actLines.push(d);
477
+ if(actLines.length>20){actLines[0].remove();actLines.shift();}
478
+ actLog.appendChild(d);
479
+ }
480
+ for(var i=0;i<14;i++)addLog();
481
+ setInterval(addLog,750);
482
+
483
+ // ── Geo drift ─────────────────────────────────────────────────────────────
484
+ function updateGeo(){
485
+ var base=[45,28,18,6,3],total=0;
486
+ var vals=base.map(function(v){return Math.max(1,v+rand(-3,3));});
487
+ vals.forEach(function(v){total+=v;});
488
+ ['us','eu','as','sa','ot'].forEach(function(k,i){
489
+ var p=Math.round(vals[i]/total*100);
490
+ document.getElementById('g-'+k).style.width=p+'%';
491
+ document.getElementById('gp-'+k).textContent=p+'%';
492
+ });
493
+ }
494
+ setInterval(updateGeo,4000);
495
+
496
+ // ── Edge nodes ────────────────────────────────────────────────────────────
497
+ var nodeNames=['NYC-01','NYC-02','LAX-01','LAX-02','ORD-01','MIA-01','LHR-01','LHR-02',
498
+ 'AMS-01','FRA-01','SIN-01','SYD-01','NRT-01','GRU-01','JNB-01','DXB-01'];
499
+ function renderNodes(){
500
+ document.getElementById('node-grid').innerHTML=nodeNames.map(function(name){
501
+ var r=Math.random();
502
+ var cls=r<0.06?'node warn':r<0.015?'node down':'node';
503
+ return '<div class="'+cls+'" onclick="restartNode(this,\''+name+'\')">'+name+'</div>';
504
+ }).join('');
505
+ }
506
+ renderNodes();
507
+ setInterval(renderNodes,7000);
508
+ function restartNode(el,name){
509
+ el.style.opacity='.3';
510
+ el.textContent='...';
511
+ setTimeout(function(){
512
+ el.style.opacity='1';
513
+ el.className='node';
514
+ el.textContent=name;
515
+ toast(name+' restarted successfully','ok');
516
+ },1800);
517
+ }
518
+
519
+ // ── Feature flags ─────────────────────────────────────────────────────────
520
+ var flags=[
521
+ {id:'ff-maintenance',label:'Maintenance Mode',desc:'Show maintenance page to users',on:false},
522
+ {id:'ff-beta',label:'Beta Features',desc:'Enable experimental UI elements',on:true},
523
+ {id:'ff-analytics',label:'Analytics Tracking',desc:'User behaviour telemetry',on:true},
524
+ {id:'ff-ratelimit',label:'Rate Limiting',desc:'Throttle requests per IP',on:true},
525
+ {id:'ff-cdn',label:'CDN Cache',desc:'Serve assets from edge cache',on:true},
526
+ {id:'ff-debug',label:'Debug Logging',desc:'Verbose server-side logs',on:false},
527
+ ];
528
+ var flagList=document.getElementById('flag-list');
529
+ flags.forEach(function(f){
530
+ var row=document.createElement('div');
531
+ row.className='flag-row';
532
+ row.innerHTML='<div><div class="flag-name">'+f.label+'</div><div class="flag-desc">'+f.desc+'</div></div>'
533
+ +'<label class="toggle-wrap"><input type="checkbox" id="'+f.id+'"'+(f.on?' checked':'')+'>'
534
+ +'<div class="toggle-track"></div><div class="toggle-knob"></div></label>';
535
+ flagList.appendChild(row);
536
+ row.querySelector('input').addEventListener('change',function(){
537
+ toast(f.label+': '+(this.checked?'ENABLED':'DISABLED'),this.checked?'ok':'err');
538
+ });
539
+ });
540
+
541
+ // ── User management ───────────────────────────────────────────────────────
542
+ var users=[
543
+ {name:'sys_root', last:'just now', sessions:3, status:'active'},
544
+ {name:'dev_rafi', last:'2m ago', sessions:1, status:'active'},
545
+ {name:'tzvi_admin', last:'8m ago', sessions:2, status:'active'},
546
+ {name:'test_user', last:'34m ago', sessions:0, status:'idle'},
547
+ {name:'guest_4821', last:'1h ago', sessions:0, status:'idle'},
548
+ {name:'anon_proxy', last:'3h ago', sessions:0, status:'banned'},
549
+ {name:'scraper_bot',last:'12h ago', sessions:0, status:'banned'},
550
+ {name:'yael.k', last:'yesterday', sessions:1, status:'active'},
551
+ ];
552
+ function renderUsers(){
553
+ var tbody=document.getElementById('user-tbody');
554
+ tbody.innerHTML=users.map(function(u,i){
555
+ var isBanned=u.status==='banned';
556
+ return '<tr>'
557
+ +'<td style="color:var(--accent)">'+u.name+'</td>'
558
+ +'<td style="color:var(--muted)">'+u.last+'</td>'
559
+ +'<td style="color:var(--muted)">'+u.sessions+'</td>'
560
+ +'<td><span class="u-status '+u.status+'">'+u.status.toUpperCase()+'</span></td>'
561
+ +'<td>'
562
+ +(isBanned
563
+ ?'<button class="u-btn" onclick="unbanUser('+i+')">Unban</button>'
564
+ :'<button class="u-btn ban-btn" onclick="banUser('+i+')">Ban</button>'
565
+ +'<button class="u-btn kick-btn" onclick="kickUser('+i+')">Kick</button>'
566
+ )
567
+ +'</td></tr>';
568
+ }).join('');
569
+ }
570
+ renderUsers();
571
+ function banUser(i){
572
+ users[i].status='banned';users[i].sessions=0;
573
+ renderUsers();toast('User '+users[i].name+' banned','err');
574
+ }
575
+ function unbanUser(i){
576
+ users[i].status='idle';
577
+ renderUsers();toast('User '+users[i].name+' unbanned','ok');
578
+ }
579
+ function kickUser(i){
580
+ var prev=users[i].sessions;
581
+ users[i].sessions=0;
582
+ renderUsers();toast('Kicked '+users[i].name+' ('+prev+' session'+(prev!==1?'s':'')+' terminated)','ok');
583
+ }
584
+
585
+ // ── Incidents ─────────────────────────────────────────────────────────────
586
+ var incidentTemplates=[
587
+ {sev:'p1',title:'Database primary unreachable',detail:'db.primary failed health check'},
588
+ {sev:'p1',title:'API error rate spike: 18%',detail:'Elevated 5xx across /api/games'},
589
+ {sev:'p2',title:'CDN edge timeout: AMS-01',detail:'Latency >2s detected on edge node'},
590
+ {sev:'p2',title:'Memory pressure on LAX-02',detail:'RSS at 91%, swap engaged'},
591
+ {sev:'p2',title:'SSL cert renewal required',detail:'cert.mm.games expires in 14 days'},
592
+ {sev:'p3',title:'Backup job delayed',detail:'Scheduled backup ran 22min late'},
593
+ {sev:'p3',title:'Search index stale',detail:'Last indexed 47 minutes ago'},
594
+ {sev:'p3',title:'Log storage at 78%',detail:'/var/log nearing capacity threshold'},
595
+ ];
596
+ var incidents=[];
597
+ function pickIncident(){
598
+ var unused=incidentTemplates.filter(function(t){
599
+ return !incidents.some(function(inc){return inc.title===t.title&&!inc.resolved;});
600
+ });
601
+ if(!unused.length)return null;
602
+ return unused[Math.floor(Math.random()*unused.length)];
603
+ }
604
+ function addIncident(){
605
+ var tpl=pickIncident();
606
+ if(!tpl)return;
607
+ incidents.unshift({sev:tpl.sev,title:tpl.title,detail:tpl.detail,time:now(),resolved:false,id:'inc-'+Date.now()});
608
+ renderIncidents();
609
+ }
610
+ function renderIncidents(){
611
+ var list=document.getElementById('inc-list');
612
+ var open=incidents.filter(function(i){return!i.resolved;}).length;
613
+ document.getElementById('inc-count').textContent=open?open+' OPEN':'';
614
+ list.innerHTML=incidents.map(function(inc){
615
+ return '<div class="incident'+(inc.resolved?' resolved':'')+'" id="'+inc.id+'">'
616
+ +'<span class="inc-badge '+inc.sev+'">'+inc.sev.toUpperCase()+'</span>'
617
+ +'<div class="inc-body">'
618
+ +'<div class="inc-title">'+inc.title+'</div>'
619
+ +'<div class="inc-meta">'+inc.detail+' &nbsp;·&nbsp; '+inc.time+'</div>'
620
+ +(inc.resolved
621
+ ?'<div class="inc-done">Resolved</div>'
622
+ :'<button class="inc-resolve" onclick="resolveInc(\''+inc.id+'\')">Mark Resolved</button>'
623
+ )
624
+ +'</div></div>';
625
+ }).join('');
626
+ }
627
+ function resolveInc(id){
628
+ var inc=incidents.find(function(i){return i.id===id;});
629
+ if(inc){inc.resolved=true;renderIncidents();toast('Incident resolved','ok');}
630
+ }
631
+ addIncident();addIncident();addIncident();
632
+ setInterval(function(){if(Math.random()<0.25)addIncident();},15000);
633
+
634
+ // ── Deployment pipeline ───────────────────────────────────────────────────
635
+ var stageNames=['Init','Build','Test','Stage','Deploy','CDN','Done'];
636
+ var deployRunning=false;
637
+ function renderStages(activeIdx,failIdx){
638
+ document.getElementById('deploy-stages').innerHTML=stageNames.map(function(s,i){
639
+ var cls='stage';
640
+ if(typeof failIdx!=='undefined'&&i===failIdx)cls+=' fail';
641
+ else if(i<activeIdx)cls+=' done';
642
+ else if(i===activeIdx)cls+=' active';
643
+ var dotCls='stage-dot';
644
+ if(typeof failIdx!=='undefined'&&i===failIdx)dotCls+=' fail';
645
+ else if(i<activeIdx)dotCls+=' done';
646
+ else if(i===activeIdx)dotCls+=' active';
647
+ var icon=i<activeIdx?'✓':i===activeIdx&&typeof failIdx==='undefined'?'◉':failIdx===i?'✕':'·';
648
+ return '<div class="'+cls+'"><div class="'+dotCls+'">'+icon+'</div><div class="stage-label">'+s+'</div></div>';
649
+ }).join('');
650
+ }
651
+ var deployLogLines=[];
652
+ function dlog(msg,type){
653
+ var el=document.getElementById('deploy-log');
654
+ var d=document.createElement('div');
655
+ d.innerHTML='<span style="color:var(--muted)">'+now()+'</span> <span class="t-'+(type||'muted')+'">'+msg+'</span>';
656
+ el.appendChild(d);
657
+ el.scrollTop=el.scrollHeight;
658
+ }
659
+ renderStages(0);
660
+ dlog('No active deployment. Select branch and environment to begin.','muted');
661
+
662
+ function startDeploy(){
663
+ if(deployRunning)return;
664
+ deployRunning=true;
665
+ var btn=document.getElementById('deploy-btn');
666
+ btn.disabled=true;btn.textContent='Running...';
667
+ var branch=document.getElementById('deploy-branch').value;
668
+ var env=document.getElementById('deploy-env').value;
669
+ document.getElementById('deploy-log').innerHTML='';
670
+ var step=0;
671
+ var msgs=[
672
+ ['Initializing deployment context...','info'],
673
+ ['Pulling '+branch+'...','info'],
674
+ ['Installing dependencies (847 packages)...','info'],
675
+ ['Running test suite (312 tests)...','info'],
676
+ ['All tests passed.','ok'],
677
+ ['Bundling assets...','info'],
678
+ ['Uploading to '+env+'...','info'],
679
+ ['Running migrations...','info'],
680
+ ['Flushing CDN cache across 47 PoPs...','info'],
681
+ ['Smoke tests passed.','ok'],
682
+ ['Deployment complete.','ok'],
683
+ ];
684
+ var stageTimes=[0,600,1200,2000,2600,3200,3800,4500,5200,5800,6400];
685
+ renderStages(0);
686
+ msgs.forEach(function(m,i){
687
+ setTimeout(function(){
688
+ var s=Math.min(Math.floor(i/msgs.length*stageNames.length),stageNames.length-1);
689
+ renderStages(s);
690
+ dlog(m[0],m[1]);
691
+ if(i===msgs.length-1){
692
+ setTimeout(function(){
693
+ renderStages(stageNames.length);
694
+ deployRunning=false;
695
+ btn.disabled=false;btn.textContent='Deploy';
696
+ toast('Deployed '+branch+' to '+env,'ok');
697
+ },400);
698
+ }
699
+ },stageTimes[i]);
700
+ });
701
+ }
702
+
703
+ // ── Interactive shell ──────────────────────────────────────────────────────
704
+ var itermOut=document.getElementById('iterm-out');
705
+ var itermInput=document.getElementById('iterm-input');
706
+ var cmdHistory=[];
707
+ var histIdx=-1;
708
+
709
+ function tprint(html){
710
+ var d=document.createElement('div');
711
+ d.innerHTML=html;
712
+ itermOut.appendChild(d);
713
+ itermOut.scrollTop=itermOut.scrollHeight;
714
+ }
715
+
716
+ tprint('<span class="t-ok">MM Systems Shell v0.0.1</span>');
717
+ tprint('<span class="t-muted">Type <span class="t-cmd">help</span> for available commands.</span>');
718
+ tprint('');
719
+
720
+ var shellCmds={
721
+ help:function(){
722
+ tprint('<span class="t-ok">Available commands:</span>');
723
+ [['ls','List directory contents'],['ps','Show running processes'],
724
+ ['top','System resource snapshot'],['df','Disk usage'],
725
+ ['netstat','Network connections'],['uptime','System uptime'],
726
+ ['whoami','Current user'],['ping','Ping a host (e.g. ping 8.8.8.8)'],
727
+ ['curl','HTTP request (e.g. curl api/status)'],['cat','Read a file'],
728
+ ['kill','Kill a process (e.g. kill 3821)'],['history','Command history'],
729
+ ['clear','Clear terminal']].forEach(function(c){
730
+ tprint(' <span class="t-cmd">'+c[0]+'</span><span class="t-muted" style="margin-left:16px">'+c[1]+'</span>');
731
+ });
732
+ },
733
+ ls:function(args){
734
+ var path=args||'/var/www/moshelab';
735
+ tprint('<span class="t-muted">total 248</span>');
736
+ [['drwxr-xr-x','2','root','root','4096','May 7 18:31','api.js'],
737
+ ['drwxr-xr-x','2','root','root','4096','May 7 18:31','games.json'],
738
+ ['-rw-r--r--','1','root','root','12481','May 6 09:12','browse.html'],
739
+ ['-rw-r--r--','1','root','root','8902','May 6 09:12','admin.html'],
740
+ ['-rw-r--r--','1','root','root','6190','May 6 09:12','game.html'],
741
+
742
+ ['drwxr-xr-x','4','root','root','4096','May 6 09:12','css/'],
743
+ ['drwxr-xr-x','4','root','root','4096','May 6 09:12','js/'],
744
+ ['drwxr-xr-x','8','root','root','4096','May 5 14:22','assets/'],
745
+ ['drwxr-xr-x','3','root','root','4096','May 4 11:08','local-games/'],
746
+ ].forEach(function(r){
747
+ tprint('<span class="t-muted">'+r[0]+' '+r[1]+' '+r[2]+' '+r[3]+'</span> <span class="t-ok">'+r[4]+'</span> <span class="t-muted">'+r[5]+'</span> <span style="color:var(--text)">'+r[6]+'</span>');
748
+ });
749
+ },
750
+ ps:function(){
751
+ tprint('<span class="t-muted">USER PID %CPU %MEM COMMAND</span>');
752
+ [['root','1','0.0','0.1','init'],['root','312','0.0','0.2','systemd'],
753
+ ['www','1842','2.1','3.4','node api.js'],['www','1843','0.8','2.1','nginx: worker'],
754
+ ['www','1844','0.8','2.1','nginx: worker'],['www','2041','0.1','0.8','node monitor.js'],
755
+ ['root','3218','0.0','0.1','sshd'],['root',String(rand(3800,4200)),'0.0','0.1','cron'],
756
+ ['www',String(rand(4500,5000)),'4.1','5.2','node games-cache.js'],
757
+ ].forEach(function(r){
758
+ tprint('<span class="t-muted">'+r[0]+'</span> <span class="t-ok">'+r[1]+'</span> '+r[2]+' '+r[3]+' <span style="color:var(--text)">'+r[4]+'</span>');
759
+ });
760
+ },
761
+ top:function(){
762
+ tprint('<span class="t-ok">top — '+now()+' up 12 days, 4:32</span>');
763
+ tprint('<span class="t-muted">Tasks: 84 total, 2 running, 82 sleeping</span>');
764
+ tprint('<span class="t-muted">%Cpu(s): '+rand(40,80)+'.'+rand(0,9)+' us, '+rand(2,8)+'.'+rand(0,9)+' sy</span>');
765
+ tprint('<span class="t-muted">MiB Mem: 7892.0 total, '+rand(1200,2400)+'.0 free</span>');
766
+ },
767
+ df:function(){
768
+ tprint('<span class="t-muted">Filesystem Size Used Avail Use% Mounted on</span>');
769
+ tprint('<span class="t-muted">/dev/sda1 80G '+rand(30,55)+'G '+rand(20,40)+'G '+rand(42,72)+'% /</span>');
770
+ tprint('<span class="t-muted">/dev/sda2 40G '+rand(10,20)+'G '+rand(15,25)+'G '+rand(28,55)+'% /var</span>');
771
+ tprint('<span class="t-muted">tmpfs 3.9G 128M 3.8G 4% /tmp</span>');
772
+ },
773
+ uptime:function(){
774
+ tprint('<span class="t-ok">'+now()+'</span> <span class="t-muted">up 12 days, 4:32, 2 users, load average: '+randF(0.4,2.8)+', '+randF(0.3,2.1)+', '+randF(0.2,1.8)+'</span>');
775
+ },
776
+ whoami:function(){tprint('<span class="t-ok">root</span>');},
777
+ netstat:function(){
778
+ tprint('<span class="t-muted">Active Internet connections</span>');
779
+ tprint('<span class="t-muted">Proto Recv-Q Send-Q Local Address Foreign Address State</span>');
780
+ for(var n=0;n<6;n++){
781
+ tprint('<span class="t-muted">tcp 0 0 0.0.0.0:443 '+rand(10,250)+'.'+rand(0,255)+'.'+rand(0,255)+'.'+rand(1,254)+':'+rand(1024,65535)+' ESTABLISHED</span>');
782
+ }
783
+ tprint('<span class="t-muted">tcp 0 0 127.0.0.1:3001 0.0.0.0:* LISTEN</span>');
784
+ tprint('<span class="t-muted">tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN</span>');
785
+ tprint('<span class="t-muted">tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN</span>');
786
+ },
787
+ clear:function(){itermOut.innerHTML='';},
788
+ history:function(){
789
+ cmdHistory.forEach(function(c,i){
790
+ tprint('<span class="t-muted">'+(i+1)+' </span><span style="color:var(--text)">'+c+'</span>');
791
+ });
792
+ },
793
+ };
794
+
795
+ function execCmd(raw){
796
+ var parts=raw.trim().split(/\s+/);
797
+ var cmd=parts[0].toLowerCase();
798
+ var args=parts.slice(1).join(' ');
799
+ tprint('<span class="t-muted">root@mm-sys:~#</span> <span style="color:var(--text)">'+raw+'</span>');
800
+ if(!cmd)return;
801
+ if(shellCmds[cmd]){shellCmds[cmd](args);return;}
802
+ if(cmd==='ping'){
803
+ var host=args||'8.8.8.8';
804
+ tprint('PING '+host+': 56 data bytes');
805
+ var pings=0;
806
+ var pi=setInterval(function(){
807
+ tprint('64 bytes from '+host+': icmp_seq='+pings+' ttl=55 time='+randF(8,42)+' ms');
808
+ pings++;
809
+ if(pings>=4){clearInterval(pi);tprint('--- '+host+' ping statistics ---');tprint('4 packets transmitted, 4 received, 0% packet loss');}
810
+ },300);
811
+ return;
812
+ }
813
+ if(cmd==='curl'){
814
+ tprint('<span class="t-muted">HTTP/1.1 200 OK</span>');
815
+ tprint('<span class="t-muted">Content-Type: application/json</span>');
816
+ tprint('<span class="t-ok">{"status":"ok","version":"3.9.0","uptime":'+rand(800000,1200000)+'}</span>');
817
+ return;
818
+ }
819
+ if(cmd==='cat'){
820
+ if(args.includes('passwd')){
821
+ tprint('root:x:0:0:root:/root:/bin/bash');
822
+ tprint('www-data:x:33:33::/var/www:/bin/sh');
823
+ tprint('node:x:1001:1001::/home/node:/bin/bash');
824
+ } else if(args.includes('hosts')){
825
+ tprint('127.0.0.1 localhost');tprint('127.0.1.1 mm-sys');
826
+ tprint('127.0.0.1 db.primary');tprint('10.0.0.4 cache.internal');
827
+ } else {
828
+ tprint('<span class="t-err">cat: '+args+': No such file or directory</span>');
829
+ }
830
+ return;
831
+ }
832
+ if(cmd==='kill'){
833
+ var pid=parseInt(args);
834
+ if(!pid||isNaN(pid)){tprint('<span class="t-err">kill: '+args+': not a valid PID</span>');}
835
+ else{tprint('<span class="t-ok">Process '+pid+' terminated.</span>');}
836
+ return;
837
+ }
838
+ if(cmd==='exit'||cmd==='logout'){window.location.href='./browse.html';return;}
839
+ tprint('<span class="t-err">'+cmd+': command not found</span>');
840
+ }
841
+
842
+ itermInput.addEventListener('keydown',function(e){
843
+ if(e.key==='Enter'){
844
+ var val=this.value.trim();
845
+ if(val){cmdHistory.push(val);histIdx=cmdHistory.length;}
846
+ execCmd(val);
847
+ this.value='';
848
+ } else if(e.key==='ArrowUp'){
849
+ e.preventDefault();
850
+ if(histIdx>0){histIdx--;this.value=cmdHistory[histIdx];}
851
+ } else if(e.key==='ArrowDown'){
852
+ e.preventDefault();
853
+ if(histIdx<cmdHistory.length-1){histIdx++;this.value=cmdHistory[histIdx];}
854
+ else{histIdx=cmdHistory.length;this.value='';}
855
+ }
856
+ });
857
+
858
+ // keep focus in terminal when clicking panel
859
+ document.getElementById('iterm').addEventListener('click',function(){itermInput.focus();});
860
+
861
+ // ── Emergency shutdown ────────────────────────────────────────────────────
862
+ var shutdownTimer,shutdownCount;
863
+ function openShutdown(){
864
+ shutdownCount=10;
865
+ document.getElementById('shutdown-countdown').textContent=shutdownCount;
866
+ document.getElementById('shutdown-modal').classList.add('open');
867
+ shutdownTimer=setInterval(function(){
868
+ shutdownCount--;
869
+ document.getElementById('shutdown-countdown').textContent=shutdownCount;
870
+ if(shutdownCount<=0){
871
+ clearInterval(shutdownTimer);
872
+ document.getElementById('shutdown-modal').classList.remove('open');
873
+ toast('SHUTDOWN SEQUENCE COMPLETED — All services terminated','err');
874
+ }
875
+ },1000);
876
+ }
877
+ function abortShutdown(){
878
+ clearInterval(shutdownTimer);
879
+ document.getElementById('shutdown-modal').classList.remove('open');
880
+ toast('Shutdown aborted. Systems remain online.','ok');
881
+ }
882
+ </script>
883
+
884
+ </body>
885
+ </html>