// Escape for safe HTML text content (prevents XSS when inserting into HTML) function escapeHtml(text) { if (text == null) return ''; const s = String(text); return s .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } // Format bytes to GB (matches Django convert_bytes filter default) function formatBytes(bytes, targetUnit = 'GB') { if (bytes == null || isNaN(Number(bytes))) return '0'; const b = Number(bytes); const factors = { B: 1, KB: 1024, MB: 1024 * 1024, GB: 1024 ** 3, TB: 1024 ** 4 }; const unit = (targetUnit || 'GB').toUpperCase(); const factor = factors[unit] || factors.GB; return (b / factor).toFixed(1); } // Color utilities const getCSSVar = (varName) => { return getComputedStyle(document.documentElement).getPropertyValue(varName).trim(); } function getColorWithOpacity(className) { const element = document.createElement('div'); element.className = className; element.style.opacity = '1'; // Force opacity element.textContent = '.'; document.body.appendChild(element); const computedColor = window.getComputedStyle(element).color; document.body.removeChild(element); return computedColor; } // Format audit date for display (ISO string -> short date, e.g. "Feb 1") function formatAuditDate(isoString) { if (!isoString) return ''; try { return new Date(isoString).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); } catch (e) { return ''; } } // Utility function to calculate mean and standard deviation function calculateStats(data) { if (!data || data.length === 0) return { mean: 0, std: 0 }; const mean = data.reduce((a, b) => a + b, 0) / data.length; const variance = data.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / data.length; const std = Math.sqrt(variance); return { mean, std }; }