docReady(() => { if (!EVALEX_TRUSTED) { initPinBox(); } // if we are in console mode, show the console. if (CONSOLE_MODE && EVALEX) { createInteractiveConsole(); } const frames = document.querySelectorAll("div.traceback div.frame"); if (EVALEX) { addConsoleIconToFrames(frames); } addEventListenersToElements(document.querySelectorAll("div.detail"), "click", () => document.querySelector("div.traceback").scrollIntoView(false) ); addToggleFrameTraceback(frames); addToggleTraceTypesOnClick(document.querySelectorAll("h2.traceback")); addInfoPrompt(document.querySelectorAll("span.nojavascript")); wrapPlainTraceback(); }); function addToggleFrameTraceback(frames) { frames.forEach((frame) => { frame.addEventListener("click", () => { frame.getElementsByTagName("pre")[0].parentElement.classList.toggle("expanded"); }); }) } function wrapPlainTraceback() { const plainTraceback = document.querySelector("div.plain textarea"); const wrapper = document.createElement("pre"); const textNode = document.createTextNode(plainTraceback.textContent); wrapper.appendChild(textNode); plainTraceback.replaceWith(wrapper); } function makeDebugURL(args) { const params = new URLSearchParams(args) params.set("s", SECRET) return `?__debugger__=yes&${params}` } function initPinBox() { document.querySelector(".pin-prompt form").addEventListener( "submit", function (event) { event.preventDefault(); const btn = this.btn; btn.disabled = true; fetch( makeDebugURL({cmd: "pinauth", pin: this.pin.value}) ) .then((res) => res.json()) .then(({auth, exhausted}) => { if (auth) { EVALEX_TRUSTED = true; fadeOut(document.getElementsByClassName("pin-prompt")[0]); } else { alert( `Error: ${ exhausted ? "too many attempts. Restart server to retry." : "incorrect pin" }` ); } }) .catch((err) => { alert("Error: Could not verify PIN. Network error?"); console.error(err); }) .finally(() => (btn.disabled = false)); }, false ); } function promptForPin() { if (!EVALEX_TRUSTED) { fetch(makeDebugURL({cmd: "printpin"})); const pinPrompt = document.getElementsByClassName("pin-prompt")[0]; fadeIn(pinPrompt); document.querySelector('.pin-prompt input[name="pin"]').focus(); } } /** * Helper function for shell initialization */ function openShell(consoleNode, target, frameID) { promptForPin(); if (consoleNode) { slideToggle(consoleNode); return consoleNode; } let historyPos = 0; const history = [""]; const consoleElement = createConsole(); const output = createConsoleOutput(); const form = createConsoleInputForm(); const command = createConsoleInput(); target.parentNode.appendChild(consoleElement); consoleElement.append(output); consoleElement.append(form); form.append(command); command.focus(); slideToggle(consoleElement); form.addEventListener("submit", (e) => { handleConsoleSubmit(e, command, frameID).then((consoleOutput) => { output.append(consoleOutput); command.focus(); consoleElement.scrollTo(0, consoleElement.scrollHeight); const old = history.pop(); history.push(command.value); if (typeof old !== "undefined") { history.push(old); } historyPos = history.length - 1; command.value = ""; }); }); command.addEventListener("keydown", (e) => { if (e.key === "l" && e.ctrlKey) { output.innerText = "--- screen cleared ---"; } else if (e.key === "ArrowUp" || e.key === "ArrowDown") { // Handle up arrow and down arrow. if (e.key === "ArrowUp" && historyPos > 0) { e.preventDefault(); historyPos--; } else if (e.key === "ArrowDown" && historyPos < history.length - 1) { historyPos++; } command.value = history[historyPos]; } return false; }); return consoleElement; } function addEventListenersToElements(elements, event, listener) { elements.forEach((el) => el.addEventListener(event, listener)); } /** * Add extra info */ function addInfoPrompt(elements) { for (let i = 0; i < elements.length; i++) { elements[i].innerHTML = "
To switch between the interactive traceback and the plaintext " + 'one, you can click on the "Traceback" headline. From the text ' + "traceback you can also create a paste of it. " + (!EVALEX ? "" : "For code execution mouse-over the frame you want to debug and " + "click on the console icon on the right side." + "
You can execute arbitrary Python code in the stack frames and " + "there are some extra helpers available for introspection:" + "
dump()
shows all variables in the frame" +
"dump(obj)
dumps all that's known about the object