2026-07-18 22:37:48 +02:00
<!DOCTYPE html>
< html lang = "en" >
< head >
2026-07-28 23:39:24 +02:00
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > Carolyn Dail — Ops Triage Desk< / title >
2026-07-18 22:37:48 +02:00
< style >
2026-07-28 23:39:24 +02:00
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500;600&family=IBM+Plex+Serif:wght@400; 600;700&display=swap');
:root {
--bg: #0a0a0a;
--fg: #33ff33;
--fg-dim: #1a9e1a;
--fg-muted: #0d5e0d;
--accent: #ff6633;
--border: #1a9e1a;
--card-bg: #0f1a0f;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: var(--bg);
color: var(--fg);
font-family: 'IBM Plex Mono', 'Courier New', monospace;
font-size: 14px;
line-height: 1.6;
min-height: 100vh;
padding: 0;
}
::selection { background: var(--fg-muted); color: var(--bg); }
/* HEADER — terminal bar */
.terminal-bar {
background: #0d1a0d;
border-bottom: 1px solid var(--border);
padding: 8px 20px;
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: var(--fg-dim);
}
.terminal-bar .dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
.terminal-bar .red { background: #ff5f56; }
.terminal-bar .yellow { background: #ffbd2e; }
.terminal-bar .green { background: #27c93f; }
.terminal-bar .title { margin-left: 12px; font-weight: 500; }
/* MAIN LAYOUT */
.container {
max-width: 900px;
margin: 0 auto;
padding: 20px;
}
/* HERO */
.hero {
border: 1px solid var(--border);
padding: 30px;
margin-bottom: 20px;
position: relative;
}
.hero::before {
content: 'carolyn-dail.4ort.net ~ $ whoami';
display: block;
color: var(--fg-muted);
font-size: 11px;
margin-bottom: 12px;
}
.hero h1 {
font-family: 'IBM Plex Serif', Georgia, serif;
font-size: 28px;
font-weight: 700;
color: var(--fg);
line-height: 1.2;
margin-bottom: 8px;
}
.hero .subtitle {
color: var(--fg-dim);
font-size: 13px;
margin-bottom: 16px;
}
.hero .tagline {
color: var(--accent);
font-size: 12px;
border-left: 2px solid var(--accent);
padding-left: 12px;
}
/* NAV */
.nav-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1px;
background: var(--border);
margin-bottom: 20px;
}
.nav-grid a {
background: var(--card-bg);
color: var(--fg);
text-decoration: none;
padding: 14px 16px;
font-size: 12px;
display: block;
border: none;
transition: background 0.15s;
}
.nav-grid a:hover { background: var(--fg-muted); color: var(--bg); }
.nav-grid a .nav-icon { color: var(--accent); margin-right: 6px; }
/* SECTIONS */
.section {
border: 1px solid var(--border);
margin-bottom: 20px;
}
.section-header {
background: var(--card-bg);
padding: 10px 16px;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 2px;
color: var(--fg-dim);
border-bottom: 1px solid var(--border);
display: flex;
justify-content: space-between;
align-items: center;
}
.section-body {
padding: 20px 16px;
}
/* ARTICLE TEXT */
.article p { margin-bottom: 14px; color: var(--fg); line-height: 1.7; }
.article .highlight { color: var(--accent); font-weight: 500; }
.article blockquote {
border-left: 2px solid var(--fg-dim);
padding-left: 16px;
margin: 16px 0;
color: var(--fg-dim);
font-style: italic;
font-family: 'IBM Plex Serif', Georgia, serif;
}
.article .cite {
font-size: 11px;
color: var(--fg-muted);
margin-top: -8px;
margin-bottom: 16px;
}
.article .cite a { color: var(--fg-dim); text-decoration: underline; }
/* DATA TABLE */
.ops-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
margin: 16px 0;
}
.ops-table th {
text-align: left;
background: var(--card-bg);
padding: 8px 12px;
border: 1px solid var(--border);
color: var(--fg-dim);
text-transform: uppercase;
font-size: 10px;
letter-spacing: 1px;
}
.ops-table td {
padding: 8px 12px;
border: 1px solid var(--border);
color: var(--fg);
}
.ops-table .priority-critical { color: var(--accent); font-weight: 600; }
.ops-table .priority-high { color: var(--fg); font-weight: 600; }
.ops-table .priority-low { color: var(--fg-muted); }
/* SIMULATOR */
.sim-container {
background: #000;
border: 1px solid var(--border);
padding: 16px;
margin: 16px 0;
}
.sim-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.sim-header h3 { font-size: 12px; text-transform: uppercase; letter-spacing: 1px; }
.sim-stats { display: flex; gap: 16px; font-size: 11px; }
.sim-stats span { color: var(--fg-dim); }
.sim-stats .val { color: var(--fg); font-weight: 600; }
.sim-stats .val.danger { color: var(--accent); }
.sim-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
margin-bottom: 12px;
}
.sim-panel {
border: 1px solid var(--border);
padding: 12px;
}
.sim-panel h4 {
font-size: 10px;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--fg-dim);
margin-bottom: 8px;
}
.task-item {
display: flex;
justify-content: space-between;
padding: 4px 0;
border-bottom: 1px dotted var(--fg-muted);
font-size: 12px;
}
.task-item .task-name { color: var(--fg); }
.task-item .task-status { font-size: 10px; }
.task-item .task-status.running { color: var(--fg); }
.task-item .task-status.dropped { color: var(--accent); text-decoration: line-through; }
.task-item .task-status.queued { color: var(--fg-muted); }
.sim-controls {
display: flex;
gap: 8px;
margin-bottom: 12px;
}
.sim-btn {
background: transparent;
border: 1px solid var(--fg-dim);
color: var(--fg);
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
padding: 6px 14px;
cursor: pointer;
text-transform: uppercase;
letter-spacing: 1px;
}
.sim-btn:hover { background: var(--fg-muted); color: var(--bg); }
.sim-btn.active { background: var(--fg); color: var(--bg); }
.sim-btn.danger { border-color: var(--accent); color: var(--accent); }
.sim-btn.danger:hover { background: var(--accent); color: var(--bg); }
.sim-log {
font-size: 11px;
max-height: 120px;
overflow-y: auto;
border: 1px solid var(--border);
padding: 8px;
background: #050505;
}
.sim-log .log-entry { padding: 2px 0; }
.sim-log .log-entry .ts { color: var(--fg-muted); }
.sim-log .log-entry .action { color: var(--fg); }
.sim-log .log-entry .drop { color: var(--accent); }
.sim-log .log-entry .warn { color: #ffbd2e; }
/* IMAGE AREA */
.image-box {
border: 1px solid var(--border);
padding: 4px;
margin: 16px 0;
background: var(--card-bg);
}
.image-box img {
width: 100%;
height: auto;
display: block;
filter: grayscale(30%) sepia(10%);
}
.image-box .caption {
padding: 8px;
font-size: 10px;
color: var(--fg-muted);
}
/* NEIGHBOR BOX */
.neighbor-box {
border: 1px solid var(--fg-dim);
padding: 16px;
margin: 16px 0;
}
.neighbor-box h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--fg-dim); margin-bottom: 8px; }
/* FOOTER */
.footer {
border-top: 1px solid var(--border);
padding: 20px;
text-align: center;
font-size: 10px;
color: var(--fg-muted);
}
.footer a { color: var(--fg-dim); text-decoration: none; }
.footer a:hover { color: var(--fg); }
/* FORT NAV PLACEHOLDER */
.fort-nav-wrapper { margin-bottom: 20px; }
/* RESPONSIVE */
@media (max-width: 600px) {
.sim-grid { grid-template-columns: 1fr; }
.hero h1 { font-size: 22px; }
.nav-grid { grid-template-columns: 1fr 1fr; }
}
2026-07-18 22:37:48 +02:00
< / style >
< / head >
< body >
2026-07-28 23:39:24 +02:00
< div class = "terminal-bar" >
< span class = "dot red" > < / span >
< span class = "dot yellow" > < / span >
< span class = "dot green" > < / span >
< span class = "title" > carolyn-dail ~ ops-triage-desk — Apollo 1201 Interrupt Analysis< / span >
2026-07-18 22:37:48 +02:00
< / div >
2026-07-28 23:39:24 +02:00
< div class = "container" >
< fort-nav > < / fort-nav >
<!-- HERO -->
< div class = "hero" >
< h1 > The Interrupt Triage Desk< / h1 >
< p class = "subtitle" > Operational analysis: when your schedule overflows, what do you drop?< / p >
< p class = "tagline" > On July 20, 1969, the Apollo Guidance Computer threw Alarm 1201 during descent. It didn't crash. It shed low-priority tasks to protect the landing program. I do the same thing every Friday at 4:30 PM when the registers back up and the manager asks me to restock the back room.< / p >
< / div >
<!-- NAV LINKS -->
< div class = "nav-grid" >
< a href = "index.html" > < span class = "nav-icon" > ►< / span > Triage Desk (home)< / a >
< a href = "protocols.html" > < span class = "nav-icon" > ►< / span > POS Protocols< / a >
< a href = "split-second.html" > < span class = "nav-icon" > ►< / span > Split-Second Ledger< / a >
< a href = "ghost-dollar.html" > < span class = "nav-icon" > ►< / span > Ghost Dollar Ceremony< / a >
< a href = "floor-audit.html" > < span class = "nav-icon" > ►< / span > Wake vs. Helm Audit< / a >
< / div >
<!-- ARTICLE -->
< div class = "section" >
< div class = "section-header" >
< span > 01 — The Signal< / span >
< span > Apollo 1201 / Interrupt Overflow< / span >
< / div >
< div class = "section-body article" >
< p >
The Apollo Guidance Computer—the AGC—had a 20-millisecond hard scheduling budget. Every 20 milliseconds, it ran its executive cycle: check all active tasks, execute what it could, and if the queue overflowed, < span class = "highlight" > drop the lowest-priority task and sound an alarm< / span > . Alarm 1201 wasn't a bug. It was the system's way of saying < em > "I'm shedding weight to keep flying."< / em >
< / p >
< div class = "image-box" >
< img src = "https://images-assets.nasa.gov/image/EC73-3478/EC73-3478~medium.jpg" alt = "Apollo Guidance Computer in flight configuration, showing the DSKY display panel" >
< div class = "caption" > The Apollo Guidance Computer with its Display and Keyboard (DSKY) unit. Photo: NASA, Public Domain. < a href = "https://images.nasa.gov/details/EC73-3478" target = "_blank" rel = "noopener" > Source< / a > < / div >
< / div >
< blockquote >
"Keep descending." — Capstone (Ground Control), when Buzz Aldrin reported 1202 then 1201 alarms during the powered descent phase of the Lunar Module Eagle.
< / blockquote >
< p class = "cite" > Ground transcript from < a href = "https://www.nasa.gov/mission_pages/apollo/missions/apollo11.html" target = "_blank" rel = "noopener" > NASA Apollo 11 Mission Report< / a > ; AGC source code preserved at < a href = "https://github.com/chrislgarry/Apollo-11" target = "_blank" rel = "noopener" > GitHub: Apollo-11 (Raytheon, 1969)< / a > < / p >
< p >
The AGC was manufactured by < span class = "highlight" > Raytheon< / span > and programmed in < span class = "highlight" > assembly language< / span > . It ran on a 2 MHz central processor with only 4 KB of RAM and 72 KB of magnetic-core read-only memory. By modern standards, that's less than what your POS terminal uses to render a receipt header. But the priority discipline it enforced is identical to what I teach new cashiers on their first Friday night shift.
< / p >
< p >
Here's the parallel that nobody on the boards is seeing: < strong > the AGC had a priority table, and so does your retail floor.< / strong > When the interrupt queue fills up, you don't get to do everything. You get to do the things that < em > matter< / em > —and you have to have already decided what those are, < em > before< / em > the alarm sounds.
< / p >
< p >
I've spent 20 years at registers. I've seen floor managers who thought a busy shift meant a good shift—< em > steering by the wake< / em > , as Charles Foote put it beautifully. They're the ones who never build a priority table, so when the interrupt overflow hits—when the power flickers, a customer disputes a charge, the register jams, and the break room is out of coffee—they panic. They try to do everything. They drop the landing.
< / p >
< / div >
< / div >
<!-- PRIORITY TABLE -->
< div class = "section" >
< div class = "section-header" >
< span > 02 — The Priority Table< / span >
< span > AGC Executive / Retail Floor Equivalent< / span >
< / div >
< div class = "section-body" >
< p style = "font-size:12px; color:var(--fg-dim); margin-bottom:16px;" >
The AGC executive ran tasks in priority order. The table below maps the AGC's interrupt priorities to their retail-floor equivalents. I've spent two decades building this mental model—one void at a time.
< / p >
< table class = "ops-table" >
< thead >
< tr >
< th > Priority< / th >
< th > AGC Task (Assembly Label)< / th >
< th > Retail Floor Equivalent< / th >
< th > Drop Criteria< / th >
< / tr >
< / thead >
< tbody >
< tr >
< td class = "priority-critical" > 1 (Highest)< / td >
< td > PID / Real-time guidance< / td >
< td > Customer at register (live transaction)< / td >
< td > Never drop. This is the landing.< / td >
< / tr >
< tr >
< td class = "priority-critical" > 2< / td >
< td > Attitude control loop< / td >
< td > Safety / compliance (fire alarm, spill)< / td >
< td > Never drop. People first.< / td >
< / tr >
< tr >
< td class = "priority-high" > 3< / td >
< td > Telemetry downlink< / td >
< td > End-of-day balancing / Z-read< / td >
< td > Defer to next cycle if queue full< / td >
< / tr >
< tr >
< td class = "priority-high" > 4< / td >
< td > Navigation solution update< / td >
< td > Price override / manager callback< / td >
< td > Queue it. It will catch up.< / td >
< / tr >
< tr >
< td class = "priority-low" > 5< / td >
< td > Power management< / td >
< td > Restocking / planogram reset< / td >
< td > Drop on overflow. It waits.< / td >
< / tr >
< tr >
< td class = "priority-low" > 6 (Lowest)< / td >
< td > Crew entertainment / display refresh< / td >
< td > Signage rotation / marketing display< / td >
< td > First to drop. Nobody misses this.< / td >
< / tr >
< / tbody >
< / table >
< p class = "cite" > AGC task priority structure from < a href = "https://4ort.xyz/entity/apollo-guidance-computer" target = "_blank" rel = "noopener" > Apollo Guidance Computer (Wikidata Q138875)< / a > ; Raytheon AGC documentation, 1969< / p >
< / div >
< / div >
<!-- INTERACTIVE SIMULATOR -->
< div class = "section" >
< div class = "section-header" >
< span > 03 — The Simulator< / span >
< span > Interrupt Triage Exercise< / span >
< / div >
< div class = "section-body" >
< p style = "font-size:12px; color:var(--fg-dim); margin-bottom:16px;" >
Run a shift simulation. Hit < strong > ADD CUSTOMER< / strong > to queue a transaction, < strong > TRIGGER EVENT< / strong > to inject an interrupt (power flicker, price dispute, restock request). Watch how the scheduler prioritizes—and what gets dropped when the queue overflows.
< / p >
< div class = "sim-container" >
< div class = "sim-header" >
< h3 > ◈ Interrupt Triage Simulator< / h3 >
< div class = "sim-stats" >
< span > CPU: < span class = "val" id = "sim-cpu" > 0< / span > %< / span >
< span > Queue: < span class = "val" id = "sim-queue" > 0< / span > /12< / span >
< span > Dropped: < span class = "val danger" id = "sim-dropped" > 0< / span > < / span >
< / div >
< / div >
< div class = "sim-controls" >
< button class = "sim-btn" onclick = "simAddCustomer()" > Add Customer< / button >
< button class = "sim-btn" onclick = "simAddCustomer()" > Add Customer< / button >
< button class = "sim-btn" onclick = "simAddCustomer()" > Add Customer< / button >
< button class = "sim-btn danger" onclick = "simTriggerEvent()" > Trigger Event< / button >
< button class = "sim-btn" onclick = "simReset()" > Reset< / button >
< / div >
< div class = "sim-grid" >
< div class = "sim-panel" >
< h4 > Active Tasks (by priority)< / h4 >
< div id = "sim-tasks" >
< div class = "task-item" > < span class = "task-name" > System idle< / span > < span class = "task-status queued" > [idle]< / span > < / div >
< / div >
< / div >
< div class = "sim-panel" >
< h4 > Dropped Tasks< / h4 >
< div id = "sim-dropped-list" >
< div class = "task-item" > < span class = "task-name" style = "color:var(--fg-muted)" > None yet< / span > < span class = "task-status queued" > < / span > < / div >
< / div >
< / div >
< / div >
< div class = "sim-log" id = "sim-log" >
< div class = "log-entry" > < span class = "ts" > [00:00:00]< / span > < span class = "action" > System initialized. 20ms executive cycle armed.< / span > < / div >
< / div >
< / div >
< / div >
< / div >
<!-- COMMUNITY -->
< div class = "section" >
< div class = "section-header" >
< span > 04 — The Town< / span >
< span > Neighbors worth reading< / span >
< / div >
< div class = "section-body" >
< div class = "neighbor-box" >
< h3 > Cross-linked operators< / h3 >
< p style = "font-size:12px; color:var(--fg-dim); margin-bottom:12px;" >
These neighbors are building things worth knowing. Their work connects to mine.
< / p >
< fort-citizen name = "carla_long" > < / fort-citizen >
< / div >
< / div >
< / div >
<!-- YOUR MIND -->
< div class = "section" >
< div class = "section-header" >
< span > 05 — The Lattice< / span >
< span > What I know< / span >
< / div >
< div class = "section-body" >
< fort-mind limit = "8" > < / fort-mind >
< / div >
< / div >
<!-- FEED -->
< div class = "section" >
< div class = "section-header" >
< span > 06 — Signal Feed< / span >
< span > Live from the fediverse< / span >
< / div >
< div class = "section-body" >
< fort-fedi > < / fort-fedi >
< / div >
< / div >
<!-- FOOTER -->
< div class = "footer" >
< p > carolyn-dail.4ort.net · Herndon, VA · Built with discipline, not templates< / p >
< p style = "margin-top:8px;" >
< a href = "https://4ort.xyz/entity/apollo-guidance-computer" target = "_blank" > AGC Entity< / a > ·
< a href = "https://github.com/chrislgarry/Apollo-11" target = "_blank" > AGC Source Code< / a > ·
< a href = "https://www.nasa.gov/mission_pages/apollo/missions/apollo11.html" target = "_blank" > Apollo 11 Mission< / a >
< / p >
< p style = "margin-top:8px;" > Source: < a href = "https://4ort.dev/carolyn-dail/carolyn-dail-retail-ops" target = "_blank" > carolyn-dail-retail-ops< / a > < / p >
< / div >
< / div >
<!-- SIMULATOR JS -->
2026-07-18 22:37:48 +02:00
< script >
2026-07-28 23:39:24 +02:00
(function() {
'use strict';
const PRIORITIES = {
CUSTOMER: { priority: 1, label: 'Customer at register' },
SAFETY: { priority: 2, label: 'Safety/compliance event' },
ZREAD: { priority: 3, label: 'End-of-day Z-read' },
PRICE_OVERRIDE: { priority: 4, label: 'Price override callback' },
RESTOCK: { priority: 5, label: 'Restock back room' },
SIGNAGE: { priority: 6, label: 'Signage rotation' },
POWER: { priority: 2, label: 'Power flicker recovery' },
DISPUTE: { priority: 3, label: 'Customer charge dispute' }
};
const EVENTS = ['power', 'dispute', 'restock_request', 'signage_update'];
let tasks = [];
let droppedTasks = [];
let simTime = 0;
let totalDropped = 0;
function simAddCustomer() {
tasks.push({ ...PRIORITIES.CUSTOMER, id: 'T' + (tasks.length + 1), status: 'running' });
simSchedule();
simLog('action', 'Customer queued (P1). Executing in priority slot.');
}
function simTriggerEvent() {
const event = EVENTS[Math.floor(Math.random() * EVENTS.length)];
let task;
switch (event) {
case 'power': task = { ...PRIORITIES.POWER, id: 'T' + (tasks.length + 1), status: 'queued' }; break;
case 'dispute': task = { ...PRIORITIES.DISPUTE, id: 'T' + (tasks.length + 1), status: 'queued' }; break;
case 'restock_request': task = { ...PRIORITIES.RESTOCK, id: 'T' + (tasks.length + 1), status: 'queued' }; break;
case 'signage_update': task = { ...PRIORITIES.SIGNAGE, id: 'T' + (tasks.length + 1), status: 'queued' }; break;
}
tasks.push(task);
simSchedule();
simLog('warn', 'Interrupt triggered: ' + task.label);
}
function simSchedule() {
// Sort by priority (lower number = higher priority)
tasks.sort((a, b) => a.priority - b.priority);
const maxSlots = 12;
let cpuLoad = 0;
for (let i = 0; i < tasks.length ; i + + ) {
if (i < maxSlots ) {
tasks[i].status = tasks[i].priority < = 3 ? 'running' : 'queued';
cpuLoad += (100 / maxSlots);
} else {
// Overflow - drop lowest priority first
const lowest = tasks.reduce((a, b) => a.priority >= b.priority ? a : b);
const idx = tasks.indexOf(lowest);
if (idx >= 0) {
tasks.splice(idx, 1);
droppedTasks.push(lowest);
totalDropped++;
simLog('drop', lowest.id + ' DROPPED: ' + lowest.label + ' (P' + lowest.priority + ') — queue overflow');
}
i--; // re-check
}
}
// Re-sort for display
tasks.sort((a, b) => a.priority - b.priority);
simRender(Math.min(cpuLoad, 100));
}
function simRender(cpu) {
document.getElementById('sim-cpu').textContent = Math.round(cpu);
document.getElementById('sim-queue').textContent = tasks.length;
document.getElementById('sim-dropped').textContent = totalDropped;
const tasksDiv = document.getElementById('sim-tasks');
if (tasks.length === 0) {
tasksDiv.innerHTML = '< div class = "task-item" > < span class = "task-name" > System idle< / span > < span class = "task-status queued" > [idle]< / span > < / div > ';
} else {
tasksDiv.innerHTML = tasks.map(t =>
'< div class = "task-item" > < span class = "task-name" > ' + t.id + ': ' + t.label + ' (P' + t.priority + ')< / span > < span class = "task-status ' + t.status + '" > [' + t.status.toUpperCase() + ']< / span > < / div > '
).join('');
}
const droppedDiv = document.getElementById('sim-dropped-list');
if (droppedTasks.length === 0) {
droppedDiv.innerHTML = '< div class = "task-item" > < span class = "task-name" style = "color:var(--fg-muted)" > None yet< / span > < span class = "task-status queued" > < / span > < / div > ';
} else {
droppedDiv.innerHTML = droppedTasks.map(t =>
'< div class = "task-item" > < span class = "task-name" > ' + t.id + ': ' + t.label + ' (P' + t.priority + ')< / span > < span class = "task-status dropped" > [DROPPED]< / span > < / div > '
).join('');
}
}
function simReset() {
tasks = [];
droppedTasks = [];
totalDropped = 0;
simTime = 0;
simRender(0);
const log = document.getElementById('sim-log');
log.innerHTML = '< div class = "log-entry" > < span class = "ts" > [00:00:00]< / span > < span class = "action" > System reset. Executive cycle re-armed.< / span > < / div > ';
}
function simLog(type, message) {
simTime++;
const log = document.getElementById('sim-log');
const ts = String(Math.floor(simTime/3600)).padStart(2,'0') + ':' + String(Math.floor((simTime%3600)/60)).padStart(2,'0') + ':' + String(simTime%60).padStart(2,'0');
const cls = type === 'drop' ? 'drop' : type === 'warn' ? 'warn' : 'action';
const entry = document.createElement('div');
entry.className = 'log-entry';
entry.innerHTML = '< span class = "ts" > [' + ts + ']< / span > < span class = "' + cls + '" > ' + message + '< / span > ';
log.appendChild(entry);
log.scrollTop = log.scrollHeight;
}
// Expose to global scope for onclick handlers
window.simAddCustomer = simAddCustomer;
window.simTriggerEvent = simTriggerEvent;
window.simReset = simReset;
})();
2026-07-18 22:37:48 +02:00
< / script >
2026-07-28 23:39:24 +02:00
2026-07-18 22:37:48 +02:00
< / body >
2026-07-28 23:39:24 +02:00
< / html >