kernels-benchmarks / megablocks /megablocks_only.html
drbh's picture
drbh HF Staff
Upload folder using huggingface_hub
6094336 verified
raw
history blame
243 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Megablocks Only Test</title>
<script>
// Apply theme and widget visibility immediately to prevent flicker
(function() {
const configTheme = 'light';
const hasConfigUi = false;
const configUi = hasConfigUi ? 'None' : null;
const hasWidgetsConfig = false;
const widgetsOn = hasWidgetsConfig ? false : true;
let theme;
if (configTheme === 'auto') {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
} else {
theme = localStorage.getItem('uvnote-theme') || configTheme;
}
document.documentElement.setAttribute('data-theme', theme);
// Initialize UI theme (css theme)
let ui = hasConfigUi ? configUi : (localStorage.getItem('uvnote-ui') || 'default');
if (ui !== 'default' && ui !== 'none' && ui !== 'monocolor') { ui = 'default'; }
document.documentElement.setAttribute('data-ui', ui);
// Apply widgets visibility
document.documentElement.setAttribute('data-widgets', widgetsOn ? 'on' : 'off');
})();
</script>
<style>
:root[data-theme="light"] {
--bg-primary: #ffffff;
--bg-secondary: #f6f8fa;
--bg-tertiary: #f8f9fa;
--bg-code: #f8f9fa;
--bg-error: #fdf2f2;
--bg-artifact: #e6f3ff;
--bg-artifact-hover: #d0e7ff;
--text-primary: #333;
--text-secondary: #656d76;
--text-error: #c53030;
--text-link: #0969da;
--border-primary: #e1e5e9;
--border-error: #e53e3e;
--border-cell-failed: #d73a49;
--shadow: rgba(0, 0, 0, 0.1);
}
:root[data-theme="dark"] {
--bg-primary: #0a0a0a;
--bg-secondary: #121212;
--bg-tertiary: #181818;
--bg-code: #0d0d0d;
--bg-error: #1a0f0f;
--bg-artifact: #151515;
--bg-artifact-hover: #1a1a1a;
--text-primary: #e0e0e0;
--text-secondary: #888888;
--text-error: #ff6b6b;
--text-link: #64b5f6;
--border-primary: #2a2a2a;
--border-error: #ff6b6b;
--border-cell-failed: #ff6b6b;
--shadow: rgba(255, 255, 255, 0.05);
}
/* Monocolor UI theme: black/white background, all text/borders single blue */
:root[data-ui="monocolor"] { --mono-color: #0a66ff; }
:root[data-ui="monocolor"][data-theme="light"] {
--bg-primary: #ffffff;
}
:root[data-ui="monocolor"][data-theme="dark"] {
--bg-primary: #000000;
}
:root[data-ui="monocolor"] {
--bg-secondary: var(--bg-primary);
--bg-tertiary: var(--bg-primary);
--bg-code: var(--bg-primary);
--bg-error: var(--bg-primary);
--bg-artifact: var(--bg-primary);
--bg-artifact-hover: var(--bg-primary);
--text-primary: var(--mono-color);
--text-secondary: var(--mono-color);
--text-error: var(--mono-color);
--text-link: var(--mono-color);
--border-primary: var(--mono-color);
--border-error: var(--mono-color);
--border-cell-failed: var(--mono-color);
--shadow: none;
}
:root[data-ui="monocolor"] a { color: var(--mono-color); }
:root[data-ui="monocolor"] .menu-button,
:root[data-ui="monocolor"] .theme-toggle,
:root[data-ui="monocolor"] .reset-toggle { background: var(--bg-primary); color: var(--mono-color); border-color: var(--mono-color); }
:root[data-ui="monocolor"] .menu-button:hover,
:root[data-ui="monocolor"] .theme-toggle:hover,
:root[data-ui="monocolor"] .reset-toggle:hover { background: var(--bg-primary); color: var(--mono-color); border-color: var(--mono-color); }
:root[data-ui="monocolor"] .menu-dropdown { background: var(--bg-primary); border-color: var(--mono-color); box-shadow: none; }
:root[data-ui="monocolor"] .menu-item { color: var(--mono-color); border-bottom-color: var(--mono-color); }
:root[data-ui="monocolor"] .system-info { background: var(--bg-primary); border-color: var(--mono-color); }
:root[data-ui="monocolor"] .cell { border-color: var(--mono-color); background: var(--bg-primary); }
:root[data-ui="monocolor"] .cell-header { background: var(--bg-primary); border-bottom-color: var(--mono-color); }
:root[data-ui="monocolor"] .artifact { background: var(--bg-primary); border-color: var(--mono-color); color: var(--mono-color); }
:root[data-ui="monocolor"] .artifact:hover { background: var(--bg-primary); }
:root[data-ui="monocolor"] .artifact-preview img,
:root[data-ui="monocolor"] .artifact-preview svg { border-color: var(--mono-color); }
:root[data-ui="monocolor"] .status-widget { background: var(--bg-primary); border-color: var(--mono-color); color: var(--mono-color); }
:root[data-ui="monocolor"] .minimap,
:root[data-ui="monocolor"] .file-explorer,
:root[data-ui="monocolor"] .tools-widget {
background: var(--bg-primary);
border-color: var(--mono-color);
color: var(--mono-color);
}
:root[data-ui="monocolor"] .cell-code {
background: var(--bg-primary);
border-bottom-color: var(--mono-color);
}
:root[data-ui="monocolor"] .tools-title,
:root[data-ui="monocolor"] .file-explorer-section-title,
:root[data-ui="monocolor"] .minimap-title { color: var(--mono-color); border-bottom-color: var(--mono-color); }
:root[data-ui="monocolor"] .tool-button { background: var(--bg-primary); border-color: var(--mono-color); color: var(--mono-color); }
:root[data-ui="monocolor"] .tool-button.active { border-color: var(--mono-color); }
:root[data-ui="monocolor"] .file-explorer-item,
:root[data-ui="monocolor"] .minimap-item { color: var(--mono-color); }
/* Force Pygments code to mono blue on mono bg */
:root[data-ui="monocolor"] .highlight { background: var(--bg-primary) !important; color: var(--mono-color) !important; }
:root[data-ui="monocolor"] .highlight *,
:root[data-ui="monocolor"] .highlight .hll { color: var(--mono-color) !important; background: transparent !important; border-color: var(--mono-color) !important; }
/* Default code font + metrics (overridable via frontmatter) */
:root { --code-font-size: 0.95rem; --code-line-height: 1.5; --code-pad-y: 0.75rem; }
/* Minimal UI theme overrides base variables for a flatter, 90s look */
:root[data-ui="none"] {
--bg-primary: #ffffff;
--bg-secondary: transparent;
--bg-tertiary: transparent;
--bg-code: #f9f9f9;
--bg-error: #fff0f0;
--bg-artifact: #f0f7ff;
--bg-artifact-hover: #e5f1ff;
--text-primary: #000000;
--text-secondary: #222222;
--text-error: #a00000;
--text-link: #0000ee;
--border-primary: #cccccc;
--border-error: #cc0000;
--border-cell-failed: #cc0000;
--shadow: none;
}
html {
overscroll-behavior: none;
}
body {
font-family: 'Cascadia Mono', 'Cascadia Code', 'JetBrains Mono', 'SF Mono', Monaco, 'Consolas', monospace;
line-height: 1.4;
max-width: 1000px;
margin: 0 auto;
padding: 15px;
color: var(--text-primary);
background: var(--bg-primary);
transition: background-color 0.2s ease, color 0.2s ease;
overscroll-behavior: none;
}
/* Minimal "none" UI theme overrides */
:root[data-ui="none"] body {
font-family: 'Times New Roman', Times, serif;
line-height: 1.5;
max-width: 860px;
padding: 12px;
background: #ffffff;
color: #000000;
transition: none;
}
/* Two panel layout removed */
.controls {
position: fixed;
top: 20px;
right: 20px;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 0.25rem;
z-index: 1000;
}
.controls-buttons { display: flex; gap: 0.5rem; }
.menu-button {
position: relative;
background: var(--bg-secondary);
border: 1px solid var(--border-primary);
padding: 8px 12px;
border-radius: 2px;
color: var(--text-secondary);
cursor: pointer;
font-family: inherit;
font-size: 0.9rem;
user-select: none;
}
/* Keep default control styling when widgets are enabled, even in minimal UI */
:root[data-ui="none"][data-widgets="on"] .menu-button,
:root[data-ui="none"][data-widgets="on"] .theme-toggle,
:root[data-ui="none"][data-widgets="on"] .reset-toggle {
background: #f6f6f6;
border: 1px solid #cccccc;
color: #222222;
}
.menu-button:hover {
color: var(--text-primary);
background: var(--bg-tertiary);
}
/* Controls state indicator (top-right) */
/* Status widget (bottom-right) */
.status-widget {
position: fixed;
right: 20px;
bottom: 20px;
width: auto;
max-width: 260px;
background: var(--bg-secondary);
border: 1px solid var(--border-primary);
border-radius: 2px;
padding: 6px 8px;
font-size: 0.8rem;
color: var(--text-secondary);
z-index: 100;
}
.status-widget strong { color: var(--text-primary); }
:root[data-ui="none"][data-widgets="on"] .status-widget { background: #f6f6f6; border-color: #ccc; color: #222; }
:root[data-ui="none"][data-widgets="on"] .menu-button:hover,
:root[data-ui="none"][data-widgets="on"] .theme-toggle:hover,
:root[data-ui="none"][data-widgets="on"] .reset-toggle:hover {
background: #ededed;
border-color: #bbbbbb;
color: #000000;
}
.menu-dropdown {
position: absolute;
top: 100%;
right: 0;
background: var(--bg-secondary);
border: 1px solid var(--border-primary);
border-radius: 4px;
box-shadow: 0 4px 12px var(--shadow);
min-width: 160px;
opacity: 0;
visibility: hidden;
transform: translateY(-8px);
transition: all 0.2s ease;
z-index: 1001;
margin-top: 4px;
}
:root[data-ui="none"][data-widgets="on"] .menu-dropdown { background: #ffffff; border: 1px solid #cccccc; box-shadow: none; }
.menu-button.active .menu-dropdown {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.menu-item {
display: block;
padding: 8px 12px;
color: var(--text-secondary);
text-decoration: none;
font-size: 0.85rem;
border-bottom: 1px solid var(--border-primary);
cursor: pointer;
}
:root[data-ui="none"] .menu-item { color: #000; border-bottom: 1px solid #eee; }
.menu-item:last-child {
border-bottom: none;
}
.menu-item:hover {
background: var(--bg-tertiary);
color: var(--text-primary);
}
.menu-checkbox {
display: inline-block;
width: 16px;
font-family: monospace;
color: var(--text-link);
}
.theme-toggle,
.reset-toggle {
background: var(--bg-secondary);
border: 1px solid var(--border-primary);
padding: 8px 12px;
border-radius: 4px;
color: var(--text-secondary);
cursor: pointer;
font-family: inherit;
font-size: 0.9rem;
user-select: none;
}
.theme-toggle:hover,
.reset-toggle:hover {
color: var(--text-primary);
background: var(--bg-tertiary);
}
.system-info {
background: var(--bg-secondary);
border: 1px solid var(--border-primary);
border-radius: 4px;
padding: 8px 12px;
margin-bottom: 16px;
font-size: 0.85em;
color: var(--text-secondary);
}
.system-info-header {
font-weight: 600;
color: var(--text-primary);
margin-bottom: 2px;
}
.system-info-content {
font-family: monospace;
}
.theme-toggle, .reset-toggle {
background: var(--bg-secondary);
border: 1px solid var(--border-primary);
border-radius: 2px;
/* padding: 0.4rem 0.6rem; */
cursor: pointer;
font-family: inherit;
font-size: 0.8rem;
color: var(--text-secondary);
user-select: none;
transition: all 0.2s ease;
text-transform: lowercase;
letter-spacing: 0;
}
.theme-toggle:hover, .reset-toggle:hover {
background: var(--bg-tertiary);
border-color: var(--text-secondary);
color: var(--text-primary);
}
.minimap {
position: fixed;
bottom: 20px;
right: 20px;
width: 220px;
max-height: 400px;
background: var(--bg-secondary);
border: 1px solid var(--border-primary);
border-radius: 2px;
padding: 0.5rem;
font-size: 0.7rem;
overflow-y: auto;
z-index: 100;
opacity: 0.9;
transition: opacity 0.2s ease;
}
/* Hide widgets and controls when disabled via frontmatter */
:root[data-widgets="off"] .controls,
:root[data-widgets="off"] .minimap,
:root[data-widgets="off"] .file-explorer,
:root[data-widgets="off"] .tools-widget,
:root[data-widgets="off"] .status-widget { display: none !important; }
.file-explorer {
position: fixed;
bottom: 20px; /* default; JS will stack */
right: 20px;
left: auto;
top: auto;
width: 220px;
max-height: 400px;
background: var(--bg-secondary);
border: 1px solid var(--border-primary);
border-radius: 2px;
padding: 0.5rem;
font-size: 0.7rem;
overflow-y: auto;
z-index: 100;
opacity: 0.9;
transition: opacity 0.2s ease;
}
/* Drawing overlay */
.draw-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 80; /* under widgets (100) and controls (1000) */
display: block;
pointer-events: none; /* enabled only when a tool is active */
}
/* Tools widget */
.tools-widget {
position: fixed;
bottom: 20px; /* default; JS will stack */
right: 20px;
left: auto;
top: auto;
width: 220px;
background: var(--bg-secondary);
border: 1px solid var(--border-primary);
border-radius: 2px;
padding: 0.5rem;
font-size: 0.7rem;
z-index: 100;
opacity: 0.95;
}
.tools-title {
font-weight: bold;
color: var(--text-secondary);
margin-bottom: 0.5rem;
padding-bottom: 0.25rem;
border-bottom: 1px solid var(--border-primary);
cursor: grab;
user-select: none;
}
.tools-row { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.tool-button {
background: var(--bg-tertiary);
border: 1px solid var(--border-primary);
border-radius: 2px;
padding: 0.25rem 0.4rem;
cursor: pointer;
color: var(--text-secondary);
font-family: inherit;
font-size: 0.75rem;
user-select: none;
}
.tool-button:hover { color: var(--text-primary); }
.tool-button.active { color: var(--text-primary); border-color: var(--text-secondary); background: var(--bg-secondary); }
.minimap:hover, .file-explorer:hover {
opacity: 1;
}
.minimap-title {
font-weight: bold;
color: var(--text-secondary);
margin-bottom: 0.5rem;
padding-bottom: 0.25rem;
border-bottom: 1px solid var(--border-primary);
cursor: grab; /* drag handle */
user-select: none;
}
.minimap-item {
display: block;
color: var(--text-secondary);
text-decoration: none;
padding: 0.15rem 0;
border-left: 2px solid transparent;
padding-left: 0.5rem;
transition: all 0.2s ease;
cursor: pointer;
}
.minimap-item:hover {
color: var(--text-primary);
border-left-color: var(--text-secondary);
}
.minimap-item.active {
color: var(--text-primary);
border-left-color: var(--text-link);
}
.minimap-heading {
font-weight: normal;
}
.minimap-heading.h1 { padding-left: 0.5rem; }
.minimap-heading.h2 { padding-left: 1rem; }
.minimap-heading.h3 { padding-left: 1.5rem; }
.minimap-heading.h4 { padding-left: 2rem; }
.minimap-heading.h5 { padding-left: 2.5rem; }
.minimap-heading.h6 { padding-left: 3rem; }
.minimap-cell {
color: var(--text-link);
opacity: 0.8;
font-style: italic;
}
.minimap-cell:hover {
opacity: 1;
}
.file-explorer-title {
font-weight: bold;
color: var(--text-secondary);
margin-bottom: 0.5rem;
padding-bottom: 0.25rem;
border-bottom: 1px solid var(--border-primary);
cursor: grab; /* drag handle */
user-select: none;
}
.file-explorer-section {
margin-bottom: 0.75rem;
}
.file-explorer-section-title {
font-weight: bold;
color: var(--text-secondary);
font-size: 0.65rem;
margin-bottom: 0.25rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.file-explorer-item {
display: block;
color: var(--text-secondary);
text-decoration: none;
padding: 0.1rem 0;
margin-left: 0.5rem;
transition: color 0.2s ease;
cursor: pointer;
font-family: monospace;
}
.file-explorer-item:hover {
color: var(--text-primary);
}
.file-explorer-item.script {
color: var(--text-link);
}
.file-explorer-item.artifact {
color: var(--text-secondary);
opacity: 0.8;
}
/* Hide widgets on smaller screens */
@media (max-width: 768px) {
.minimap, .file-explorer, .tools-widget {
display: none;
}
}
.cell {
margin: 1rem 0;
border: 1px solid var(--border-primary);
border-radius: 2px;
overflow: hidden;
background: var(--bg-secondary);
}
:root[data-ui="none"] .cell { margin: 1em 0; border: none; background: transparent; }
.cell-header {
background: var(--bg-secondary);
padding: 0.5rem 1rem;
border-bottom: 1px solid var(--border-primary);
font-family: inherit;
font-size: 0.85rem;
}
:root[data-ui="none"] .cell-header { background: transparent; border: none; padding: 0; font-weight: bold; }
:root[data-ui="none"] .cell-content { padding: 0; }
:root[data-ui="none"] .copy-button,
:root[data-ui="none"] .collapse-indicators,
:root[data-ui="none"] .cell-meta,
:root[data-ui="none"] .cell-outputs-header { display: none !important; }
:root[data-ui="none"] pre, :root[data-ui="none"] code { font-family: Menlo, Monaco, 'Courier New', monospace; }
:root[data-ui="none"] .code-content pre { background: #f9f9f9; border: 1px solid #ddd; padding: 8px; }
:root[data-ui="none"] .output { background: transparent; border: none; padding: 0.25em 0; }
color: var(--text-secondary);
cursor: pointer;
user-select: none;
transition: background-color 0.2s ease;
}
.cell-header:hover {
background: var(--bg-tertiary);
}
.collapse-indicators {
color: var(--text-secondary);
font-size: 0.8rem;
opacity: 0.7;
}
.collapse-indicators span:hover {
color: var(--text-primary);
opacity: 1;
}
.cell-code {
display: block;
background: var(--bg-code);
}
.cell-code.collapsed {
display: none;
}
.cell-code pre {
margin: 0;
padding: 0.75rem;
background: var(--bg-code);
overflow-x: auto;
color: var(--text-primary);
}
.cell-output {
padding: 0.75rem;
/* background: var(--bg-primary); */
background: var(--bg-secondary);
}
.cell-output.collapsed {
display: none;
}
.cell-stdout {
background: var(--bg-tertiary);
padding: 0.75rem;
border-radius: 1px;
/* margin: 0.25rem 0; */
font-family: inherit;
font-size: 0.9rem;
white-space: pre-wrap;
color: var(--text-primary);
}
.cell-stderr {
background: var(--bg-error);
border-left: 2px solid var(--border-error);
padding: 1rem;
margin: 0.5rem 0;
font-family: inherit;
font-size: 0.9rem;
color: var(--text-error);
white-space: pre-wrap;
}
.uv-install-logs {
margin: 0.5rem 0;
}
.uv-logs-header {
cursor: pointer;
padding: 0.75rem;
border-left: 3px solid var(--border-color);
font-family: inherit;
font-size: 0.85rem;
color: var(--text-secondary);
user-select: none;
}
.uv-logs-content {
background: var(--bg-secondary);
padding: 1rem;
border-left: 3px solid var(--border-color);
white-space: pre-wrap;
font-family: monospace;
font-size: 0.85rem;
color: var(--text-secondary);
overflow-x: auto;
}
.cell-artifacts {
margin: 1rem 0;
}
.cell-artifacts h4 {
margin: 0 0 0.5rem 0;
color: var(--text-secondary);
font-size: 0.9rem;
}
.artifact {
display: inline-block;
background: var(--bg-artifact);
padding: 0.25rem 0.5rem;
border-radius: 1px;
margin: 0.25rem 0.5rem 0.25rem 0;
font-family: inherit;
font-size: 0.8rem;
color: var(--text-link);
text-decoration: none;
transition: background-color 0.2s ease;
border: 1px solid var(--border-primary);
}
.artifact:hover {
background: var(--bg-artifact-hover);
}
.artifact-preview {
margin-top: 1rem;
}
.artifact-preview img {
max-width: 100%;
height: auto;
border: 1px solid var(--border-primary);
border-radius: 1px;
}
.artifact-preview svg {
max-width: 100%;
height: auto;
border: 1px solid var(--border-primary);
border-radius: 1px;
display: block;
}
/* Style SVG text elements */
.artifact-preview svg g {
fill: var(--text-primary) !important;
}
/* Auto-theme SVG elements */
.artifact-preview svg {
background: transparent;
}
.cell-failed {
border-color: var(--border-cell-failed);
}
.cell-failed .cell-header {
background: var(--bg-error);
color: var(--text-error);
}
.cell-commented {
opacity: 0.6;
border-style: dashed;
}
.cell-commented .cell-header {
background: var(--bg-secondary);
color: var(--text-secondary);
font-style: italic;
}
.run-btn {
background: var(--bg-tertiary);
border: 1px solid var(--border-primary);
padding: 2px 6px;
border-radius: 2px;
color: var(--text-secondary);
cursor: pointer;
font-size: 0.75em;
font-family: inherit;
margin-left: 4px;
}
.run-btn:hover {
color: var(--text-primary);
background: var(--bg-primary);
}
.run-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.copy-btn {
background: var(--bg-tertiary);
border: 1px solid var(--border-primary);
padding: 2px 6px;
border-radius: 2px;
color: var(--text-secondary);
cursor: pointer;
font-size: 0.75em;
font-family: inherit;
margin-left: 4px;
}
.copy-btn:hover {
color: var(--text-primary);
background: var(--bg-primary);
}
.copy-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.raw-btn {
background: var(--bg-tertiary);
border: 1px solid var(--border-primary);
padding: 2px 6px;
border-radius: 2px;
color: var(--text-secondary);
cursor: pointer;
font-size: 0.75em;
font-family: inherit;
margin-left: 4px;
text-decoration: none;
display: inline-block;
}
.raw-btn:hover {
color: var(--text-primary);
background: var(--bg-primary);
text-decoration: none;
}
.output-stale {
opacity: 0.5;
position: relative;
}
.output-stale::after {
content: '⏳ updating...';
position: absolute;
top: 8px;
right: 8px;
background: var(--bg-secondary);
padding: 4px 8px;
border-radius: 2px;
font-size: 0.75em;
color: var(--text-secondary);
border: 1px solid var(--border-primary);
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1.5rem;
margin-bottom: 0.75rem;
color: var(--text-primary);
}
h1 {
margin-top: 0;
margin-bottom: 1rem;
}
p {
margin: 0.75rem 0;
color: var(--text-primary);
}
a {
color: var(--text-link);
}
img {
max-width: 100%;
height: auto;
border-radius: 1px;
box-shadow: none;
}
pre, code {
font-family: 'Cascadia Mono', 'Cascadia Code', 'JetBrains Mono', 'SF Mono', Monaco, 'Consolas', monospace;
font-size: var(--code-font-size);
}
.code-wrap { position: relative; }
.code-line-highlight { display: none; position: absolute; left: 0; right: 0; height: 1.5em; background: rgba(255, 235, 170, 0.35); pointer-events: none; border-left: 3px solid #f4c542; }
.line-number { cursor: pointer; text-decoration: none; color: var(--text-secondary); padding: 0 0.25rem; }
.line-number.selected { background: rgba(255, 235, 170, 0.4); color: var(--text-primary); }
/* Line numbers */
.highlight-with-lines {
display: flex;
}
.line-numbers {
background: var(--bg-tertiary);
padding: var(--code-pad-y) 0.5rem;
font-family: 'Cascadia Mono', 'Cascadia Code', 'JetBrains Mono', 'SF Mono', Monaco, 'Consolas', monospace;
font-size: var(--code-font-size);
line-height: var(--code-line-height);
color: var(--text-secondary);
user-select: none;
text-align: right;
border-right: 1px solid var(--border-primary);
}
.line-numbers .line-number {
display: block;
line-height: var(--code-line-height);
}
.highlight-with-lines .highlight {
flex: 1;
}
.highlight .hll { background-color: transparent; } /* don't conflict with our highlight */
.highlight pre {
white-space: pre;
margin: 0;
padding: var(--code-pad-y) 0.75rem;
line-height: var(--code-line-height);
}
/* Collapsed code styling */
.cell-code.collapsed {
display: none;
}
.cell-code.expanded {
display: block;
}
.cell-code {
display: block;
border-bottom: 1px solid var(--border-primary);
}
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
[data-theme="light"] .highlight .hll { background-color: #ffffcc }
[data-theme="light"] .highlight { background: #f8f8f8; }
[data-theme="light"] .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */
[data-theme="light"] .highlight .err { border: 1px solid #F00 } /* Error */
[data-theme="light"] .highlight .k { color: #008000; font-weight: bold } /* Keyword */
[data-theme="light"] .highlight .o { color: #666 } /* Operator */
[data-theme="light"] .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
[data-theme="light"] .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
[data-theme="light"] .highlight .cp { color: #9C6500 } /* Comment.Preproc */
[data-theme="light"] .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
[data-theme="light"] .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
[data-theme="light"] .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
[data-theme="light"] .highlight .gd { color: #A00000 } /* Generic.Deleted */
[data-theme="light"] .highlight .ge { font-style: italic } /* Generic.Emph */
[data-theme="light"] .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
[data-theme="light"] .highlight .gr { color: #E40000 } /* Generic.Error */
[data-theme="light"] .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
[data-theme="light"] .highlight .gi { color: #008400 } /* Generic.Inserted */
[data-theme="light"] .highlight .go { color: #717171 } /* Generic.Output */
[data-theme="light"] .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
[data-theme="light"] .highlight .gs { font-weight: bold } /* Generic.Strong */
[data-theme="light"] .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
[data-theme="light"] .highlight .gt { color: #04D } /* Generic.Traceback */
[data-theme="light"] .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
[data-theme="light"] .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
[data-theme="light"] .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
[data-theme="light"] .highlight .kp { color: #008000 } /* Keyword.Pseudo */
[data-theme="light"] .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
[data-theme="light"] .highlight .kt { color: #B00040 } /* Keyword.Type */
[data-theme="light"] .highlight .m { color: #666 } /* Literal.Number */
[data-theme="light"] .highlight .s { color: #BA2121 } /* Literal.String */
[data-theme="light"] .highlight .na { color: #687822 } /* Name.Attribute */
[data-theme="light"] .highlight .nb { color: #008000 } /* Name.Builtin */
[data-theme="light"] .highlight .nc { color: #00F; font-weight: bold } /* Name.Class */
[data-theme="light"] .highlight .no { color: #800 } /* Name.Constant */
[data-theme="light"] .highlight .nd { color: #A2F } /* Name.Decorator */
[data-theme="light"] .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */
[data-theme="light"] .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
[data-theme="light"] .highlight .nf { color: #00F } /* Name.Function */
[data-theme="light"] .highlight .nl { color: #767600 } /* Name.Label */
[data-theme="light"] .highlight .nn { color: #00F; font-weight: bold } /* Name.Namespace */
[data-theme="light"] .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
[data-theme="light"] .highlight .nv { color: #19177C } /* Name.Variable */
[data-theme="light"] .highlight .ow { color: #A2F; font-weight: bold } /* Operator.Word */
[data-theme="light"] .highlight .w { color: #BBB } /* Text.Whitespace */
[data-theme="light"] .highlight .mb { color: #666 } /* Literal.Number.Bin */
[data-theme="light"] .highlight .mf { color: #666 } /* Literal.Number.Float */
[data-theme="light"] .highlight .mh { color: #666 } /* Literal.Number.Hex */
[data-theme="light"] .highlight .mi { color: #666 } /* Literal.Number.Integer */
[data-theme="light"] .highlight .mo { color: #666 } /* Literal.Number.Oct */
[data-theme="light"] .highlight .sa { color: #BA2121 } /* Literal.String.Affix */
[data-theme="light"] .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
[data-theme="light"] .highlight .sc { color: #BA2121 } /* Literal.String.Char */
[data-theme="light"] .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
[data-theme="light"] .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
[data-theme="light"] .highlight .s2 { color: #BA2121 } /* Literal.String.Double */
[data-theme="light"] .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
[data-theme="light"] .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
[data-theme="light"] .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
[data-theme="light"] .highlight .sx { color: #008000 } /* Literal.String.Other */
[data-theme="light"] .highlight .sr { color: #A45A77 } /* Literal.String.Regex */
[data-theme="light"] .highlight .s1 { color: #BA2121 } /* Literal.String.Single */
[data-theme="light"] .highlight .ss { color: #19177C } /* Literal.String.Symbol */
[data-theme="light"] .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
[data-theme="light"] .highlight .fm { color: #00F } /* Name.Function.Magic */
[data-theme="light"] .highlight .vc { color: #19177C } /* Name.Variable.Class */
[data-theme="light"] .highlight .vg { color: #19177C } /* Name.Variable.Global */
[data-theme="light"] .highlight .vi { color: #19177C } /* Name.Variable.Instance */
[data-theme="light"] .highlight .vm { color: #19177C } /* Name.Variable.Magic */
[data-theme="light"] .highlight .il { color: #666 } /* Literal.Number.Integer.Long */
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
[data-theme="dark"] .highlight .hll { background-color: #49483e }
[data-theme="dark"] .highlight { background: #272822; color: #F8F8F2 }
[data-theme="dark"] .highlight .c { color: #959077 } /* Comment */
[data-theme="dark"] .highlight .err { color: #ED007E; background-color: #1E0010 } /* Error */
[data-theme="dark"] .highlight .esc { color: #F8F8F2 } /* Escape */
[data-theme="dark"] .highlight .g { color: #F8F8F2 } /* Generic */
[data-theme="dark"] .highlight .k { color: #66D9EF } /* Keyword */
[data-theme="dark"] .highlight .l { color: #AE81FF } /* Literal */
[data-theme="dark"] .highlight .n { color: #F8F8F2 } /* Name */
[data-theme="dark"] .highlight .o { color: #FF4689 } /* Operator */
[data-theme="dark"] .highlight .x { color: #F8F8F2 } /* Other */
[data-theme="dark"] .highlight .p { color: #F8F8F2 } /* Punctuation */
[data-theme="dark"] .highlight .ch { color: #959077 } /* Comment.Hashbang */
[data-theme="dark"] .highlight .cm { color: #959077 } /* Comment.Multiline */
[data-theme="dark"] .highlight .cp { color: #959077 } /* Comment.Preproc */
[data-theme="dark"] .highlight .cpf { color: #959077 } /* Comment.PreprocFile */
[data-theme="dark"] .highlight .c1 { color: #959077 } /* Comment.Single */
[data-theme="dark"] .highlight .cs { color: #959077 } /* Comment.Special */
[data-theme="dark"] .highlight .gd { color: #FF4689 } /* Generic.Deleted */
[data-theme="dark"] .highlight .ge { color: #F8F8F2; font-style: italic } /* Generic.Emph */
[data-theme="dark"] .highlight .ges { color: #F8F8F2; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
[data-theme="dark"] .highlight .gr { color: #F8F8F2 } /* Generic.Error */
[data-theme="dark"] .highlight .gh { color: #F8F8F2 } /* Generic.Heading */
[data-theme="dark"] .highlight .gi { color: #A6E22E } /* Generic.Inserted */
[data-theme="dark"] .highlight .go { color: #66D9EF } /* Generic.Output */
[data-theme="dark"] .highlight .gp { color: #FF4689; font-weight: bold } /* Generic.Prompt */
[data-theme="dark"] .highlight .gs { color: #F8F8F2; font-weight: bold } /* Generic.Strong */
[data-theme="dark"] .highlight .gu { color: #959077 } /* Generic.Subheading */
[data-theme="dark"] .highlight .gt { color: #F8F8F2 } /* Generic.Traceback */
[data-theme="dark"] .highlight .kc { color: #66D9EF } /* Keyword.Constant */
[data-theme="dark"] .highlight .kd { color: #66D9EF } /* Keyword.Declaration */
[data-theme="dark"] .highlight .kn { color: #FF4689 } /* Keyword.Namespace */
[data-theme="dark"] .highlight .kp { color: #66D9EF } /* Keyword.Pseudo */
[data-theme="dark"] .highlight .kr { color: #66D9EF } /* Keyword.Reserved */
[data-theme="dark"] .highlight .kt { color: #66D9EF } /* Keyword.Type */
[data-theme="dark"] .highlight .ld { color: #E6DB74 } /* Literal.Date */
[data-theme="dark"] .highlight .m { color: #AE81FF } /* Literal.Number */
[data-theme="dark"] .highlight .s { color: #E6DB74 } /* Literal.String */
[data-theme="dark"] .highlight .na { color: #A6E22E } /* Name.Attribute */
[data-theme="dark"] .highlight .nb { color: #F8F8F2 } /* Name.Builtin */
[data-theme="dark"] .highlight .nc { color: #A6E22E } /* Name.Class */
[data-theme="dark"] .highlight .no { color: #66D9EF } /* Name.Constant */
[data-theme="dark"] .highlight .nd { color: #A6E22E } /* Name.Decorator */
[data-theme="dark"] .highlight .ni { color: #F8F8F2 } /* Name.Entity */
[data-theme="dark"] .highlight .ne { color: #A6E22E } /* Name.Exception */
[data-theme="dark"] .highlight .nf { color: #A6E22E } /* Name.Function */
[data-theme="dark"] .highlight .nl { color: #F8F8F2 } /* Name.Label */
[data-theme="dark"] .highlight .nn { color: #F8F8F2 } /* Name.Namespace */
[data-theme="dark"] .highlight .nx { color: #A6E22E } /* Name.Other */
[data-theme="dark"] .highlight .py { color: #F8F8F2 } /* Name.Property */
[data-theme="dark"] .highlight .nt { color: #FF4689 } /* Name.Tag */
[data-theme="dark"] .highlight .nv { color: #F8F8F2 } /* Name.Variable */
[data-theme="dark"] .highlight .ow { color: #FF4689 } /* Operator.Word */
[data-theme="dark"] .highlight .pm { color: #F8F8F2 } /* Punctuation.Marker */
[data-theme="dark"] .highlight .w { color: #F8F8F2 } /* Text.Whitespace */
[data-theme="dark"] .highlight .mb { color: #AE81FF } /* Literal.Number.Bin */
[data-theme="dark"] .highlight .mf { color: #AE81FF } /* Literal.Number.Float */
[data-theme="dark"] .highlight .mh { color: #AE81FF } /* Literal.Number.Hex */
[data-theme="dark"] .highlight .mi { color: #AE81FF } /* Literal.Number.Integer */
[data-theme="dark"] .highlight .mo { color: #AE81FF } /* Literal.Number.Oct */
[data-theme="dark"] .highlight .sa { color: #E6DB74 } /* Literal.String.Affix */
[data-theme="dark"] .highlight .sb { color: #E6DB74 } /* Literal.String.Backtick */
[data-theme="dark"] .highlight .sc { color: #E6DB74 } /* Literal.String.Char */
[data-theme="dark"] .highlight .dl { color: #E6DB74 } /* Literal.String.Delimiter */
[data-theme="dark"] .highlight .sd { color: #E6DB74 } /* Literal.String.Doc */
[data-theme="dark"] .highlight .s2 { color: #E6DB74 } /* Literal.String.Double */
[data-theme="dark"] .highlight .se { color: #AE81FF } /* Literal.String.Escape */
[data-theme="dark"] .highlight .sh { color: #E6DB74 } /* Literal.String.Heredoc */
[data-theme="dark"] .highlight .si { color: #E6DB74 } /* Literal.String.Interpol */
[data-theme="dark"] .highlight .sx { color: #E6DB74 } /* Literal.String.Other */
[data-theme="dark"] .highlight .sr { color: #E6DB74 } /* Literal.String.Regex */
[data-theme="dark"] .highlight .s1 { color: #E6DB74 } /* Literal.String.Single */
[data-theme="dark"] .highlight .ss { color: #E6DB74 } /* Literal.String.Symbol */
[data-theme="dark"] .highlight .bp { color: #F8F8F2 } /* Name.Builtin.Pseudo */
[data-theme="dark"] .highlight .fm { color: #A6E22E } /* Name.Function.Magic */
[data-theme="dark"] .highlight .vc { color: #F8F8F2 } /* Name.Variable.Class */
[data-theme="dark"] .highlight .vg { color: #F8F8F2 } /* Name.Variable.Global */
[data-theme="dark"] .highlight .vi { color: #F8F8F2 } /* Name.Variable.Instance */
[data-theme="dark"] .highlight .vm { color: #F8F8F2 } /* Name.Variable.Magic */
[data-theme="dark"] .highlight .il { color: #AE81FF } /* Literal.Number.Integer.Long */
/* Ensure our code metrics override Pygments defaults */
.highlight pre {
white-space: pre;
margin: 0;
padding: var(--code-pad-y) 0.75rem !important;
line-height: var(--code-line-height) !important;
font-size: var(--code-font-size) !important;
font-family: 'Cascadia Mono', 'Cascadia Code', 'JetBrains Mono', 'SF Mono', Monaco, 'Consolas', monospace !important;
border: none;
}
.line-numbers { line-height: var(--code-line-height) !important; }
.line-numbers .line-number { line-height: var(--code-line-height) !important; }
/* Custom CSS from frontmatter */
#output-setup {
overflow-x: auto;
}
.cell-output {
overflow: scroll;
}
.cell-stdout {
width: max-content;
overflow: scroll;
}
.cell-stderr {
width: max-content;
overflow: scroll;
max-height: 300px;
}
/* Cursor for tools */
body[data-tool="arrow"] .main-content {
cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="%23e53935" stroke-width="2"><path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l7.586 7.586"/><circle cx="11" cy="11" r="2"/></svg>') 12 12, crosshair;
}
body[data-tool="pen"] .main-content {
cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="%23e53935" stroke-width="2"><path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><circle cx="4" cy="20" r="2" fill="%23e53935"/></svg>') 4 20, pointer;
}
body[data-tool="eraser"] .main-content {
cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="%23e53935" stroke-width="2"><path d="M20 20H7l-7-7 7-7h13v14z"/><path d="M13 13l7-7"/><path d="M13 13L9 9"/></svg>') 12 12, auto;
}
/* Color picker styles */
.tools-section-title {
font-weight: bold;
color: var(--text-secondary);
font-size: 0.65rem;
margin: 0.75rem 0 0.5rem 0;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.color-row {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 0.25rem;
margin-bottom: 0.5rem;
}
.color-swatch {
width: 18px;
height: 18px;
border: 2px solid var(--border-primary);
border-radius: 3px;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
}
.color-swatch:hover {
transform: scale(1.1);
border-color: var(--text-secondary);
}
.color-swatch.selected {
border-color: var(--text-primary);
box-shadow: 0 0 0 2px var(--text-link);
}
.color-swatch.selected::after {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 10px;
font-weight: bold;
text-shadow: 1px 1px 1px black;
}
.color-input {
width: 24px;
height: 24px;
border: 2px solid var(--border-primary);
border-radius: 3px;
cursor: pointer;
background: none;
padding: 0;
grid-column: span 2;
justify-self: center;
}
.color-input:hover {
border-color: var(--text-secondary);
}
/* Thickness slider styles */
.thickness-row {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 0.75rem;
}
.thickness-slider {
flex: 1;
-webkit-appearance: none;
appearance: none;
height: 4px;
background: var(--border-primary);
border-radius: 2px;
outline: none;
opacity: 0.7;
transition: opacity 0.2s;
}
.thickness-slider:hover {
opacity: 1;
}
.thickness-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 12px;
height: 12px;
background: var(--text-link);
border-radius: 50%;
cursor: pointer;
}
.thickness-slider::-moz-range-thumb {
width: 12px;
height: 12px;
background: var(--text-link);
border-radius: 50%;
cursor: pointer;
border: none;
}
.thickness-value {
font-size: 0.7rem;
color: var(--text-secondary);
min-width: 20px;
text-align: right;
}
.highlight {
background: none !important;
}
/* Loading animations */
.loading-spinner {
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid var(--border-primary);
border-radius: 50%;
border-top-color: var(--text-link);
animation: spin 1s linear infinite;
margin-right: 8px;
vertical-align: middle;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.loading-skeleton {
display: inline-block;
background: var(--bg-tertiary);
background: linear-gradient(
90deg,
var(--bg-tertiary) 25%,
var(--bg-secondary) 50%,
var(--bg-tertiary) 75%
);
background-size: 200% 100%;
animation: loading-shimmer 2s ease-in-out infinite;
border-radius: 2px;
height: 1em;
width: 80px;
vertical-align: middle;
}
@keyframes loading-shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
/* Loading state for cell output */
.cell-output:has(.loading-spinner) {
opacity: 0.7;
background: var(--bg-secondary);
/* border-left: 3px solid var(--text-link); */
}
</style>
<script>
// --- Drag utilities ---
function clamp(val, min, max) { return Math.max(min, Math.min(max, val)); }
function restorePosition(el, storageKey) {
try {
const raw = localStorage.getItem(storageKey);
if (!raw) return;
const pos = JSON.parse(raw);
if (typeof pos.left === 'number' && typeof pos.top === 'number') {
el.style.left = pos.left + 'px';
el.style.top = pos.top + 'px';
el.style.right = 'auto';
el.style.bottom = 'auto';
}
} catch (_) {}
}
function savePosition(el, storageKey) {
try {
const left = parseFloat(el.style.left || 'NaN');
const top = parseFloat(el.style.top || 'NaN');
if (!Number.isNaN(left) && !Number.isNaN(top)) {
localStorage.setItem(storageKey, JSON.stringify({ left, top }));
}
} catch (_) {}
}
function makeDraggable(el, storageKey, handleEl) {
let dragging = false;
let startX = 0, startY = 0; // cursor
let origLeft = 0, origTop = 0; // element
const onMove = (e) => {
if (!dragging) return;
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
const clientY = e.touches ? e.touches[0].clientY : e.clientY;
const dx = clientX - startX;
const dy = clientY - startY;
const w = el.offsetWidth;
const h = el.offsetHeight;
const maxX = window.innerWidth - w;
const maxY = window.innerHeight - h;
const newLeft = clamp(origLeft + dx, 0, maxX);
const newTop = clamp(origTop + dy, 0, maxY);
el.style.left = newLeft + 'px';
el.style.top = newTop + 'px';
el.style.right = 'auto';
el.style.bottom = 'auto';
};
const endDrag = () => {
if (!dragging) return;
dragging = false;
document.removeEventListener('mousemove', onMove);
document.removeEventListener('mouseup', endDrag);
document.removeEventListener('touchmove', onMove);
document.removeEventListener('touchend', endDrag);
handleEl && (handleEl.style.cursor = 'grab');
savePosition(el, storageKey);
// ensure no-overlap constraint after a drag
try { layoutWidgetsStackedBottomRight(); } catch (_) {}
};
const startDrag = (e) => {
// Start from element's current on-screen rect
const elRect = el.getBoundingClientRect();
el.style.left = elRect.left + 'px';
el.style.top = elRect.top + 'px';
el.style.right = 'auto';
el.style.bottom = 'auto';
dragging = true;
startX = e.touches ? e.touches[0].clientX : e.clientX;
startY = e.touches ? e.touches[0].clientY : e.clientY;
origLeft = elRect.left;
origTop = elRect.top;
document.addEventListener('mousemove', onMove);
document.addEventListener('mouseup', endDrag);
document.addEventListener('touchmove', onMove, { passive: false });
document.addEventListener('touchend', endDrag);
handleEl && (handleEl.style.cursor = 'grabbing');
e.preventDefault();
};
(handleEl || el).addEventListener('mousedown', startDrag);
(handleEl || el).addEventListener('touchstart', startDrag, { passive: false });
// Apply any saved position on init
restorePosition(el, storageKey);
}
function toggleCell(cellId) {
const codeElement = document.getElementById('code-' + cellId);
const outputElement = document.getElementById('output-' + cellId);
if (codeElement) {
codeElement.classList.toggle('collapsed');
}
if (outputElement) {
outputElement.classList.toggle('collapsed');
}
updateIndicators(cellId);
encodeToolStateToUrl();
}
function toggleCode(cellId) {
const codeElement = document.getElementById('code-' + cellId);
if (codeElement) {
codeElement.classList.toggle('collapsed');
updateIndicators(cellId);
encodeToolStateToUrl();
}
}
function toggleOutput(cellId) {
const outputElement = document.getElementById('output-' + cellId);
if (outputElement) {
outputElement.classList.toggle('collapsed');
updateIndicators(cellId);
encodeToolStateToUrl();
}
}
function toggleUvLogs(headerElement) {
const contentElement = headerElement.nextElementSibling;
if (contentElement) {
const isCollapsed = contentElement.style.display === 'none';
contentElement.style.display = isCollapsed ? 'block' : 'none';
headerElement.textContent = isCollapsed ? '▼ UV Install Logs' : '▶ UV Install Logs';
// Update the header indicator if it exists
const uvLogsDiv = headerElement.parentElement;
if (uvLogsDiv && uvLogsDiv.id && uvLogsDiv.id.startsWith('uv-logs-')) {
const cellId = uvLogsDiv.id.replace('uv-logs-', '');
const indicatorElement = document.getElementById('uv-indicator-' + cellId);
if (indicatorElement) {
indicatorElement.textContent = isCollapsed ? '▼ uv-logs' : '▶ uv-logs';
}
}
}
}
function toggleUvLogsFromHeader(cellId) {
const uvLogsElement = document.getElementById('uv-logs-' + cellId);
const indicatorElement = document.getElementById('uv-indicator-' + cellId);
if (uvLogsElement) {
const headerElement = uvLogsElement.querySelector('.uv-logs-header');
const contentElement = uvLogsElement.querySelector('.uv-logs-content');
if (contentElement && headerElement) {
const isCollapsed = contentElement.style.display === 'none';
contentElement.style.display = isCollapsed ? 'block' : 'none';
headerElement.textContent = isCollapsed ? '▼ UV Install Logs' : '▶ UV Install Logs';
if (indicatorElement) {
indicatorElement.textContent = isCollapsed ? '▼ uv-logs' : '▶ uv-logs';
}
}
}
}
function updateIndicators(cellId) {
const codeElement = document.getElementById('code-' + cellId);
const outputElement = document.getElementById('output-' + cellId);
const indicators = document.querySelector(`[onclick*="${cellId}"]`)?.closest('.cell-header')?.querySelector('.collapse-indicators');
if (indicators) {
const codeCollapsed = codeElement && codeElement.classList.contains('collapsed');
const outputCollapsed = outputElement && outputElement.classList.contains('collapsed');
const codeIcon = codeCollapsed ? '▶' : '▼';
const outputIcon = outputCollapsed ? '▶' : '▼';
const codeSpan = indicators.querySelector('[onclick*="toggleCode"]');
const outputSpan = indicators.querySelector('[onclick*="toggleOutput"]');
if (codeSpan) codeSpan.innerHTML = `${codeIcon} code`;
if (outputSpan) outputSpan.innerHTML = `${outputIcon} output`;
}
}
function toggleTheme() {
const html = document.documentElement;
const currentTheme = html.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
html.setAttribute('data-theme', newTheme);
localStorage.setItem('uvnote-theme', newTheme);
updateThemeIcon();
updateUiDebug();
}
// Two panel code removed
function updateThemeIcon() {
const theme = document.documentElement.getAttribute('data-theme');
const toggle = document.querySelector('.theme-toggle');
if (toggle) {
toggle.textContent = theme === 'dark' ? 'light' : 'dark';
}
}
function setUiTheme(newUi) {
if (newUi !== 'default' && newUi !== 'none' && newUi !== 'monocolor') return;
const html = document.documentElement;
html.setAttribute('data-ui', newUi);
try { localStorage.setItem('uvnote-ui', newUi); } catch (_) {}
updateUiMenu();
updateUiDebug();
}
function updateUiMenu() {
const ui = document.documentElement.getAttribute('data-ui') || 'default';
const checks = {
default: document.getElementById('checkbox-ui-default'),
none: document.getElementById('checkbox-ui-none'),
monocolor: document.getElementById('checkbox-ui-monocolor')
};
if (checks.default) checks.default.textContent = ui === 'default' ? '☑' : '☐';
if (checks.none) checks.none.textContent = ui === 'none' ? '☑' : '☐';
if (checks.monocolor) checks.monocolor.textContent = ui === 'monocolor' ? '☑' : '☐';
}
function updateUiDebug() {
const ui = document.documentElement.getAttribute('data-ui') || 'default';
const color = document.documentElement.getAttribute('data-theme') || 'light';
const el = document.getElementById('ui-debug');
if (el) {
el.textContent = `UI: ${ui} | Color: ${color}`;
}
}
// Line selection and deep-linking
function clearLineSelections() {
try {
document.querySelectorAll('.code-line-highlight').forEach(el => { el.style.display = 'none'; });
document.querySelectorAll('.line-number.selected').forEach(el => el.classList.remove('selected'));
} catch (_) {}
}
let _selection = null; // { cellId, a, b }
function clearSelection(updateUrl) {
clearLineSelections();
_selection = null;
if (updateUrl) {
try {
const url = new URL(window.location.href);
url.searchParams.delete('cell');
url.searchParams.delete('line');
history.replaceState(null, '', url.toString());
} catch (_) {}
}
updateStateIndicator();
}
function selectCellLine(cellId, line, updateUrl) {
try {
// Ensure only one selection across the whole document
clearLineSelections();
const codeBox = document.getElementById(`code-${cellId}`);
if (!codeBox) return;
const pre = codeBox.querySelector('.highlight pre');
const overlay = document.getElementById(`line-highlight-${cellId}`);
const numbers = document.getElementById(`lines-${cellId}`);
if (!pre || !overlay) return;
// Measure line height directly from computed style
const preStyle = getComputedStyle(pre);
const padTop = parseFloat(preStyle.paddingTop || '0');
const lh = parseFloat(preStyle.lineHeight || '20');
// Position overlay
overlay.style.display = 'block';
overlay.style.height = `${lh}px`;
overlay.style.top = `${pre.offsetTop + padTop + (line - 1) * lh}px`;
// Update selected class in line numbers
if (numbers) {
numbers.querySelectorAll('.line-number').forEach(a => a.classList.remove('selected'));
const sel = numbers.querySelector(`.line-number[data-line="${line}"]`);
if (sel) sel.classList.add('selected');
}
if (updateUrl) {
const url = new URL(window.location.href);
url.searchParams.set('cell', cellId);
url.searchParams.set('line', String(line));
history.replaceState(null, '', url.toString());
}
_selection = { cellId, a: line, b: line };
updateStateIndicator();
} catch (e) { console.warn('selectCellLine error', e); }
}
function selectCellLines(cellId, startLine, endLine, updateUrl) {
try {
// normalize order
const a = Math.min(startLine, endLine);
const b = Math.max(startLine, endLine);
clearLineSelections();
const codeBox = document.getElementById(`code-${cellId}`);
if (!codeBox) return;
const pre = codeBox.querySelector('.highlight pre');
const overlay = document.getElementById(`line-highlight-${cellId}`);
const numbers = document.getElementById(`lines-${cellId}`);
if (!pre || !overlay) return;
const preStyle = getComputedStyle(pre);
const padTop = parseFloat(preStyle.paddingTop || '0');
const lh = parseFloat(preStyle.lineHeight || '20');
overlay.style.display = 'block';
overlay.style.top = `${pre.offsetTop + padTop + (a - 1) * lh}px`;
overlay.style.height = `${(b - a + 1) * lh}px`;
if (numbers) {
numbers.querySelectorAll('.line-number').forEach(a => a.classList.remove('selected'));
for (let i = a; i <= b; i++) {
const el = numbers.querySelector(`.line-number[data-line="${i}"]`);
if (el) el.classList.add('selected');
}
}
if (updateUrl) {
const url = new URL(window.location.href);
url.searchParams.set('cell', cellId);
if (a === b) url.searchParams.set('line', String(a));
else url.searchParams.set('line', `${a}-${b}`);
history.replaceState(null, '', url.toString());
}
_selection = { cellId, a, b };
updateStateIndicator();
} catch (e) { console.warn('selectCellLines error', e); }
}
// Drag-to-select support on line numbers
let _lineDrag = { active: false, cellId: null, start: 0 };
function onLineNumberMouseDown(e) {
const a = e.target.closest('.line-number');
if (!a) return;
e.preventDefault();
const cellId = a.dataset.cell;
const line = parseInt(a.dataset.line || '1', 10) || 1;
// Toggle off if this exact single line is already the only selection
const numbers = document.getElementById(`lines-${cellId}`);
if (numbers) {
const selected = Array.from(numbers.querySelectorAll('.line-number.selected')).map(n => parseInt(n.dataset.line||'0',10)).filter(Boolean);
if (selected.length === 1 && selected[0] === line) {
clearSelection(true);
return;
}
}
_lineDrag.active = true;
_lineDrag.cellId = cellId;
_lineDrag.start = line;
selectCellLines(_lineDrag.cellId, _lineDrag.start, _lineDrag.start, false);
}
function onDocMouseMove(e) {
if (!_lineDrag.active) return;
const el = document.elementFromPoint(e.clientX, e.clientY);
if (!el) return;
const a = el.closest && el.closest('.line-number');
if (!a) return;
if (a.dataset.cell !== _lineDrag.cellId) return;
const cur = parseInt(a.dataset.line || '1', 10) || 1;
selectCellLines(_lineDrag.cellId, _lineDrag.start, cur, false);
}
function onDocMouseUp(e) {
if (!_lineDrag.active) return;
const last = document.querySelector('.line-number.selected:last-of-type');
// finalize URL using the current selected range
const numbers = document.getElementById(`lines-${_lineDrag.cellId}`);
if (numbers) {
const selected = Array.from(numbers.querySelectorAll('.line-number.selected')).map(n => parseInt(n.dataset.line||'0',10)).filter(Boolean);
if (selected.length) {
const a = Math.min(...selected); const b = Math.max(...selected);
selectCellLines(_lineDrag.cellId, a, b, true);
}
}
_lineDrag.active = false; _lineDrag.cellId = null; _lineDrag.start = 0;
}
function applyLocationFromUrl() {
try {
const url = new URL(window.location.href);
const cell = url.searchParams.get('cell');
const lineParam = url.searchParams.get('line');
if (cell && lineParam) {
if (lineParam.includes('-')) {
const [a, b] = lineParam.split('-').map(x => parseInt(x, 10));
if (!Number.isNaN(a) && !Number.isNaN(b)) selectCellLines(cell, a, b, false);
} else {
const l = parseInt(lineParam, 10);
if (!Number.isNaN(l)) selectCellLine(cell, l, false);
}
}
// Apply tool parameters from URL
applyToolsFromUrl(url.searchParams);
// Cell states will be applied later in DOMContentLoaded with proper timing
const encodedCellStates = url.searchParams.get('cells');
console.log('Encoded cell states from URL:', encodedCellStates);
} catch (_) {}
}
function applyToolsFromUrl(params) {
try {
// Check if tools widget should be shown
const showTools = params.get('tools');
if (showTools === '1') {
// Mark that tool was loaded from URL
_urlLoadedTool = true;
// Apply color
const color = params.get('color');
if (color && /^[0-9a-fA-F]{6}$/.test(color)) {
setStoredArrowColor('#' + color);
}
// Apply thickness
const thickness = params.get('thickness');
if (thickness) {
const value = parseInt(thickness, 10);
if (value >= 1 && value <= 10) {
setStoredLineThickness(value);
}
}
// Don't override fadeout time for URL-loaded tools - let individual shapes decide
// Load shapes from URL
const encodedShapes = params.get('shapes');
if (encodedShapes) {
const decodedShapes = decodeShapesFromUrl(encodedShapes);
if (decodedShapes.length > 0) {
_shapes = decodedShapes;
saveShapes();
// Trigger render after overlay is initialized
setTimeout(() => {
renderOverlay();
}, 300);
}
}
// Wait for widgets to be initialized before showing tools
setTimeout(() => {
const toolsWidget = document.querySelector('.tools-widget');
const checkbox = document.getElementById('checkbox-tools');
if (toolsWidget && checkbox) {
toolsWidget.style.display = 'block';
checkbox.textContent = '☑';
localStorage.setItem('uvnote-widget-tools', 'visible');
}
// Apply active tool
const activeTool = params.get('tool');
if (activeTool && ['arrow', 'pen', 'eraser', 'spotlight'].includes(activeTool)) {
const toolBtn = Array.from(document.querySelectorAll('.tool-button')).find(btn => btn.textContent === activeTool);
if (toolBtn) {
toolBtn.click();
}
}
// Re-layout widgets after showing tools
layoutWidgetsStackedBottomRight();
}, 200);
}
} catch (_) {}
}
function captureInitialCellStates() {
const cells = document.querySelectorAll('.cell');
cells.forEach(cell => {
const cellId = cell.id.replace('cell-', '');
const codeEl = document.getElementById('code-' + cellId);
const outputEl = document.getElementById('output-' + cellId);
if (codeEl || outputEl) {
const state = {};
if (codeEl) {
state.c = codeEl.classList.contains('collapsed') ? 0 : 1;
}
if (outputEl) {
state.o = outputEl.classList.contains('collapsed') ? 0 : 1;
}
_initialCellStates[cellId] = state;
}
});
console.log('Captured initial cell states:', _initialCellStates);
}
function encodeCellStatesToUrl() {
// Get all cells and their collapse states
const cells = document.querySelectorAll('.cell');
const cellStates = {};
console.log('Found cells:', cells.length);
cells.forEach(cell => {
const cellId = cell.id.replace('cell-', '');
const codeEl = document.getElementById('code-' + cellId);
const outputEl = document.getElementById('output-' + cellId);
const initialState = _initialCellStates[cellId] || {};
console.log(`Encoding cell ${cellId}:`, {
codeEl: !!codeEl,
outputEl: !!outputEl,
codeCollapsed: codeEl ? codeEl.classList.contains('collapsed') : 'N/A',
outputCollapsed: outputEl ? outputEl.classList.contains('collapsed') : 'N/A',
initialState: initialState
});
if (codeEl || outputEl) {
const state = {};
let hasChanges = false;
if (codeEl) {
const currentCodeState = codeEl.classList.contains('collapsed') ? 0 : 1;
const initialCodeState = initialState.c;
// Only encode if different from initial state
if (initialCodeState !== undefined && currentCodeState !== initialCodeState) {
state.c = currentCodeState;
hasChanges = true;
}
}
if (outputEl) {
const currentOutputState = outputEl.classList.contains('collapsed') ? 0 : 1;
const initialOutputState = initialState.o;
// Only encode if different from initial state
if (initialOutputState !== undefined && currentOutputState !== initialOutputState) {
state.o = currentOutputState;
hasChanges = true;
}
}
// Only include cell if it has changes from initial state
if (hasChanges) {
cellStates[cellId] = state;
console.log(`Added cell ${cellId}:`, state);
}
}
});
console.log('Final cell states to encode:', cellStates);
// Return empty string if no changed cells
if (Object.keys(cellStates).length === 0) return '';
// Encode as compact base64 string
const encoded = btoa(JSON.stringify(cellStates));
console.log('Encoded cell states:', encoded);
return encoded;
}
function decodeCellStatesFromUrl(encodedStates) {
if (!encodedStates) return {};
try {
return JSON.parse(atob(encodedStates));
} catch (e) {
console.error('Failed to decode cell states:', e);
return {};
}
}
function applyCellStatesFromUrl(cellStates) {
console.log('Applying cell states from URL:', cellStates);
Object.entries(cellStates).forEach(([cellId, state]) => {
const codeEl = document.getElementById('code-' + cellId);
const outputEl = document.getElementById('output-' + cellId);
console.log(`Cell ${cellId}:`, {
codeEl: !!codeEl,
outputEl: !!outputEl,
state: state
});
if (codeEl && state.c !== undefined) {
if (state.c === 0) {
codeEl.classList.add('collapsed');
console.log(`Collapsed code for cell ${cellId}`, {
hasCollapsedClass: codeEl.classList.contains('collapsed'),
computedDisplay: getComputedStyle(codeEl).display,
classList: Array.from(codeEl.classList),
elementId: codeEl.id
});
} else {
codeEl.classList.remove('collapsed');
codeEl.classList.add('expanded'); // Explicitly add expanded class
console.log(`Expanded code for cell ${cellId}`, {
hasCollapsedClass: codeEl.classList.contains('collapsed'),
hasExpandedClass: codeEl.classList.contains('expanded'),
computedDisplay: getComputedStyle(codeEl).display,
classList: Array.from(codeEl.classList),
elementId: codeEl.id
});
}
}
if (outputEl && state.o !== undefined) {
if (state.o === 0) {
outputEl.classList.add('collapsed');
console.log(`Collapsed output for cell ${cellId}`);
} else {
outputEl.classList.remove('collapsed');
console.log(`Expanded output for cell ${cellId}`);
}
}
// Update visual indicators and force style recalculation
try {
updateIndicators(cellId);
// Force browser to recalculate styles
if (codeEl) {
codeEl.offsetHeight; // Force reflow
console.log(`After indicators update - code visible: ${getComputedStyle(codeEl).display !== 'none'}`);
}
if (outputEl) {
outputEl.offsetHeight; // Force reflow
console.log(`After indicators update - output visible: ${getComputedStyle(outputEl).display !== 'none'}`);
}
} catch (e) {
console.error(`Error updating indicators for cell ${cellId}:`, e);
}
});
}
function encodeShapesToUrl() {
// Encode shapes as compact base64 string
if (_shapes.length === 0) return '';
const shapeData = _shapes.map(shape => {
const baseData = {
ct: shape.createdAt, // creation timestamp
fo: shape.fadeoutTime || getFadeoutTime() // fadeout time for this shape
};
if (shape.type === 'arrow') {
return {
...baseData,
t: 'a',
x1: Math.round(shape.x1),
y1: Math.round(shape.y1),
x2: Math.round(shape.x2),
y2: Math.round(shape.y2),
c: shape.color.substring(1), // remove #
w: shape.width
};
} else if (shape.type === 'pen') {
return {
...baseData,
t: 'p',
pts: shape.points.map(p => [Math.round(p.x), Math.round(p.y)]),
c: shape.color.substring(1),
w: shape.width
};
} else if (shape.type === 'spotlight') {
return {
...baseData,
t: 's',
x: Math.round(shape.x),
y: Math.round(shape.y),
r: Math.round(shape.radius)
};
}
}).filter(Boolean);
return btoa(JSON.stringify(shapeData));
}
function decodeShapesFromUrl(encodedShapes) {
if (!encodedShapes) return [];
try {
const shapeData = JSON.parse(atob(encodedShapes));
return shapeData.map(data => {
const base = {
createdAt: data.ct || Date.now(), // use encoded timestamp or current time
fadeoutTime: data.fo || 0, // use encoded fadeout time or 0 (never fade)
opacity: 1.0
};
if (data.t === 'a') {
return {
...base,
type: 'arrow',
x1: data.x1,
y1: data.y1,
x2: data.x2,
y2: data.y2,
color: '#' + data.c,
width: data.w
};
} else if (data.t === 'p') {
return {
...base,
type: 'pen',
points: data.pts.map(([x, y]) => ({ x, y })),
color: '#' + data.c,
width: data.w
};
} else if (data.t === 's') {
return {
...base,
type: 'spotlight',
x: data.x,
y: data.y,
radius: data.r,
color: '#000000'
};
}
}).filter(Boolean);
} catch (e) {
console.error('Failed to decode shapes:', e);
return [];
}
}
function encodeToolStateToUrl() {
// Don't update URL during initialization
if (_isInitializing) {
return window.location.href;
}
const params = new URLSearchParams(window.location.search);
// Check if tools widget is visible and has an active tool
const toolsWidget = document.querySelector('.tools-widget');
const activeTool = document.body.dataset.tool;
const hasActiveTool = activeTool && activeTool !== 'none';
const toolsWidgetVisible = toolsWidget && getComputedStyle(toolsWidget).display !== 'none';
// Always handle shapes regardless of tool state
const encodedShapes = encodeShapesToUrl();
if (encodedShapes) {
params.set('shapes', encodedShapes);
} else {
params.delete('shapes');
}
// Always preserve existing cell states from URL if present
const existingCellStates = params.get('cells');
if (existingCellStates) {
// Keep existing cell states - don't re-encode from DOM
params.set('cells', existingCellStates);
} else {
// Only encode new cell states if none exist in URL
const encodedCellStates = encodeCellStatesToUrl();
if (encodedCellStates) {
params.set('cells', encodedCellStates);
}
}
if (toolsWidgetVisible && hasActiveTool) {
// Include tool params when widget is visible AND tool is active
params.set('tools', '1');
params.set('tool', activeTool);
// Get color (without # prefix)
const color = getArrowColor();
if (color && color.startsWith('#')) {
params.set('color', color.substring(1));
}
// Get thickness
const thickness = getLineThickness();
params.set('thickness', thickness.toString());
} else {
// Remove tool state params but keep shapes
params.delete('tools');
params.delete('tool');
params.delete('color');
params.delete('thickness');
params.delete('fadeout');
}
// Update URL without reloading
const newUrl = window.location.pathname + (params.toString() ? '?' + params.toString() : '') + window.location.hash;
window.history.replaceState(null, '', newUrl);
return window.location.href;
}
function resetLayout() {
try {
// Clear all uvnote-* keys
const allKeys = Object.keys(localStorage);
const uvnoteKeys = allKeys.filter(key => key.startsWith('uvnote-'));
uvnoteKeys.forEach(k => localStorage.removeItem(k));
} catch (_) {}
// Clear any active selection and remove URL params
try { clearSelection(true); } catch(_) {}
// Reset active tool if any
try { window.setActiveTool('none'); } catch(_) {}
// Clear shapes
try { _shapes = []; saveShapes(); } catch(_) {}
// Reset URL-loaded tool flag
try { _urlLoadedTool = false; } catch(_) {}
// Reset all cells to expanded state
try {
const cells = document.querySelectorAll('.cell');
cells.forEach(cell => {
const cellId = cell.id.replace('cell-', '');
const codeEl = document.getElementById('code-' + cellId);
const outputEl = document.getElementById('output-' + cellId);
if (codeEl) codeEl.classList.remove('collapsed');
if (outputEl) outputEl.classList.remove('collapsed');
updateIndicators(cellId);
});
} catch(_) {}
// Clear ALL URL parameters and reload with clean URL
try {
const cleanUrl = window.location.pathname + window.location.hash;
window.location.href = cleanUrl; // Use window.location.href instead of history.replaceState + reload
} catch (_) {
// Fallback - reload current page
location.reload();
}
}
function toggleMenu() {
const menuButton = document.querySelector('.menu-button');
if (menuButton) {
menuButton.classList.toggle('active');
}
}
function toggleWidget(widgetName) {
let widget;
let checkbox;
// Close the menu first
const menuButton = document.querySelector('.menu-button');
if (menuButton) {
menuButton.classList.remove('active');
}
switch(widgetName) {
case 'tools':
widget = document.querySelector('.tools-widget');
checkbox = document.getElementById('checkbox-tools');
break;
case 'file-explorer':
widget = document.querySelector('.file-explorer');
checkbox = document.getElementById('checkbox-file-explorer');
break;
case 'minimap':
widget = document.querySelector('.minimap');
checkbox = document.getElementById('checkbox-minimap');
break;
case 'status':
widget = document.querySelector('.status-widget');
checkbox = document.getElementById('checkbox-status');
break;
default:
return;
}
if (widget && checkbox) {
const isVisible = getComputedStyle(widget).display !== 'none';
widget.style.display = isVisible ? 'none' : 'block';
checkbox.textContent = isVisible ? '☐' : '☑';
// Save state to localStorage
try {
localStorage.setItem(`uvnote-widget-${widgetName}`, isVisible ? 'hidden' : 'visible');
} catch (_) {}
// Re-layout widgets after visibility change
try {
layoutWidgetsStackedBottomRight();
} catch (_) {}
// Update URL when tools widget visibility changes
if (widgetName === 'tools') {
encodeToolStateToUrl();
}
}
}
function initializeWidgetVisibility() {
const widgets = [
{ name: 'tools', selector: '.tools-widget' },
{ name: 'file-explorer', selector: '.file-explorer' },
{ name: 'minimap', selector: '.minimap' },
{ name: 'status', selector: '.status-widget' }
];
widgets.forEach(({ name, selector }) => {
const defaultState = name === 'status' ? 'visible' : 'hidden';
const savedState = localStorage.getItem(`uvnote-widget-${name}`) || defaultState;
const widget = document.querySelector(selector);
const checkbox = document.getElementById(`checkbox-${name}`);
if (widget && checkbox) {
const isVisible = savedState === 'visible';
widget.style.display = isVisible ? 'block' : 'none';
checkbox.textContent = isVisible ? '☑' : '☐';
}
});
}
// Close menu when clicking outside
document.addEventListener('click', function(event) {
const menuButton = document.querySelector('.menu-button');
// Don't close if clicking on a menu item (let the item handler close it)
if (menuButton && !menuButton.contains(event.target)) {
menuButton.classList.remove('active');
}
});
// Layout: stack widgets bottom-right and equalize widths
function hasCustomWidgetPositions() {
try {
return (
localStorage.getItem('uvnote-minimap-pos') ||
localStorage.getItem('uvnote-file-explorer-pos') ||
localStorage.getItem('uvnote-tools-pos')
);
} catch (_) { return false; }
}
function rectsOverlap(r1, r2) {
return !(r1.right <= r2.left || r2.right <= r1.left || r1.bottom <= r2.top || r2.bottom <= r1.top);
}
function widgetsOverlap(widgets) {
for (let i = 0; i < widgets.length; i++) {
const a = widgets[i];
const ra = a.getBoundingClientRect();
for (let j = i + 1; j < widgets.length; j++) {
const b = widgets[j];
const rb = b.getBoundingClientRect();
if (rectsOverlap(ra, rb)) return true;
}
}
return false;
}
function applyStackLayout(widgets, order) {
if (!widgets.length) return;
// Fixed equal width
const fixedWidth = 220;
widgets.forEach(el => { el.style.width = fixedWidth + 'px'; });
// Fit heights if needed to avoid overflow
const gap = 12;
const available = Math.max(0, window.innerHeight - 40 - gap * (order.length - 1));
const eachMax = Math.floor(available / order.length);
order.forEach(el => {
el.style.maxHeight = eachMax + 'px';
el.style.overflowY = 'auto';
});
// Stack bottom-up in the requested order
let bottomOffset = 20; // base gutter
order.forEach(el => {
el.style.left = 'auto';
el.style.top = 'auto';
el.style.right = '20px';
el.style.bottom = bottomOffset + 'px';
bottomOffset += el.offsetHeight + gap;
});
}
function layoutWidgetsStackedBottomRight() {
const minimap = document.querySelector('.minimap');
const fileExplorer = document.querySelector('.file-explorer');
const tools = document.querySelector('.tools-widget');
const status = document.querySelector('.status-widget');
const widgets = [minimap, fileExplorer, tools, status].filter(el => el && getComputedStyle(el).display !== 'none');
if (!widgets.length) return;
const order = [minimap, fileExplorer, tools, status].filter(Boolean).filter(el => getComputedStyle(el).display !== 'none');
// If user placed custom positions and there is no overlap, respect them.
if (hasCustomWidgetPositions() && !widgetsOverlap(widgets)) return;
applyStackLayout(widgets, order);
}
// Panel icon removed
let _minimapScrollContainer = null;
let _minimapScrollHandler = null;
function initMinimap() {
// Generate minimap content
const minimap = createMinimap();
document.body.appendChild(minimap);
// Make draggable (use title as handle)
const mTitle = minimap.querySelector('.minimap-title');
makeDraggable(minimap, 'uvnote-minimap-pos', mTitle);
// Attach scroll listener to window (two-panel removed)
_minimapScrollContainer = window;
if (_minimapScrollContainer) {
_minimapScrollHandler = () => updateMinimapActive();
if (_minimapScrollContainer === window) {
window.addEventListener('scroll', _minimapScrollHandler);
} else {
_minimapScrollContainer.addEventListener('scroll', _minimapScrollHandler);
}
}
updateMinimapActive();
}
function teardownMinimap() {
const minimap = document.querySelector('.minimap');
if (minimap && minimap.parentNode) minimap.parentNode.removeChild(minimap);
if (_minimapScrollContainer && _minimapScrollHandler) {
if (_minimapScrollContainer === window) {
window.removeEventListener('scroll', _minimapScrollHandler);
} else {
_minimapScrollContainer.removeEventListener('scroll', _minimapScrollHandler);
}
}
_minimapScrollContainer = null;
_minimapScrollHandler = null;
}
function initFileExplorer() {
// Generate file explorer content
const fileExplorer = createFileExplorer();
document.body.appendChild(fileExplorer);
}
function createMinimap() {
const minimap = document.createElement('div');
minimap.className = 'minimap';
const title = document.createElement('div');
title.className = 'minimap-title';
title.textContent = 'navigation';
minimap.appendChild(title);
// Find all headings and cells
const root = document.querySelector('.main-content') || document;
const headings = root.querySelectorAll('h1, h2, h3, h4, h5, h6');
const cells = root.querySelectorAll('.cell');
// Combine and sort by position
const items = [];
headings.forEach(heading => {
const id = heading.id || generateId(heading.textContent);
if (!heading.id) heading.id = id;
items.push({
element: heading,
type: 'heading',
level: parseInt(heading.tagName.charAt(1)),
text: heading.textContent.trim(),
id: id,
position: heading.getBoundingClientRect().top + window.scrollY
});
});
cells.forEach(cell => {
const header = cell.querySelector('.cell-header');
if (header) {
const id = cell.id || `cell-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
if (!cell.id) cell.id = id;
items.push({
element: cell,
type: 'cell',
text: header.textContent.trim(),
id: id,
position: cell.getBoundingClientRect().top + window.scrollY
});
}
});
// Sort by position
items.sort((a, b) => a.position - b.position);
// Create minimap items
items.forEach(item => {
const link = document.createElement('a');
link.className = `minimap-item ${item.type === 'heading' ? 'minimap-heading' : 'minimap-cell'}`;
if (item.type === 'heading') {
link.classList.add(`h${item.level}`);
}
link.textContent = item.text.length > 25 ? item.text.substring(0, 22) + '...' : item.text;
link.href = `#${item.id}`;
link.onclick = function(e) {
e.preventDefault();
item.element.scrollIntoView({ behavior: 'smooth', block: 'start' });
};
minimap.appendChild(link);
});
return minimap;
}
function generateId(text) {
return text.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.substring(0, 20);
}
function updateMinimapActive() {
const minimapItems = document.querySelectorAll('.minimap-item');
const container = _minimapScrollContainer || window;
const containerRect = container === window ? null : container.getBoundingClientRect();
const scrollPos = (container === window ? window.scrollY : container.scrollTop) + 100; // Offset for better detection
let activeItem = null;
minimapItems.forEach(item => {
const targetId = item.getAttribute('href').substring(1);
const target = document.getElementById(targetId);
if (target) {
const rectTop = target.getBoundingClientRect().top;
const targetPos = (container === window)
? rectTop + window.scrollY
: rectTop - containerRect.top + container.scrollTop;
if (targetPos <= scrollPos) {
activeItem = item;
}
}
item.classList.remove('active');
});
if (activeItem) {
activeItem.classList.add('active');
}
}
function createFileExplorer() {
const fileExplorer = document.createElement('div');
fileExplorer.className = 'file-explorer';
const title = document.createElement('div');
title.className = 'file-explorer-title';
title.textContent = 'files';
fileExplorer.appendChild(title);
// Make draggable (use title as handle)
makeDraggable(fileExplorer, 'uvnote-file-explorer-pos', title);
// Scripts section
const scriptsSection = document.createElement('div');
scriptsSection.className = 'file-explorer-section';
const scriptsTitle = document.createElement('div');
scriptsTitle.className = 'file-explorer-section-title';
scriptsTitle.textContent = 'scripts';
scriptsSection.appendChild(scriptsTitle);
// Find all cells and list their script files (single panel)
const root = document.querySelector('.main-content') || document;
const cells = root.querySelectorAll('.cell');
cells.forEach(cell => {
const header = cell.querySelector('.cell-header');
if (header) {
const cellText = header.textContent.trim();
const cellMatch = cellText.match(/Cell: ([a-zA-Z_][a-zA-Z0-9_]*)/);
if (cellMatch) {
const cellId = cellMatch[1];
const scriptItem = document.createElement('div');
scriptItem.className = 'file-explorer-item script';
scriptItem.textContent = `${cellId}.py`;
scriptItem.onclick = function() {
cell.scrollIntoView({ behavior: 'smooth', block: 'start' });
};
scriptsSection.appendChild(scriptItem);
}
}
});
fileExplorer.appendChild(scriptsSection);
// Artifacts section
const artifactsSection = document.createElement('div');
artifactsSection.className = 'file-explorer-section';
const artifactsTitle = document.createElement('div');
artifactsTitle.className = 'file-explorer-section-title';
artifactsTitle.textContent = 'artifacts';
artifactsSection.appendChild(artifactsTitle);
// Find all artifact links (single panel)
const artifactsRoot = document.querySelector('.main-content') || document;
const artifacts = artifactsRoot.querySelectorAll('.artifact');
if (artifacts.length === 0) {
const noArtifacts = document.createElement('div');
noArtifacts.className = 'file-explorer-item artifact';
noArtifacts.textContent = '(none)';
noArtifacts.style.opacity = '0.5';
artifactsSection.appendChild(noArtifacts);
} else {
artifacts.forEach(artifact => {
const artifactItem = document.createElement('div');
artifactItem.className = 'file-explorer-item artifact';
artifactItem.textContent = artifact.textContent;
artifactItem.onclick = function() {
artifact.click();
};
artifactsSection.appendChild(artifactItem);
});
}
fileExplorer.appendChild(artifactsSection);
return fileExplorer;
}
function initStatusWidget() {
let el = document.querySelector('.status-widget');
if (!el) {
el = document.createElement('div');
el.className = 'status-widget';
el.id = 'status-widget';
el.textContent = 'ready — Esc';
document.body.appendChild(el);
}
}
// Tools widget
let _cursorX = 0;
let _cursorY = 0;
let _cursorVisible = false;
function setActiveTool(tool) {
if (!tool || tool === 'none') {
document.body.dataset.tool = 'none';
localStorage.setItem('uvnote-active-tool', 'none');
setOverlayActive(false);
_cursorVisible = false;
// Remove active class from all tool buttons when deactivating
const toolButtons = document.querySelectorAll('.tools-widget .tool-button');
toolButtons.forEach(btn => btn.classList.remove('active'));
updateStateIndicator();
encodeToolStateToUrl();
return;
}
document.body.dataset.tool = tool;
localStorage.setItem('uvnote-active-tool', tool);
setOverlayActive(true);
_cursorVisible = true;
updateStateIndicator();
encodeToolStateToUrl();
}
// Make setActiveTool globally accessible for ESC key handler
window.setActiveTool = setActiveTool;
function getArrowColor() {
const saved = localStorage.getItem('uvnote-arrow-color');
if (saved) return saved;
return '#e53935'; // Default red color
}
function setStoredArrowColor(color) {
try { localStorage.setItem('uvnote-arrow-color', color); } catch (_) {}
}
function getLineThickness() {
const saved = localStorage.getItem('uvnote-line-thickness');
if (saved) return parseInt(saved, 10);
return 6; // default thickness
}
function setStoredLineThickness(thickness) {
try { localStorage.setItem('uvnote-line-thickness', thickness); } catch (_) {}
}
function getFadeoutTime() {
const saved = localStorage.getItem('uvnote-fadeout-time');
if (saved) return parseInt(saved, 10);
return 5; // default 5 seconds
}
function setStoredFadeoutTime(seconds) {
try { localStorage.setItem('uvnote-fadeout-time', seconds); } catch (_) {}
}
function createToolsWidget() {
const tools = document.createElement('div');
tools.className = 'tools-widget';
const title = document.createElement('div');
title.className = 'tools-title';
title.textContent = 'tools';
tools.appendChild(title);
const row = document.createElement('div');
row.className = 'tools-row';
tools.appendChild(row);
// Arrow tool
const arrowBtn = document.createElement('div');
arrowBtn.className = 'tool-button';
arrowBtn.textContent = 'arrow';
arrowBtn.onclick = function() {
const isActive = arrowBtn.classList.contains('active');
if (isActive) {
arrowBtn.classList.remove('active');
setActiveTool('none');
} else {
tools.querySelectorAll('.tool-button').forEach(b => b.classList.remove('active'));
arrowBtn.classList.add('active');
setActiveTool('arrow');
}
};
row.appendChild(arrowBtn);
// Pen tool
const penBtn = document.createElement('div');
penBtn.className = 'tool-button';
penBtn.textContent = 'pen';
penBtn.onclick = function() {
const isActive = penBtn.classList.contains('active');
if (isActive) {
penBtn.classList.remove('active');
setActiveTool('none');
} else {
tools.querySelectorAll('.tool-button').forEach(b => b.classList.remove('active'));
penBtn.classList.add('active');
setActiveTool('pen');
}
};
row.appendChild(penBtn);
// Eraser tool
const eraseBtn = document.createElement('div');
eraseBtn.className = 'tool-button';
eraseBtn.textContent = 'eraser';
eraseBtn.onclick = function() {
const isActive = eraseBtn.classList.contains('active');
if (isActive) {
eraseBtn.classList.remove('active');
setActiveTool('none');
} else {
tools.querySelectorAll('.tool-button').forEach(b => b.classList.remove('active'));
eraseBtn.classList.add('active');
setActiveTool('eraser');
}
};
row.appendChild(eraseBtn);
// Spotlight tool
const spotlightBtn = document.createElement('div');
spotlightBtn.className = 'tool-button';
spotlightBtn.textContent = 'spotlight';
spotlightBtn.onclick = function() {
const isActive = spotlightBtn.classList.contains('active');
if (isActive) {
spotlightBtn.classList.remove('active');
setActiveTool('none');
} else {
tools.querySelectorAll('.tool-button').forEach(b => b.classList.remove('active'));
spotlightBtn.classList.add('active');
setActiveTool('spotlight');
}
};
row.appendChild(spotlightBtn);
// Clear all
const clearBtn = document.createElement('div');
clearBtn.className = 'tool-button';
clearBtn.textContent = 'clear';
clearBtn.onclick = function() {
_shapes = [];
saveShapes();
renderOverlay();
};
row.appendChild(clearBtn);
// We'll add the copy button at the end of the widget
// Restore active state from storage
const saved = localStorage.getItem('uvnote-active-tool') || 'none';
if (saved === 'arrow') {
arrowBtn.classList.add('active');
setActiveTool('arrow');
} else if (saved === 'pen') {
penBtn.classList.add('active');
setActiveTool('pen');
} else if (saved === 'eraser') {
eraseBtn.classList.add('active');
setActiveTool('eraser');
} else if (saved === 'spotlight') {
spotlightBtn.classList.add('active');
setActiveTool('spotlight');
}
// Color selector
const colorTitle = document.createElement('div');
colorTitle.className = 'tools-section-title';
colorTitle.textContent = 'color';
tools.appendChild(colorTitle);
const colorRow = document.createElement('div');
colorRow.className = 'tools-row color-row';
tools.appendChild(colorRow);
const swatchColors = [
// Primary colors
'#e53935', '#fb8c00', '#fdd835', '#43a047', '#1e88e5', '#8e24aa',
// Additional useful colors
'#ff5722', '#795548', '#607d8b', '#9c27b0',
// Grayscale
'#000000', '#424242', '#9e9e9e', '#ffffff'
];
const swatches = [];
swatchColors.forEach(c => {
const s = document.createElement('div');
s.className = 'color-swatch';
s.style.backgroundColor = c;
s.title = c;
s.onclick = () => {
setStoredArrowColor(c);
refreshColorUI(c);
if (_cursorVisible) renderOverlay();
encodeToolStateToUrl();
};
colorRow.appendChild(s);
swatches.push(s);
});
const colorInput = document.createElement('input');
colorInput.type = 'color';
colorInput.className = 'color-input';
colorInput.oninput = () => {
setStoredArrowColor(colorInput.value);
refreshColorUI(colorInput.value);
if (_cursorVisible) renderOverlay();
encodeToolStateToUrl();
};
colorRow.appendChild(colorInput);
function refreshColorUI(selected) {
const selectedHex = selected.startsWith('#') ? selected.toLowerCase() : rgbToHex(selected);
swatches.forEach((s, i) => {
const swatchHex = swatchColors[i].toLowerCase();
if (swatchHex === selectedHex) {
s.classList.add('selected');
} else {
s.classList.remove('selected');
}
});
try {
colorInput.value = selectedHex;
} catch (_) {}
}
function rgbToHex(rgb) {
const m = rgb.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)\)/i);
if (!m) return '#000000';
const r = parseInt(m[1]).toString(16).padStart(2, '0');
const g = parseInt(m[2]).toString(16).padStart(2, '0');
const b = parseInt(m[3]).toString(16).padStart(2, '0');
return `#${r}${g}${b}`;
}
// Restore color selection
refreshColorUI(getArrowColor());
// Thickness slider
const thicknessTitle = document.createElement('div');
thicknessTitle.className = 'tools-section-title';
thicknessTitle.textContent = 'thickness';
tools.appendChild(thicknessTitle);
const thicknessRow = document.createElement('div');
thicknessRow.className = 'thickness-row';
tools.appendChild(thicknessRow);
const thicknessSlider = document.createElement('input');
thicknessSlider.type = 'range';
thicknessSlider.className = 'thickness-slider';
thicknessSlider.min = '1';
thicknessSlider.max = '10';
thicknessSlider.value = getLineThickness();
const thicknessValue = document.createElement('span');
thicknessValue.className = 'thickness-value';
thicknessValue.textContent = thicknessSlider.value + 'px';
thicknessSlider.oninput = function() {
const value = parseInt(thicknessSlider.value, 10);
setStoredLineThickness(value);
thicknessValue.textContent = value + 'px';
if (_cursorVisible) renderOverlay();
encodeToolStateToUrl();
};
thicknessRow.appendChild(thicknessSlider);
thicknessRow.appendChild(thicknessValue);
// Fadeout time slider
const fadeoutTitle = document.createElement('div');
fadeoutTitle.className = 'tools-section-title';
fadeoutTitle.textContent = 'fadeout time';
tools.appendChild(fadeoutTitle);
const fadeoutRow = document.createElement('div');
fadeoutRow.className = 'thickness-row';
tools.appendChild(fadeoutRow);
const fadeoutSlider = document.createElement('input');
fadeoutSlider.type = 'range';
fadeoutSlider.className = 'thickness-slider';
fadeoutSlider.min = '0';
fadeoutSlider.max = '30';
fadeoutSlider.value = getFadeoutTime();
const fadeoutValue = document.createElement('span');
fadeoutValue.className = 'thickness-value';
fadeoutValue.textContent = fadeoutSlider.value === '0' ? 'never' : fadeoutSlider.value + 's';
fadeoutSlider.oninput = function() {
const value = parseInt(fadeoutSlider.value, 10);
setStoredFadeoutTime(value);
fadeoutValue.textContent = value === 0 ? 'never' : value + 's';
encodeToolStateToUrl();
};
fadeoutRow.appendChild(fadeoutSlider);
fadeoutRow.appendChild(fadeoutValue);
// Draggable behavior
makeDraggable(tools, 'uvnote-tools-pos', title);
return tools;
}
function initTools() {
const widget = createToolsWidget();
document.body.appendChild(widget);
}
function teardownTools() {
const w = document.querySelector('.tools-widget');
if (w && w.parentNode) w.parentNode.removeChild(w);
}
// --- Canvas overlay for tools ---
let _overlay = null;
let _overlayCtx = null;
let _overlayContainer = null; // window
let _overlayMode = 'single';
let _overlayResizeHandler = null;
let _overlayScrollHandler = null;
let _drawing = null; // current in-progress arrow {x1,y1,x2,y2}
let _shapes = []; // committed shapes for current mode
let _fadeTimer = null; // timer for fade animation
let _urlLoadedTool = false; // track if tool was loaded from URL
let _isInitializing = true; // prevent URL updates during initialization
let _initialCellStates = {}; // track initial cell states from page load
function getOverlayStorageKey() { return 'uvnote-shapes'; }
function loadShapes() {
try {
const raw = localStorage.getItem(getOverlayStorageKey());
_shapes = raw ? JSON.parse(raw) : [];
} catch (_) { _shapes = []; }
}
function saveShapes() {
try {
localStorage.setItem(getOverlayStorageKey(), JSON.stringify(_shapes));
// Always update URL when shapes change
encodeToolStateToUrl();
} catch (_) {}
}
function updateShapesFade() {
const now = Date.now();
let needsUpdate = false;
for (let i = _shapes.length - 1; i >= 0; i--) {
const shape = _shapes[i];
if (!shape.createdAt) continue; // Skip old shapes without timestamps
// Use individual shape's fadeout time, or global if not set
const shapesFadeoutSeconds = shape.fadeoutTime !== undefined ? shape.fadeoutTime : getFadeoutTime();
// Skip fading if fadeout is disabled for this shape
if (shapesFadeoutSeconds === 0) continue;
const fadeStartTime = Math.max(0, (shapesFadeoutSeconds - 2) * 1000); // Start fading 2s before end
const fadeEndTime = shapesFadeoutSeconds * 1000; // Fully gone after specified time
const age = now - shape.createdAt;
if (age >= fadeEndTime) {
// Remove completely faded shapes
_shapes.splice(i, 1);
needsUpdate = true;
} else if (age >= fadeStartTime) {
// Update opacity for fading shapes
const fadeProgress = (age - fadeStartTime) / (fadeEndTime - fadeStartTime);
const newOpacity = 1 - fadeProgress;
if (Math.abs(shape.opacity - newOpacity) > 0.01) {
shape.opacity = newOpacity;
needsUpdate = true;
}
}
}
if (needsUpdate) {
saveShapes();
renderOverlay();
// Update URL to remove faded shapes
encodeToolStateToUrl();
}
}
function getContentContainer() { return window; }
function updateOverlayModeAndContainer() {
_overlayContainer = window;
_overlayMode = 'single';
}
function updateOverlayBounds() {
if (!_overlay) return;
if (_overlayContainer === window) {
_overlay.style.position = 'fixed';
_overlay.style.left = '0px';
_overlay.style.top = '0px';
_overlay.width = window.innerWidth;
_overlay.height = window.innerHeight;
} else {
const rect = _overlayContainer.getBoundingClientRect();
_overlay.style.position = 'fixed';
_overlay.style.left = rect.left + 'px';
_overlay.style.top = rect.top + 'px';
_overlay.width = Math.max(0, Math.floor(rect.width));
_overlay.height = Math.max(0, Math.floor(rect.height));
}
renderOverlay();
}
function containerScrollLeft() {
return (_overlayContainer === window) ? (window.scrollX || 0) : (_overlayContainer.scrollLeft || 0);
}
function containerScrollTop() {
return (_overlayContainer === window) ? (window.scrollY || 0) : (_overlayContainer.scrollTop || 0);
}
function toCanvasCoords(clientX, clientY) {
const rect = _overlay.getBoundingClientRect();
return { x: clientX - rect.left, y: clientY - rect.top };
}
function onPointerDown(e) {
const tool = document.body.dataset.tool;
if (tool === 'arrow') {
startDrawArrow(e);
} else if (tool === 'pen') {
startDrawPen(e);
} else if (tool === 'eraser') {
eraseAt(e);
} else if (tool === 'spotlight') {
startDrawSpotlight(e);
}
}
function onPointerMove(e) {
// Update cursor position
const pt = toCanvasCoords(e.touches ? e.touches[0].clientX : e.clientX, e.touches ? e.touches[0].clientY : e.clientY);
_cursorX = pt.x;
_cursorY = pt.y;
if (!_drawing) {
// Just update cursor position and re-render
if (_cursorVisible) {
renderOverlay();
}
return;
}
if (_drawing.type === 'pen') {
moveDrawPen(e);
} else if (_drawing.type === 'spotlight') {
moveDrawSpotlight(e);
} else {
moveDrawArrow(e);
}
}
function onPointerEnter(e) {
_cursorVisible = document.body.dataset.tool !== 'none';
if (_cursorVisible) {
renderOverlay();
}
}
function onPointerLeave(e) {
_cursorVisible = false;
renderOverlay();
}
function onPointerUp(e) {
if (!_drawing) return;
if (_drawing.type === 'pen') {
endDrawPen();
} else if (_drawing.type === 'spotlight') {
endDrawSpotlight();
} else {
endDrawArrow();
}
}
function startDrawArrow(e) {
if (document.body.dataset.tool !== 'arrow') return;
const pt = toCanvasCoords(e.touches ? e.touches[0].clientX : e.clientX, e.touches ? e.touches[0].clientY : e.clientY);
_drawing = {
x1: pt.x + containerScrollLeft(),
y1: pt.y + containerScrollTop(),
x2: pt.x + containerScrollLeft(),
y2: pt.y + containerScrollTop(),
color: getArrowColor(),
width: getLineThickness()
};
renderOverlay();
e.preventDefault();
}
function moveDrawArrow(e) {
if (!_drawing) return;
const pt = toCanvasCoords(e.touches ? e.touches[0].clientX : e.clientX, e.touches ? e.touches[0].clientY : e.clientY);
_drawing.x2 = pt.x + containerScrollLeft();
_drawing.y2 = pt.y + containerScrollTop();
renderOverlay();
e.preventDefault();
}
function endDrawArrow() {
if (!_drawing) return;
_shapes.push({
type: 'arrow',
..._drawing,
createdAt: Date.now(),
fadeoutTime: getFadeoutTime(),
opacity: 1.0
});
_drawing = null;
saveShapes();
renderOverlay();
}
function startDrawPen(e) {
if (document.body.dataset.tool !== 'pen') return;
const pt = toCanvasCoords(e.touches ? e.touches[0].clientX : e.clientX, e.touches ? e.touches[0].clientY : e.clientY);
_drawing = {
type: 'pen',
points: [{
x: pt.x + containerScrollLeft(),
y: pt.y + containerScrollTop()
}],
color: getArrowColor(),
width: getLineThickness()
};
renderOverlay();
e.preventDefault();
}
function moveDrawPen(e) {
if (!_drawing || _drawing.type !== 'pen') return;
const pt = toCanvasCoords(e.touches ? e.touches[0].clientX : e.clientX, e.touches ? e.touches[0].clientY : e.clientY);
_drawing.points.push({
x: pt.x + containerScrollLeft(),
y: pt.y + containerScrollTop()
});
renderOverlay();
e.preventDefault();
}
function endDrawPen() {
if (!_drawing || _drawing.type !== 'pen') return;
if (_drawing.points.length > 1) {
_shapes.push({
..._drawing,
createdAt: Date.now(),
fadeoutTime: getFadeoutTime(),
opacity: 1.0
});
}
_drawing = null;
saveShapes();
renderOverlay();
}
function startDrawSpotlight(e) {
if (document.body.dataset.tool !== 'spotlight') return;
const pt = toCanvasCoords(e.touches ? e.touches[0].clientX : e.clientX, e.touches ? e.touches[0].clientY : e.clientY);
_drawing = {
type: 'spotlight',
x: pt.x + containerScrollLeft(),
y: pt.y + containerScrollTop(),
radius: getLineThickness() * 20, // Use thickness to control spotlight size (bigger default)
color: getArrowColor()
};
renderOverlay();
e.preventDefault();
}
function moveDrawSpotlight(e) {
if (!_drawing || _drawing.type !== 'spotlight') return;
const pt = toCanvasCoords(e.touches ? e.touches[0].clientX : e.clientX, e.touches ? e.touches[0].clientY : e.clientY);
const dx = pt.x + containerScrollLeft() - _drawing.x;
const dy = pt.y + containerScrollTop() - _drawing.y;
_drawing.radius = Math.max(20, Math.sqrt(dx * dx + dy * dy)); // Minimum radius of 20
renderOverlay();
e.preventDefault();
}
function endDrawSpotlight() {
if (!_drawing || _drawing.type !== 'spotlight') return;
_shapes.push({
..._drawing,
createdAt: Date.now(),
fadeoutTime: getFadeoutTime(),
opacity: 1.0
});
_drawing = null;
saveShapes();
renderOverlay();
}
function distPointToSegment(px, py, x1, y1, x2, y2) {
const dx = x2 - x1, dy = y2 - y1;
if (dx === 0 && dy === 0) return Math.hypot(px - x1, py - y1);
const t = Math.max(0, Math.min(1, ((px - x1) * dx + (py - y1) * dy) / (dx*dx + dy*dy)));
const cx = x1 + t * dx, cy = y1 + t * dy;
return Math.hypot(px - cx, py - cy);
}
function eraseAt(e) {
const pt = toCanvasCoords(e.touches ? e.touches[0].clientX : e.clientX, e.touches ? e.touches[0].clientY : e.clientY);
const x = pt.x + containerScrollLeft();
const y = pt.y + containerScrollTop();
const threshold = 10; // pixels
for (let i = _shapes.length - 1; i >= 0; i--) {
const s = _shapes[i];
if (s.type === 'arrow') {
const d = distPointToSegment(x, y, s.x1, s.y1, s.x2, s.y2);
if (d <= threshold) {
_shapes.splice(i, 1);
saveShapes();
renderOverlay();
break;
}
} else if (s.type === 'pen' && s.points) {
// Check if click is near any line segment in the pen stroke
let minDist = Infinity;
for (let j = 1; j < s.points.length; j++) {
const d = distPointToSegment(x, y, s.points[j-1].x, s.points[j-1].y, s.points[j].x, s.points[j].y);
minDist = Math.min(minDist, d);
}
if (minDist <= threshold) {
_shapes.splice(i, 1);
saveShapes();
renderOverlay();
break;
}
}
}
e.preventDefault();
}
function drawArrow(ctx, x1, y1, x2, y2, color, width, opacity = 1.0) {
// Set opacity
const oldAlpha = ctx.globalAlpha;
ctx.globalAlpha = opacity;
ctx.strokeStyle = color;
ctx.fillStyle = color;
ctx.lineWidth = width;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
// Check if points are too close (initial state)
const dx = x2 - x1;
const dy = y2 - y1;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 5) {
// Draw just a small arrowhead pointing down-right when first clicked
const defaultAngle = Math.PI / 4; // 45 degrees (down-right)
const headLength = Math.min(15 + width * 1.5, 25);
const headAngle = Math.PI / 6;
// Calculate arrowhead points
const hx1 = x1 + headLength * Math.cos(defaultAngle - headAngle);
const hy1 = y1 + headLength * Math.sin(defaultAngle - headAngle);
const hx2 = x1 + headLength * Math.cos(defaultAngle + headAngle);
const hy2 = y1 + headLength * Math.sin(defaultAngle + headAngle);
// Draw arrowhead only
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(hx1, hy1);
ctx.lineTo(hx2, hy2);
ctx.closePath();
ctx.fill();
} else {
// Normal arrow drawing - head at x1,y1, tail at x2,y2
const angle = Math.atan2(y1 - y2, x1 - x2);
const headLength = Math.min(15 + width * 1.5, 25);
const headAngle = Math.PI / 6;
// Calculate where the line should end (before the arrowhead)
const lineEndX = x1 - headLength * 0.8 * Math.cos(angle);
const lineEndY = y1 - headLength * 0.8 * Math.sin(angle);
// Draw the line from tail to near the head
ctx.beginPath();
ctx.moveTo(x2, y2);
ctx.lineTo(lineEndX, lineEndY);
ctx.stroke();
// Calculate arrowhead points
const hx1 = x1 - headLength * Math.cos(angle - headAngle);
const hy1 = y1 - headLength * Math.sin(angle - headAngle);
const hx2 = x1 - headLength * Math.cos(angle + headAngle);
const hy2 = y1 - headLength * Math.sin(angle + headAngle);
// Draw arrowhead
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(hx1, hy1);
ctx.lineTo(hx2, hy2);
ctx.closePath();
ctx.fill();
}
// Restore opacity
ctx.globalAlpha = oldAlpha;
}
function drawPen(ctx, points, color, width, offX, offY, opacity = 1.0) {
if (!points || points.length < 2) return;
// Set opacity
const oldAlpha = ctx.globalAlpha;
ctx.globalAlpha = opacity;
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.beginPath();
ctx.moveTo(points[0].x - offX, points[0].y - offY);
for (let i = 1; i < points.length; i++) {
ctx.lineTo(points[i].x - offX, points[i].y - offY);
}
ctx.stroke();
// Restore opacity
ctx.globalAlpha = oldAlpha;
}
function drawAllSpotlights(ctx, spotlights, offX, offY) {
if (!spotlights || spotlights.length === 0) return;
ctx.save();
// Calculate the overall opacity based on all spotlights
const maxOpacity = Math.max(...spotlights.map(s => s.opacity || 1.0));
// Fill entire canvas with dark overlay
ctx.fillStyle = `rgba(0, 0, 0, ${0.7 * maxOpacity})`;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// Cut out completely transparent holes for all spotlights
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = 'rgba(0, 0, 0, 1)'; // Solid black to ensure complete removal
for (const spotlight of spotlights) {
ctx.beginPath();
ctx.arc(spotlight.x - offX, spotlight.y - offY, spotlight.radius, 0, 2 * Math.PI);
ctx.fill();
}
ctx.restore();
}
function renderOverlay() {
if (!_overlay || !_overlayCtx) return;
_overlayCtx.clearRect(0, 0, _overlay.width, _overlay.height);
const offX = containerScrollLeft();
const offY = containerScrollTop();
// Draw non-spotlight shapes first
for (const s of _shapes) {
const opacity = s.opacity !== undefined ? s.opacity : 1.0;
if (s.type === 'arrow') {
drawArrow(_overlayCtx, s.x1 - offX, s.y1 - offY, s.x2 - offX, s.y2 - offY, s.color || '#f00', s.width || 2, opacity);
} else if (s.type === 'pen') {
drawPen(_overlayCtx, s.points, s.color || '#f00', s.width || 2, offX, offY, opacity);
}
}
// Draw current drawing (non-spotlight)
if (_drawing) {
if (_drawing.type === 'pen') {
drawPen(_overlayCtx, _drawing.points, _drawing.color, _drawing.width, offX, offY);
} else if (_drawing.type !== 'spotlight') {
drawArrow(_overlayCtx, _drawing.x1 - offX, _drawing.y1 - offY, _drawing.x2 - offX, _drawing.y2 - offY, _drawing.color, _drawing.width);
}
}
// Collect all spotlights (existing + current drawing + cursor preview)
const spotlights = [];
// Add existing spotlight shapes
for (const s of _shapes) {
if (s.type === 'spotlight') {
spotlights.push({
x: s.x,
y: s.y,
radius: s.radius,
opacity: s.opacity !== undefined ? s.opacity : 1.0
});
}
}
// Add current spotlight being drawn
if (_drawing && _drawing.type === 'spotlight') {
spotlights.push({
x: _drawing.x,
y: _drawing.y,
radius: _drawing.radius,
opacity: 1.0
});
}
// Add cursor preview spotlight if tool is active
if (_cursorVisible && !_drawing) {
const tool = document.body.dataset.tool;
if (tool === 'spotlight') {
const thickness = getLineThickness();
const radius = thickness * 20;
const cursorWorldX = _cursorX + containerScrollLeft();
const cursorWorldY = _cursorY + containerScrollTop();
spotlights.push({
x: cursorWorldX,
y: cursorWorldY,
radius: radius,
opacity: 0.8
});
}
}
// Draw all spotlights as a single overlay with multiple holes
drawAllSpotlights(_overlayCtx, spotlights, offX, offY);
// Draw cursor indicators for non-spotlight tools
if (_cursorVisible && !_drawing) {
const tool = document.body.dataset.tool;
const color = getArrowColor();
const thickness = getLineThickness();
if (tool !== 'spotlight') {
_overlayCtx.save();
_overlayCtx.fillStyle = color;
_overlayCtx.globalAlpha = 0.7;
if (tool === 'eraser') {
// Draw eraser indicator
_overlayCtx.strokeStyle = color;
_overlayCtx.lineWidth = 2;
_overlayCtx.beginPath();
_overlayCtx.arc(_cursorX, _cursorY, 10, 0, 2 * Math.PI);
_overlayCtx.stroke();
} else {
// Draw dot for pen/arrow
_overlayCtx.beginPath();
_overlayCtx.arc(_cursorX, _cursorY, thickness / 2, 0, 2 * Math.PI);
_overlayCtx.fill();
}
_overlayCtx.restore();
}
}
}
function setOverlayActive(active) {
if (!_overlay) initOverlay();
_overlay.style.pointerEvents = active ? 'auto' : 'none';
_overlay.style.cursor = active ? 'none' : 'auto';
// Re-render to ensure visibility aligns with content
renderOverlay();
}
function initOverlay() {
if (_overlay) return;
updateOverlayModeAndContainer();
_overlay = document.createElement('canvas');
_overlay.className = 'draw-overlay';
_overlayCtx = _overlay.getContext('2d');
document.body.appendChild(_overlay);
updateOverlayBounds();
loadShapes();
renderOverlay();
// Events
_overlay.addEventListener('mousedown', onPointerDown);
_overlay.addEventListener('mousemove', onPointerMove);
_overlay.addEventListener('mouseenter', onPointerEnter);
_overlay.addEventListener('mouseleave', onPointerLeave);
document.addEventListener('mouseup', onPointerUp);
_overlay.addEventListener('touchstart', onPointerDown, { passive: false });
_overlay.addEventListener('touchmove', onPointerMove, { passive: false });
document.addEventListener('touchend', onPointerUp);
_overlayResizeHandler = () => updateOverlayBounds();
window.addEventListener('resize', _overlayResizeHandler);
_overlayScrollHandler = () => renderOverlay();
window.addEventListener('scroll', _overlayScrollHandler);
// Start fade animation timer
_fadeTimer = setInterval(updateShapesFade, 100); // Update every 100ms for smooth fade
}
function rebindOverlayContainer() {
if (!_overlay) return;
// Remove old scroll handler
if (_overlayScrollHandler) { window.removeEventListener('scroll', _overlayScrollHandler); }
updateOverlayModeAndContainer();
updateOverlayBounds();
loadShapes();
renderOverlay();
_overlayScrollHandler = () => renderOverlay();
window.addEventListener('scroll', _overlayScrollHandler);
}
function teardownOverlay() {
if (!_overlay) return;
_overlay.removeEventListener('mousedown', onPointerDown);
_overlay.removeEventListener('mousemove', onPointerMove);
_overlay.removeEventListener('mouseenter', onPointerEnter);
_overlay.removeEventListener('mouseleave', onPointerLeave);
document.removeEventListener('mouseup', onPointerUp);
_overlay.removeEventListener('touchstart', onPointerDown);
_overlay.removeEventListener('touchmove', onPointerMove);
document.removeEventListener('touchend', onPointerUp);
if (_overlayResizeHandler) window.removeEventListener('resize', _overlayResizeHandler);
if (_overlayScrollHandler) {
if (_overlayContainer === window) {
window.removeEventListener('scroll', _overlayScrollHandler);
} else if (_overlayContainer) {
_overlayContainer.removeEventListener('scroll', _overlayScrollHandler);
}
}
if (_fadeTimer) {
clearInterval(_fadeTimer);
_fadeTimer = null;
}
if (_overlay.parentNode) _overlay.parentNode.removeChild(_overlay);
_overlay = null; _overlayCtx = null; _overlayContainer = null; _overlayResizeHandler = null; _overlayScrollHandler = null; _drawing = null;
}
function teardownFileExplorer() {
const fe = document.querySelector('.file-explorer');
if (fe && fe.parentNode) fe.parentNode.removeChild(fe);
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function runCell(cellId){
const btn=document.querySelector('.run-btn[onclick*="'+cellId+'"]');
const output=document.getElementById('output-'+cellId);
if(btn){btn.textContent='⏳ running...';btn.disabled=true;}
if(output){output.classList.add('output-stale');}
fetch('/run/'+cellId,{method:'POST'}).then(r=>r.json()).then(data=>{
if(output){
output.classList.remove('output-stale');
let html='';
if(data.stdout) html+='<div class="cell-stdout">'+escapeHtml(data.stdout)+'</div>';
console.log('UV Logs:', data);
if(data.stderr) {
// Split UV logs from regular stderr
const lines = data.stderr.split('\\n');
let uvLogs = [];
let regularLogs = [];
let inUvSection = true;
for (const line of lines) {
if (inUvSection) {
uvLogs.push(line);
if (line.startsWith('Installed ')) {
inUvSection = false;
}
} else {
regularLogs.push(line);
}
}
// If we never found "Installed", treat it all as regular stderr
if (inUvSection) {
html+='<div class="cell-stderr">'+escapeHtml(data.stderr)+'</div>';
} else {
const uvLogsStr = uvLogs.join('\\n');
const regularLogsStr = regularLogs.join('\\n').trim();
if (uvLogsStr) {
html+='<div class="uv-install-logs">';
html+='<div class="uv-logs-header" onclick="toggleUvLogs(this)">▶ UV Install Logs</div>';
html+='<div class="uv-logs-content" style="display: none;">'+escapeHtml(uvLogsStr)+'</div>';
html+='</div>';
}
if (regularLogsStr) {
html+='<div class="cell-stderr">'+escapeHtml(regularLogsStr)+'</div>';
}
}
}
output.innerHTML=html;
}
if(btn){btn.textContent='▶ run';btn.disabled=false;}
}).catch(e=>{
console.error('Run failed:',e);
if(output){output.classList.remove('output-stale');}
if(btn){btn.textContent='▶ run';btn.disabled=false;}
});
}
function copyCell(cellId){
console.log('copyCell called with cellId:', cellId);
// Try multiple selectors to find the code element
let codeElement = document.querySelector('#code-'+cellId+' code');
if (!codeElement) {
codeElement = document.querySelector('#code-'+cellId+' pre code');
}
if (!codeElement) {
codeElement = document.querySelector('#code-'+cellId+' .highlight code');
}
if (!codeElement) {
// Try finding any code element within the cell
const codeDiv = document.getElementById('code-'+cellId);
if (codeDiv) {
codeElement = codeDiv.querySelector('code');
}
}
const btn = document.querySelector('.copy-btn[onclick*="'+cellId+'"]');
console.log('Found codeElement:', codeElement);
console.log('Found btn:', btn);
console.log('Code div structure:', document.getElementById('code-'+cellId));
if (!codeElement) {
console.error('Code element not found for cell:', cellId);
// Log the actual structure for debugging
const codeDiv = document.getElementById('code-'+cellId);
if (codeDiv) {
console.log('Code div HTML:', codeDiv.innerHTML);
}
return;
}
if (!btn) {
console.error('Copy button not found for cell:', cellId);
return;
}
const codeText = codeElement.textContent;
console.log('Code text to copy:', codeText ? codeText.substring(0, 50) + '...' : 'empty');
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(codeText).then(function() {
console.log('Clipboard copy successful');
btn.textContent = '✓ Copied!';
btn.classList.add('copied');
setTimeout(function() {
btn.textContent = 'Copy';
btn.classList.remove('copied');
}, 2000);
}).catch(function(err) {
console.warn('Clipboard copy failed:', err);
fallbackCopy();
});
} else {
console.log('Using fallback copy method');
fallbackCopy();
}
function fallbackCopy() {
const textarea = document.createElement('textarea');
textarea.value = codeText;
textarea.style.position = 'absolute';
textarea.style.left = '-9999px';
document.body.appendChild(textarea);
textarea.select();
try {
const success = document.execCommand('copy');
console.log('Fallback copy success:', success);
btn.textContent = '✓ Copied!';
btn.classList.add('copied');
setTimeout(function() {
btn.textContent = 'Copy';
btn.classList.remove('copied');
}, 2000);
} catch (err) {
console.error('Fallback copy failed:', err);
btn.textContent = 'Copy failed';
setTimeout(function() {
btn.textContent = 'Copy';
}, 2000);
}
document.body.removeChild(textarea);
}
}
// Live reload functionality (robust SSE handling)
(function(){
if (!('EventSource' in window)) {
console.warn('SSE not supported in this browser');
return;
}
let source = new EventSource('/events');
let isOpen = false;
source.onopen = function(){ isOpen = true; console.log('SSE connected'); };
source.onmessage = function(e){
const msg=(e.data||'').trim(); if(!msg) return;
console.log('SSE message:', msg);
if (msg==='reload' || msg==='incremental') { location.reload(); }
// Ignore 'loading' to avoid premature reload loops
};
source.onerror = function(e){
// Let EventSource auto-reconnect instead of forcing a reload
if (isOpen) console.warn('SSE error after open, retrying...', e);
};
window.addEventListener('beforeunload', function(){ try{source.close();}catch(_){} });
})();
document.addEventListener('DOMContentLoaded', function() {
// Capture initial cell states before any modifications
captureInitialCellStates();
updateThemeIcon();
updateUiMenu();
updateUiDebug();
const widgetsEnabled = (document.documentElement.getAttribute('data-widgets') || 'on') === 'on';
if (widgetsEnabled) {
initMinimap();
initFileExplorer();
initTools();
initOverlay();
initStatusWidget();
initializeWidgetVisibility();
layoutWidgetsStackedBottomRight();
window.addEventListener('resize', layoutWidgetsStackedBottomRight);
}
// Apply deep-link selection if present
applyLocationFromUrl();
updateStateIndicator();
// Apply cell states from URL immediately
const url = new URL(window.location.href);
const encodedCellStates = url.searchParams.get('cells');
if (encodedCellStates) {
console.log('Applying cell states from URL...');
const cellStates = decodeCellStatesFromUrl(encodedCellStates);
// Use requestAnimationFrame to ensure DOM is ready
requestAnimationFrame(() => {
applyCellStatesFromUrl(cellStates);
// Clear initialization flag after cell states are applied
if (typeof _isInitializing !== 'undefined') {
_isInitializing = false;
}
});
} else {
// Clear initialization flag even if no cell states
if (typeof _isInitializing !== 'undefined') {
requestAnimationFrame(() => {
_isInitializing = false;
});
}
}
// Bind drag selection on line numbers
document.addEventListener('mousedown', onLineNumberMouseDown);
document.addEventListener('mousemove', onDocMouseMove);
document.addEventListener('mouseup', onDocMouseUp);
// Add ESC key handler to exit tools
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' || e.keyCode === 27) {
const currentTool = document.body.dataset.tool;
if (currentTool && currentTool !== 'none') {
// Deactivate the current tool
window.setActiveTool('none');
}
// Also clear any active line selection
clearSelection(true);
}
});
});
function updateStateIndicator() {
try {
const el = document.getElementById('status-widget');
if (!el) return;
const tool = document.body.dataset.tool || 'none';
if (tool && tool !== 'none') {
el.textContent = `tool: ${tool} — Esc`;
return;
}
if (_selection) {
const t = _selection.a === _selection.b ? `L${_selection.a}` : `L${_selection.a}-${_selection.b}`;
el.textContent = `selected: ${t} — Esc`;
return;
}
el.textContent = 'ready — Esc';
} catch (_) {}
}
</script>
</head>
<body>
<div class="controls">
<div class="controls-buttons">
<div class="theme-toggle" onclick="toggleTheme()">light</div>
<div class="reset-toggle" onclick="resetLayout()">reset</div>
<div class="menu-button" onclick="toggleMenu()">
menu ▼
<div class="menu-dropdown">
<div class="menu-item" onclick="setUiTheme('default')">
<span class="menu-checkbox" id="checkbox-ui-default"></span> Theme: default
</div>
<div class="menu-item" onclick="setUiTheme('none')">
<span class="menu-checkbox" id="checkbox-ui-none"></span> Theme: none
</div>
<div class="menu-item" onclick="setUiTheme('monocolor')">
<span class="menu-checkbox" id="checkbox-ui-monocolor"></span> Theme: monocolor
</div>
<div class="menu-item" onclick="toggleWidget('tools')">
<span class="menu-checkbox" id="checkbox-tools"></span> Tools
</div>
<div class="menu-item" onclick="toggleWidget('file-explorer')">
<span class="menu-checkbox" id="checkbox-file-explorer"></span> File Explorer
</div>
<div class="menu-item" onclick="toggleWidget('minimap')">
<span class="menu-checkbox" id="checkbox-minimap"></span> Table of Contents
</div>
<div class="menu-item" onclick="toggleWidget('status')">
<span class="menu-checkbox" id="checkbox-status"></span> Status Indicator
</div>
</div>
</div>
</div>
</div>
<div class="system-info">
<div class="system-info-header">Generated on:</div>
<div class="system-info-content">
Linux x86_64 | Linux-6.12.40-64.114.amzn2023.x86_64-x86_64-with-glibc2.36
</div>
</div>
<div class="main-content">
<h1>No Kernels</h1>
<p>First, we run the model without any custom kernels to get a reference point.</p>
<h2>Forward</h2>
<h2>Forward and Backward</h2>
<p>Next, we'll attempt to run a forward and backward pass without any custom kernels. This will likely run out of memory since the default implementation is not optimized for memory usage.</p>
<div class="cell cell-failed" id="cell-forward_and_backward_no_kernel">
<div class="cell-header">
<span class="collapse-indicators">
<span onclick="toggleCode('forward_and_backward_no_kernel')" style="cursor: pointer;">▼ code</span>
<span onclick="toggleOutput('forward_and_backward_no_kernel')" style="cursor: pointer;">▼ output</span>
<span id="uv-indicator-forward_and_backward_no_kernel" onclick="toggleUvLogsFromHeader('forward_and_backward_no_kernel')" style="cursor: pointer;">▶ uv-logs</span>
</span> |
Cell: forward_and_backward_no_kernel | 99.38s | FAILED
| <button class="run-btn" onclick="runCell('forward_and_backward_no_kernel')">▶ run</button>
<button class="copy-btn" onclick="copyCell('forward_and_backward_no_kernel')">Copy</button>
<a href="cells/forward_and_backward_no_kernel.py" target="_blank" class="raw-btn">Raw</a>
</div>
<div id="code-forward_and_backward_no_kernel" class="cell-code" data-lines="196">
<div class="highlight-with-lines">
<div class="line-numbers" id="lines-forward_and_backward_no_kernel">
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="1" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 1, true);">1</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="2" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 2, true);">2</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="3" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 3, true);">3</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="4" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 4, true);">4</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="5" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 5, true);">5</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="6" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 6, true);">6</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="7" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 7, true);">7</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="8" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 8, true);">8</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="9" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 9, true);">9</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="10" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 10, true);">10</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="11" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 11, true);">11</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="12" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 12, true);">12</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="13" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 13, true);">13</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="14" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 14, true);">14</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="15" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 15, true);">15</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="16" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 16, true);">16</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="17" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 17, true);">17</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="18" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 18, true);">18</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="19" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 19, true);">19</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="20" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 20, true);">20</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="21" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 21, true);">21</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="22" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 22, true);">22</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="23" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 23, true);">23</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="24" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 24, true);">24</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="25" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 25, true);">25</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="26" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 26, true);">26</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="27" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 27, true);">27</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="28" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 28, true);">28</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="29" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 29, true);">29</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="30" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 30, true);">30</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="31" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 31, true);">31</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="32" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 32, true);">32</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="33" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 33, true);">33</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="34" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 34, true);">34</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="35" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 35, true);">35</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="36" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 36, true);">36</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="37" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 37, true);">37</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="38" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 38, true);">38</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="39" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 39, true);">39</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="40" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 40, true);">40</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="41" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 41, true);">41</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="42" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 42, true);">42</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="43" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 43, true);">43</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="44" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 44, true);">44</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="45" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 45, true);">45</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="46" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 46, true);">46</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="47" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 47, true);">47</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="48" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 48, true);">48</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="49" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 49, true);">49</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="50" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 50, true);">50</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="51" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 51, true);">51</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="52" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 52, true);">52</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="53" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 53, true);">53</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="54" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 54, true);">54</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="55" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 55, true);">55</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="56" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 56, true);">56</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="57" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 57, true);">57</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="58" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 58, true);">58</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="59" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 59, true);">59</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="60" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 60, true);">60</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="61" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 61, true);">61</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="62" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 62, true);">62</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="63" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 63, true);">63</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="64" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 64, true);">64</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="65" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 65, true);">65</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="66" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 66, true);">66</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="67" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 67, true);">67</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="68" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 68, true);">68</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="69" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 69, true);">69</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="70" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 70, true);">70</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="71" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 71, true);">71</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="72" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 72, true);">72</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="73" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 73, true);">73</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="74" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 74, true);">74</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="75" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 75, true);">75</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="76" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 76, true);">76</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="77" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 77, true);">77</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="78" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 78, true);">78</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="79" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 79, true);">79</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="80" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 80, true);">80</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="81" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 81, true);">81</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="82" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 82, true);">82</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="83" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 83, true);">83</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="84" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 84, true);">84</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="85" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 85, true);">85</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="86" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 86, true);">86</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="87" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 87, true);">87</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="88" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 88, true);">88</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="89" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 89, true);">89</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="90" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 90, true);">90</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="91" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 91, true);">91</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="92" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 92, true);">92</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="93" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 93, true);">93</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="94" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 94, true);">94</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="95" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 95, true);">95</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="96" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 96, true);">96</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="97" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 97, true);">97</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="98" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 98, true);">98</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="99" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 99, true);">99</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="100" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 100, true);">100</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="101" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 101, true);">101</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="102" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 102, true);">102</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="103" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 103, true);">103</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="104" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 104, true);">104</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="105" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 105, true);">105</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="106" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 106, true);">106</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="107" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 107, true);">107</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="108" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 108, true);">108</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="109" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 109, true);">109</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="110" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 110, true);">110</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="111" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 111, true);">111</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="112" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 112, true);">112</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="113" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 113, true);">113</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="114" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 114, true);">114</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="115" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 115, true);">115</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="116" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 116, true);">116</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="117" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 117, true);">117</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="118" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 118, true);">118</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="119" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 119, true);">119</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="120" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 120, true);">120</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="121" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 121, true);">121</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="122" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 122, true);">122</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="123" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 123, true);">123</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="124" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 124, true);">124</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="125" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 125, true);">125</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="126" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 126, true);">126</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="127" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 127, true);">127</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="128" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 128, true);">128</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="129" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 129, true);">129</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="130" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 130, true);">130</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="131" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 131, true);">131</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="132" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 132, true);">132</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="133" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 133, true);">133</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="134" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 134, true);">134</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="135" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 135, true);">135</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="136" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 136, true);">136</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="137" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 137, true);">137</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="138" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 138, true);">138</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="139" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 139, true);">139</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="140" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 140, true);">140</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="141" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 141, true);">141</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="142" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 142, true);">142</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="143" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 143, true);">143</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="144" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 144, true);">144</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="145" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 145, true);">145</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="146" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 146, true);">146</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="147" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 147, true);">147</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="148" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 148, true);">148</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="149" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 149, true);">149</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="150" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 150, true);">150</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="151" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 151, true);">151</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="152" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 152, true);">152</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="153" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 153, true);">153</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="154" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 154, true);">154</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="155" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 155, true);">155</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="156" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 156, true);">156</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="157" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 157, true);">157</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="158" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 158, true);">158</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="159" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 159, true);">159</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="160" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 160, true);">160</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="161" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 161, true);">161</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="162" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 162, true);">162</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="163" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 163, true);">163</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="164" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 164, true);">164</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="165" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 165, true);">165</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="166" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 166, true);">166</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="167" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 167, true);">167</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="168" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 168, true);">168</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="169" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 169, true);">169</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="170" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 170, true);">170</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="171" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 171, true);">171</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="172" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 172, true);">172</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="173" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 173, true);">173</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="174" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 174, true);">174</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="175" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 175, true);">175</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="176" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 176, true);">176</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="177" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 177, true);">177</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="178" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 178, true);">178</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="179" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 179, true);">179</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="180" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 180, true);">180</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="181" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 181, true);">181</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="182" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 182, true);">182</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="183" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 183, true);">183</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="184" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 184, true);">184</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="185" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 185, true);">185</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="186" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 186, true);">186</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="187" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 187, true);">187</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="188" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 188, true);">188</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="189" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 189, true);">189</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="190" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 190, true);">190</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="191" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 191, true);">191</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="192" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 192, true);">192</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="193" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 193, true);">193</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="194" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 194, true);">194</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="195" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 195, true);">195</a>
<a class="line-number" data-cell="forward_and_backward_no_kernel" data-line="196" href="#cell-forward_and_backward_no_kernel" onclick="event.preventDefault(); selectCellLine('forward_and_backward_no_kernel', 196, true);">196</a>
</div>
<div class="code-wrap">
<div class="highlight"><pre><span></span><span class="c1"># /// script</span>
<span class="c1"># requires-python = &quot;&gt;=3.12&quot;</span>
<span class="c1"># dependencies = [</span>
<span class="c1"># &quot;accelerate&gt;=1.10.1&quot;,</span>
<span class="c1"># &quot;torch&gt;=2.7.0&quot;,</span>
<span class="c1"># &quot;kernels==0.10.0&quot;,</span>
<span class="c1"># &quot;transformers@https://github.com/huggingface/transformers.git&quot;,</span>
<span class="c1"># &quot;ipdb&gt;=0.13.13&quot;,</span>
<span class="c1"># &quot;matplotlib&gt;=3.7.2&quot;,</span>
<span class="c1"># &quot;numpy&gt;=1.24.3&quot;,</span>
<span class="c1"># ]</span>
<span class="c1"># ///</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">torch</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">transformers</span><span class="w"> </span><span class="kn">import</span> <span class="n">GptOssForCausalLM</span><span class="p">,</span> <span class="n">PreTrainedTokenizerFast</span><span class="p">,</span> <span class="n">Mxfp4Config</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">time</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">torch.nn</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">nn</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">kernels</span><span class="w"> </span><span class="kn">import</span> <span class="n">register_kernel_mapping</span><span class="p">,</span> <span class="n">Mode</span><span class="p">,</span> <span class="n">LayerRepository</span><span class="p">,</span> <span class="n">replace_kernel_forward_from_hub</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">torch.profiler</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">gc</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">transformers.models.gpt_oss.modeling_gpt_oss</span><span class="w"> </span><span class="kn">import</span> <span class="n">GptOssRMSNorm</span>
<span class="c1"># remove liger kernel for testing </span>
<span class="n">replace_kernel_forward_from_hub</span><span class="p">(</span><span class="n">GptOssRMSNorm</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="c1"># set to debug logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">reset_peak_memory_stats</span><span class="p">():</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Clear CUDA cache and reset memory allocation counters.&quot;&quot;&quot;</span>
<span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">empty_cache</span><span class="p">()</span>
<span class="k">if</span> <span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">is_available</span><span class="p">():</span>
<span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">reset_peak_memory_stats</span><span class="p">()</span>
<span class="n">gc</span><span class="o">.</span><span class="n">collect</span><span class="p">()</span>
<span class="k">def</span><span class="w"> </span><span class="nf">get_memory_stats</span><span class="p">():</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get current and peak CUDA memory usage.&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">is_available</span><span class="p">():</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">&quot;allocated_gb&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">&quot;peak_gb&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">&quot;reserved_gb&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">}</span>
<span class="k">return</span> <span class="p">{</span>
<span class="s2">&quot;allocated_gb&quot;</span><span class="p">:</span> <span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">memory_allocated</span><span class="p">()</span> <span class="o">/</span> <span class="mf">1e9</span><span class="p">,</span>
<span class="s2">&quot;peak_gb&quot;</span><span class="p">:</span> <span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">max_memory_allocated</span><span class="p">()</span> <span class="o">/</span> <span class="mf">1e9</span><span class="p">,</span>
<span class="s2">&quot;reserved_gb&quot;</span><span class="p">:</span> <span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">memory_reserved</span><span class="p">()</span> <span class="o">/</span> <span class="mf">1e9</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">def</span><span class="w"> </span><span class="nf">override_kernel_layer_name</span><span class="p">(</span><span class="n">cls_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Helper to dynamically override the kernel_layer_name in a model class.&quot;&quot;&quot;</span>
<span class="k">for</span> <span class="n">mod</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="k">if</span> <span class="n">mod</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">continue</span>
<span class="n">obj</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="n">cls_name</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="nb">type</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
<span class="nb">setattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">&quot;kernel_layer_name&quot;</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Overrode </span><span class="si">{</span><span class="n">cls_name</span><span class="si">}</span><span class="s2">.kernel_layer_name to </span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="c1"># Init the model the normal way</span>
<span class="n">model_id</span> <span class="o">=</span> <span class="s2">&quot;openai/gpt-oss-20b&quot;</span>
<span class="n">tokenizer</span> <span class="o">=</span> <span class="n">PreTrainedTokenizerFast</span><span class="o">.</span><span class="n">from_pretrained</span><span class="p">(</span><span class="n">model_id</span><span class="p">)</span>
<span class="n">quantization_config</span> <span class="o">=</span> <span class="n">Mxfp4Config</span><span class="p">(</span><span class="n">dequantize</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">GptOssForCausalLM</span><span class="o">.</span><span class="n">from_pretrained</span><span class="p">(</span>
<span class="n">model_id</span><span class="p">,</span>
<span class="n">dtype</span><span class="o">=</span><span class="s2">&quot;bfloat16&quot;</span><span class="p">,</span>
<span class="n">device_map</span><span class="o">=</span><span class="s2">&quot;auto&quot;</span><span class="p">,</span>
<span class="n">use_kernels</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">quantization_config</span><span class="o">=</span><span class="n">quantization_config</span><span class="p">,</span>
<span class="p">)</span><span class="o">.</span><span class="n">eval</span><span class="p">()</span>
<span class="n">messages</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">{</span><span class="s2">&quot;role&quot;</span><span class="p">:</span> <span class="s2">&quot;system&quot;</span><span class="p">,</span> <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;What is Tensor Parallelism?&quot;</span><span class="p">},</span>
<span class="p">]</span>
<span class="n">inputs</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">apply_chat_template</span><span class="p">(</span>
<span class="n">messages</span><span class="p">,</span>
<span class="n">add_generation_prompt</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">return_tensors</span><span class="o">=</span><span class="s2">&quot;pt&quot;</span><span class="p">,</span>
<span class="n">return_dict</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">reasoning_effort</span><span class="o">=</span><span class="s2">&quot;low&quot;</span><span class="p">,</span>
<span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="s2">&quot;cuda&quot;</span><span class="p">)</span>
<span class="n">max_tokens</span> <span class="o">=</span> <span class="mi">128</span> <span class="c1"># Reduced to help with memory usage</span>
<span class="c1"># Clear memory before backward pass</span>
<span class="n">reset_peak_memory_stats</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Pre-generation memory: </span><span class="si">{</span><span class="n">get_memory_stats</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># forward and backward pass</span>
<span class="k">with</span> <span class="n">torch</span><span class="o">.</span><span class="n">autograd</span><span class="o">.</span><span class="n">set_grad_enabled</span><span class="p">(</span><span class="kc">True</span><span class="p">):</span>
<span class="n">start_time</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span><span class="p">()</span>
<span class="n">generated</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span>
<span class="o">**</span><span class="n">inputs</span><span class="p">,</span>
<span class="n">max_new_tokens</span><span class="o">=</span><span class="n">max_tokens</span><span class="p">,</span>
<span class="n">do_sample</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">temperature</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">end_time</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">tokenizer</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">generated</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">skip_special_tokens</span><span class="o">=</span><span class="kc">False</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Generation took </span><span class="si">{</span><span class="n">end_time</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">start_time</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2"> seconds&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Post-generation memory: </span><span class="si">{</span><span class="n">get_memory_stats</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Use gradient checkpointing to reduce memory usage</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="s1">&#39;gradient_checkpointing_enable&#39;</span><span class="p">):</span>
<span class="n">model</span><span class="o">.</span><span class="n">gradient_checkpointing_enable</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Enabled gradient checkpointing&quot;</span><span class="p">)</span>
<span class="c1"># Reduce sequence length if needed for memory</span>
<span class="n">max_seq_len</span> <span class="o">=</span> <span class="mi">512</span> <span class="c1"># Limit sequence length for backward pass</span>
<span class="k">if</span> <span class="n">generated</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">max_seq_len</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Truncating sequence from </span><span class="si">{</span><span class="n">generated</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="si">}</span><span class="s2"> to </span><span class="si">{</span><span class="n">max_seq_len</span><span class="si">}</span><span class="s2"> tokens&quot;</span><span class="p">)</span>
<span class="n">full_sequence</span> <span class="o">=</span> <span class="n">generated</span><span class="p">[:,</span> <span class="o">-</span><span class="n">max_seq_len</span><span class="p">:]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">full_sequence</span> <span class="o">=</span> <span class="n">generated</span>
<span class="c1"># Get model outputs for the full sequence</span>
<span class="n">model</span><span class="o">.</span><span class="n">train</span><span class="p">()</span> <span class="c1"># Enable dropout and other training behaviors</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">outputs</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span>
<span class="n">input_ids</span><span class="o">=</span><span class="n">full_sequence</span><span class="p">,</span>
<span class="n">labels</span><span class="o">=</span><span class="n">full_sequence</span><span class="p">,</span> <span class="c1"># This will compute loss internally</span>
<span class="n">return_dict</span><span class="o">=</span><span class="kc">True</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Post-forward memory: </span><span class="si">{</span><span class="n">get_memory_stats</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># If model doesn&#39;t compute loss, compute it manually</span>
<span class="k">if</span> <span class="n">outputs</span><span class="o">.</span><span class="n">loss</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">shift_logits</span> <span class="o">=</span> <span class="n">outputs</span><span class="o">.</span><span class="n">logits</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="p">:]</span><span class="o">.</span><span class="n">contiguous</span><span class="p">()</span>
<span class="n">shift_labels</span> <span class="o">=</span> <span class="n">full_sequence</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="mi">1</span><span class="p">:]</span><span class="o">.</span><span class="n">contiguous</span><span class="p">()</span>
<span class="c1"># Use CrossEntropyLoss with ignore_index for padding tokens</span>
<span class="n">loss_fct</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">CrossEntropyLoss</span><span class="p">(</span><span class="n">ignore_index</span><span class="o">=</span><span class="n">tokenizer</span><span class="o">.</span><span class="n">pad_token_id</span> <span class="k">if</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">pad_token_id</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="o">-</span><span class="mi">100</span><span class="p">)</span>
<span class="n">loss</span> <span class="o">=</span> <span class="n">loss_fct</span><span class="p">(</span>
<span class="n">shift_logits</span><span class="o">.</span><span class="n">view</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">shift_logits</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)),</span>
<span class="n">shift_labels</span><span class="o">.</span><span class="n">view</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">loss</span> <span class="o">=</span> <span class="n">outputs</span><span class="o">.</span><span class="n">loss</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Loss: </span><span class="si">{</span><span class="n">loss</span><span class="o">.</span><span class="n">item</span><span class="p">()</span><span class="si">:</span><span class="s2">.4f</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Clear intermediate tensors to save memory</span>
<span class="k">del</span> <span class="n">outputs</span>
<span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">empty_cache</span><span class="p">()</span>
<span class="c1"># Perform backward pass with memory management</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Running backward pass...&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Pre-backward memory: </span><span class="si">{</span><span class="n">get_memory_stats</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">loss</span><span class="o">.</span><span class="n">backward</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Post-backward memory: </span><span class="si">{</span><span class="n">get_memory_stats</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">OutOfMemoryError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;OOM during forward/backward pass: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Try reducing max_tokens or max_seq_len&quot;</span><span class="p">)</span>
<span class="k">raise</span>
<span class="c1"># Calculate gradient statistics and print sample gradients</span>
<span class="n">total_norm</span> <span class="o">=</span> <span class="mf">0.0</span>
<span class="n">param_count</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">grad_samples</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">named_parameters</span><span class="p">():</span>
<span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">grad</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">param_count</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">grad_norm</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">grad</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">norm</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">item</span><span class="p">()</span>
<span class="n">total_norm</span> <span class="o">+=</span> <span class="n">grad_norm</span> <span class="o">**</span> <span class="mi">2</span>
<span class="c1"># Collect gradient statistics for key layers</span>
<span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">key</span> <span class="ow">in</span> <span class="n">name</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;embed&#39;</span><span class="p">,</span> <span class="s1">&#39;lm_head&#39;</span><span class="p">,</span> <span class="s1">&#39;mlp.up&#39;</span><span class="p">,</span> <span class="s1">&#39;mlp.down&#39;</span><span class="p">,</span> <span class="s1">&#39;self_attn.q_proj&#39;</span><span class="p">,</span> <span class="s1">&#39;norm&#39;</span><span class="p">]):</span>
<span class="n">grad_samples</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">&#39;norm&#39;</span><span class="p">:</span> <span class="n">grad_norm</span><span class="p">,</span>
<span class="s1">&#39;mean&#39;</span><span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">grad</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span><span class="o">.</span><span class="n">item</span><span class="p">(),</span>
<span class="s1">&#39;std&#39;</span><span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">grad</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">std</span><span class="p">()</span><span class="o">.</span><span class="n">item</span><span class="p">(),</span>
<span class="s1">&#39;max&#39;</span><span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">grad</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">max</span><span class="p">()</span><span class="o">.</span><span class="n">item</span><span class="p">(),</span>
<span class="s1">&#39;min&#39;</span><span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">grad</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">min</span><span class="p">()</span><span class="o">.</span><span class="n">item</span><span class="p">(),</span>
<span class="p">}</span>
<span class="n">total_norm</span> <span class="o">=</span> <span class="n">total_norm</span> <span class="o">**</span> <span class="mf">0.5</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Gradient norm: </span><span class="si">{</span><span class="n">total_norm</span><span class="si">:</span><span class="s2">.4f</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Parameters with gradients: </span><span class="si">{</span><span class="n">param_count</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Print sample gradients from important layers</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Sample gradient statistics:&quot;</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">stats</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">grad_samples</span><span class="o">.</span><span class="n">items</span><span class="p">())[:</span><span class="mi">10</span><span class="p">]):</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot; </span><span class="si">{</span><span class="n">name</span><span class="p">[:</span><span class="mi">60</span><span class="p">]</span><span class="si">:</span><span class="s2">&lt;60</span><span class="si">}</span><span class="s2"> | norm: </span><span class="si">{</span><span class="n">stats</span><span class="p">[</span><span class="s1">&#39;norm&#39;</span><span class="p">]</span><span class="si">:</span><span class="s2">.4e</span><span class="si">}</span><span class="s2"> | mean: </span><span class="si">{</span><span class="n">stats</span><span class="p">[</span><span class="s1">&#39;mean&#39;</span><span class="p">]</span><span class="si">:</span><span class="s2">.4e</span><span class="si">}</span><span class="s2"> | std: </span><span class="si">{</span><span class="n">stats</span><span class="p">[</span><span class="s1">&#39;std&#39;</span><span class="p">]</span><span class="si">:</span><span class="s2">.4e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Optional: zero gradients for next iteration</span>
<span class="n">model</span><span class="o">.</span><span class="n">zero_grad</span><span class="p">()</span>
<span class="n">model</span><span class="o">.</span><span class="n">eval</span><span class="p">()</span> <span class="c1"># Switch back to eval mode</span>
</pre></div>
<div class="code-line-highlight" id="line-highlight-forward_and_backward_no_kernel"></div>
</div>
</div>
</div>
<div id="output-forward_and_backward_no_kernel" class="cell-output">
<div class="cell-stdout">Pre-generation memory: {&#x27;allocated_gb&#x27;: 9.390148608, &#x27;peak_gb&#x27;: 9.390148608, &#x27;reserved_gb&#x27;: 17.177772032}
&lt;|start|&gt;system&lt;|message|&gt;You are ChatGPT, a large language model trained by OpenAI.
Knowledge cutoff: 2024-06
Current date: 2025-09-24
Reasoning: low
# Valid channels: analysis, commentary, final. Channel must be included for every message.&lt;|end|&gt;&lt;|start|&gt;developer&lt;|message|&gt;# Instructions
What is Tensor Parallelism?
&lt;|end|&gt;&lt;|start|&gt;assistant&lt;|channel|&gt;analysis&lt;|message|&gt;Need to explain tensor parallelism.&lt;|end|&gt;&lt;|start|&gt;assistant&lt;|channel|&gt;final&lt;|message|&gt;**Tensor Parallelism** is a technique used to distribute the computation of a single tensor (or a set of tensors) across multiple devices (GPUs, TPUs, or other accelerators) in order to speed up large‑scale deep‑learning training and inference. It is one of several parallelism strategies—alongside data parallelism, pipeline parallelism, and model parallelism—designed to scale models that exceed the memory or compute capacity of a single device.
---
## 1. Why Tensor Parallelism?
- **Memory constraints**: Modern
Generation took 13.15 seconds
Post-generation memory: {&#x27;allocated_gb&#x27;: 9.398670336, &#x27;peak_gb&#x27;: 9.514059776, &#x27;reserved_gb&#x27;: 17.188257792}
Enabled gradient checkpointing
Post-forward memory: {&#x27;allocated_gb&#x27;: 9.487933952, &#x27;peak_gb&#x27;: 9.514059776, &#x27;reserved_gb&#x27;: 17.188257792}
Loss: 1.9761
Running backward pass...
Pre-backward memory: {&#x27;allocated_gb&#x27;: 9.405890048, &#x27;peak_gb&#x27;: 9.514059776, &#x27;reserved_gb&#x27;: 17.177772032}
OOM during forward/backward pass: CUDA out of memory. Tried to allocate 508.00 MiB. GPU 2 has a total capacity of 22.30 GiB of which 118.69 MiB is free. Process 25557 has 22.18 GiB memory in use. Of the allocated memory 21.52 GiB is allocated by PyTorch, and 357.89 MiB is reserved by PyTorch but unallocated. If reserved but unallocated memory is large try setting PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True to avoid fragmentation. See documentation for Memory Management (https://pytorch.org/docs/stable/notes/cuda.html#environment-variables)
Try reducing max_tokens or max_seq_len
</div>
<div class="uv-install-logs" id="uv-logs-forward_and_backward_no_kernel">
<div class="uv-logs-header" onclick="toggleUvLogs(this)">▶ UV Install Logs</div>
<div class="uv-logs-content" style="display: none;">
Downloading cpython-3.13.7-linux-x86_64-gnu (download) (32.0MiB)
Downloading cpython-3.13.7-linux-x86_64-gnu (download)
Updating https://github.com/huggingface/transformers.git (HEAD)
Updated https://github.com/huggingface/transformers.git (7258ea44bc0c0a425a468f66f8559d1de8c4126d)
Downloading nvidia-cuda-cupti-cu12 (9.8MiB)
Downloading networkx (1.9MiB)
Downloading jedi (1.5MiB)
Building transformers @ git+https://github.com/huggingface/transformers.git@7258ea44bc0c0a425a468f66f8559d1de8c4126d
Downloading kiwisolver (1.4MiB)
Downloading nvidia-cuda-nvrtc-cu12 (84.0MiB)
Downloading nvidia-nccl-cu12 (307.4MiB)
Downloading nvidia-cublas-cu12 (566.8MiB)
Downloading nvidia-cudnn-cu12 (674.0MiB)
Downloading nvidia-cufft-cu12 (184.2MiB)
Downloading nvidia-curand-cu12 (60.7MiB)
Downloading nvidia-cusparse-cu12 (274.9MiB)
Downloading hf-xet (3.0MiB)
Downloading triton (148.4MiB)
Downloading nvidia-cufile-cu12 (1.1MiB)
Downloading nvidia-nvjitlink-cu12 (37.4MiB)
Downloading tokenizers (3.1MiB)
Downloading matplotlib (8.3MiB)
Downloading sympy (6.0MiB)
Downloading pillow (6.3MiB)
Downloading nvidia-cusparselt-cu12 (273.9MiB)
Downloading pygments (1.2MiB)
Downloading nvidia-cusolver-cu12 (255.1MiB)
Downloading numpy (15.9MiB)
Downloading torch (846.8MiB)
Downloading fonttools (4.7MiB)
Downloading nvidia-cufile-cu12
Downloading kiwisolver
Downloading pygments
Downloading tokenizers
Downloading hf-xet
Downloading networkx
Downloading fonttools
Downloading pillow
Downloading matplotlib
Downloading nvidia-cuda-cupti-cu12
Downloading numpy
Downloading sympy
Built transformers @ git+https://github.com/huggingface/transformers.git@7258ea44bc0c0a425a468f66f8559d1de8c4126d
Downloading nvidia-nvjitlink-cu12
Downloading jedi
Downloading nvidia-curand-cu12
Downloading nvidia-cuda-nvrtc-cu12
Downloading triton
Downloading nvidia-cufft-cu12
Downloading nvidia-cusolver-cu12
Downloading nvidia-cusparse-cu12
Downloading nvidia-cusparselt-cu12
Downloading nvidia-nccl-cu12
Downloading nvidia-cublas-cu12
Downloading nvidia-cudnn-cu12
Downloading torch
Installed 69 packages in 579ms
</div>
</div>
<div class="cell-stderr">Fetching 3 files: 0%| | 0/3 [00:00&lt;?, ?it/s]
Fetching 3 files: 33%|███▎ | 1/3 [00:07&lt;00:15, 7.84s/it]
Fetching 3 files: 67%|██████▋ | 2/3 [00:08&lt;00:03, 3.40s/it]
Fetching 3 files: 100%|██████████| 3/3 [00:08&lt;00:00, 2.71s/it]
Loading checkpoint shards: 0%| | 0/3 [00:00&lt;?, ?it/s]
Loading checkpoint shards: 33%|███▎ | 1/3 [00:02&lt;00:04, 2.34s/it]
Loading checkpoint shards: 67%|██████▋ | 2/3 [00:04&lt;00:02, 2.25s/it]
Loading checkpoint shards: 100%|██████████| 3/3 [00:05&lt;00:00, 1.80s/it]
Loading checkpoint shards: 100%|██████████| 3/3 [00:05&lt;00:00, 1.93s/it]
`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`.
Traceback (most recent call last):
File &quot;/repo/moe_benchmarks/megablocks/.uvnote/cells/forward_and_backward_no_kernel.py&quot;, line 154, in &lt;module&gt;
loss.backward()
~~~~~~~~~~~~~^^
File &quot;/tmp/uvnote-run-yr7p57do/home/.cache/uv/environments-v2/forward-and-backward-no-kernel-349948fac2e1b63b/lib/python3.13/site-packages/torch/_tensor.py&quot;, line 647, in backward
torch.autograd.backward(
~~~~~~~~~~~~~~~~~~~~~~~^
self, gradient, retain_graph, create_graph, inputs=inputs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File &quot;/tmp/uvnote-run-yr7p57do/home/.cache/uv/environments-v2/forward-and-backward-no-kernel-349948fac2e1b63b/lib/python3.13/site-packages/torch/autograd/__init__.py&quot;, line 354, in backward
_engine_run_backward(
~~~~~~~~~~~~~~~~~~~~^
tensors,
^^^^^^^^
...&lt;5 lines&gt;...
accumulate_grad=True,
^^^^^^^^^^^^^^^^^^^^^
)
^
File &quot;/tmp/uvnote-run-yr7p57do/home/.cache/uv/environments-v2/forward-and-backward-no-kernel-349948fac2e1b63b/lib/python3.13/site-packages/torch/autograd/graph.py&quot;, line 829, in _engine_run_backward
return Variable._execution_engine.run_backward( # Calls into the C++ engine to run the backward pass
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
t_outputs, *args, **kwargs
^^^^^^^^^^^^^^^^^^^^^^^^^^
) # Calls into the C++ engine to run the backward pass
^
File &quot;/tmp/uvnote-run-yr7p57do/home/.cache/uv/environments-v2/forward-and-backward-no-kernel-349948fac2e1b63b/lib/python3.13/site-packages/torch/autograd/function.py&quot;, line 311, in apply
return user_fn(self, *args)
File &quot;/tmp/uvnote-run-yr7p57do/home/.cache/uv/environments-v2/forward-and-backward-no-kernel-349948fac2e1b63b/lib/python3.13/site-packages/torch/utils/checkpoint.py&quot;, line 319, in backward
torch.autograd.backward(outputs_with_grad, args_with_grad)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File &quot;/tmp/uvnote-run-yr7p57do/home/.cache/uv/environments-v2/forward-and-backward-no-kernel-349948fac2e1b63b/lib/python3.13/site-packages/torch/autograd/__init__.py&quot;, line 354, in backward
_engine_run_backward(
~~~~~~~~~~~~~~~~~~~~^
tensors,
^^^^^^^^
...&lt;5 lines&gt;...
accumulate_grad=True,
^^^^^^^^^^^^^^^^^^^^^
)
^
File &quot;/tmp/uvnote-run-yr7p57do/home/.cache/uv/environments-v2/forward-and-backward-no-kernel-349948fac2e1b63b/lib/python3.13/site-packages/torch/autograd/graph.py&quot;, line 829, in _engine_run_backward
return Variable._execution_engine.run_backward( # Calls into the C++ engine to run the backward pass
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
t_outputs, *args, **kwargs
^^^^^^^^^^^^^^^^^^^^^^^^^^
) # Calls into the C++ engine to run the backward pass
^
torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 508.00 MiB. GPU 2 has a total capacity of 22.30 GiB of which 118.69 MiB is free. Process 25557 has 22.18 GiB memory in use. Of the allocated memory 21.52 GiB is allocated by PyTorch, and 357.89 MiB is reserved by PyTorch but unallocated. If reserved but unallocated memory is large try setting PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True to avoid fragmentation. See documentation for Memory Management (https://pytorch.org/docs/stable/notes/cuda.html#environment-variables)</div>
</div>
</div>
<h1>Kernels</h1>
<p>Next we can run with Megablocks kernels enabled.</p>
<h3>Forward</h3>
<p>First, we run a forward pass with Megablocks kernels.</p>
<h2>Forward and Backward</h2>
<p>Next, we run a forward and backward pass with Megablocks kernels enabled. This should be more memory efficient and allow us to complete the backward pass without running out of memory.</p>
</div>
</body>
</html>