1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js"; 2import { S as ScoreMusicXmlViewer } from "./ScoreMusicXmlViewer-D8VtSBA7.js"; 3import { aX as ArrowLeft, cv as Award, b7 as Check, aW as X, bi as Sparkles, bV as Play, ba as Info } from "./vendor-D0P4XgNj.js"; 4import "./vendor-i18n-BC7ZMXWQ.js"; 5function StagingArena({ currentUser, onAuthRequested, id, onNavigate }) { 6 const [algo, setAlgo] = reactExports.useState(null); 7 const [isLoading, setIsLoading] = reactExports.useState(true); 8 const [benchmarks, setBenchmarks] = reactExports.useState([]); 9 const [selectedBenchmark, setSelectedBenchmark] = reactExports.useState("basic_scale"); 10 const [customMidiId, setCustomMidiId] = reactExports.useState(""); 11 const [testResultXml, setTestResultXml] = reactExports.useState(""); 12 const [testDiagnostics, setTestDiagnostics] = reactExports.useState(null); 13 const [isTesting, setIsTesting] = reactExports.useState(false); 14 reactExports.useEffect(() => { 15 fetch(`/api/algorithms/${id}`).then((r) => r.json()).then((data) => { 16 setAlgo(data); 17 setIsLoading(false); 18 }).catch((err) => { 19 console.error("Failed to load algorithm:", err); 20 setIsLoading(false); 21 }); 22 fetch("/api/algorithms/benchmarks").then((r) => r.json()).then((data) => { 23 if (Array.isArray(data)) setBenchmarks(data); 24 }).catch((err) => console.error("Failed to load benchmarks:", err)); 25 }, [id]); 26 const handleVote = async (value) => { 27 if (!currentUser) return onAuthRequested(); 28 try { 29 const res = await fetch(`/api/algorithms/${id}/vote`, { 30 method: "POST", 31 headers: { "Content-Type": "application/json" }, 32 body: JSON.stringify({ value }) 33 }); 34 const data = await res.json(); 35 if (data.error) { 36 alert(`Vote error: ${data.error}`); 37 return; 38 } 39 setAlgo(data); 40 } catch (e) { 41 console.error("Vote failed:", e); 42 } 43 }; 44 const runBenchmark = async () => { 45 if (!algo || !algo.content) return; 46 setIsTesting(true); 47 setTestDiagnostics(null); 48 const startTime = Date.now(); 49 try { 50 let payload = { scriptContent: algo.content }; 51 if (selectedBenchmark === "custom") { 52 if (!customMidiId.trim()) { 53 alert("Please enter a valid MIDI track ID to benchmark."); 54 setIsTesting(false); 55 return; 56 } 57 const trackNum = parseInt(customMidiId.trim(), 10); 58 const groupFolder = Math.floor(trackNum / 1e3); 59 const midiRes = await fetch(`/storage/tracks/midi/${groupFolder}/${trackNum}.mid`); 60 if (!midiRes.ok) throw new Error(`Benchmark MIDI track #${trackNum} not found in public storage`); 61 const arrayBuffer = await midiRes.arrayBuffer(); 62 const base64String = btoa( 63 new Uint8Array(arrayBuffer).reduce((data2, byte) => data2 + String.fromCharCode(byte), "") 64 ); 65 payload.midiBase64 = base64String; 66 } else { 67 payload.benchmarkId = selectedBenchmark; 68 } 69 const res = await fetch("/api/algorithms/sandbox-test", { 70 method: "POST", 71 headers: { "Content-Type": "application/json" }, 72 body: JSON.stringify(payload) 73 }); 74 const data = await res.json(); 75 const elapsed = Date.now() - startTime; 76 if (data.error) { 77 setTestDiagnostics({ elapsedMs: elapsed, error: data.error }); 78 setTestResultXml(""); 79 } else { 80 setTestResultXml(data.xml || ""); 81 setTestDiagnostics({ elapsedMs: elapsed }); 82 } 83 } catch (e) { 84 setTestDiagnostics({ elapsedMs: Date.now() - startTime, error: e.message }); 85 setTestResultXml(""); 86 } finally { 87 setIsTesting(false); 88 } 89 }; 90 if (isLoading) { 91 return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-12 text-center text-zinc-500 font-semibold", children: "Loading Testing Arena..." }); 92 } 93 if (!algo) { 94 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-12 text-center", children: [
95 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 mb-4", children: "Algorithm not found." }), 96 /* @__PURE__ */ jsxRuntimeExports.jsx( 97 "button", 98 { 99 onClick: () => onNavigate("algorithm-studio"), 100 className: "px-4 py-2 bg-indigo-600 text-white rounded-xl font-bold", 101 children: "Back to Studio" 102 } 103 ) 104 ] }); 105 } 106 const netVotes = (algo.phase2Upvotes || 0) - (algo.phase2Downvotes || 0); 107 const votesNeeded = Math.max(0, 3 - netVotes); 108 const isMain = algo.status === "MAIN" || algo.isMainBranch; 109 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-7xl mx-auto p-6 h-screen flex flex-col animate-in fade-in", children: [ 110 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-4 shrink-0 flex-wrap gap-4", children: [ 111 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [ 112 /* @__PURE__ */ jsxRuntimeExports.jsx( 113 "button", 114 { 115 type: "button", 116 onClick: () => onNavigate("algorithm-studio"), 117 className: "p-2 bg-zinc-100 hover:bg-zinc-200 dark:bg-zinc-800 dark:hover:bg-zinc-700 rounded-full transition-colors", 118 title: "Back to Studio", 119 children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { size: 20 }) 120 } 121 ),
122 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 123 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5", children: [ 124 /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-2xl font-black text-zinc-900 dark:text-zinc-100", children: algo.name }), 125 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `px-2.5 py-0.5 rounded-full text-[11px] font-bold uppercase tracking-wider ${isMain ? "bg-green-500/10 text-green-600 dark:text-green-400 border border-green-500/30" : "bg-blue-500/10 text-blue-600 dark:text-blue-400 border border-blue-500/30"}`, children: isMain ? `Main Standard (v${algo.version})` : "Phase 2 Candidate" }) 126 ] }), 127 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 text-xs mt-1", children: algo.description || "Community MIDI-to-Score quantization logic candidate." }) 128 ] }) 129 ] }), 130 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-3", children: isMain ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-4 py-2 bg-green-500/10 text-green-600 dark:text-green-400 border border-green-500/30 rounded-xl font-bold text-sm", children: [
131 /* @__PURE__ */ jsxRuntimeExports.jsx(Award, { size: 18 }), 132 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Approved Community Standard" }) 133 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 border border-zinc-200 dark:border-zinc-800 rounded-xl p-2 bg-white dark:bg-zinc-900 shadow-sm", children: [ 134 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right pl-2", children: [ 135 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[10px] text-zinc-400 font-semibold uppercase tracking-wider", children: "Promotion Threshold" }), 136 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-bold text-zinc-700 dark:text-zinc-200 font-mono", children: [ 137 netVotes, 138 " / 3 Net Votes ", 139 votesNeeded > 0 ? `(${votesNeeded} more needed)` : "(Qualifying)" 140 ] }) 141 ] }), 142 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 border-l border-zinc-200 dark:border-zinc-800 pl-3", children: [
143 /* @__PURE__ */ jsxRuntimeExports.jsxs( 144 "button", 145 { 146 type: "button", 147 onClick: () => handleVote(1), 148 title: "Upvote logic", 149 className: "px-3 py-1.5 bg-green-100 hover:bg-green-200 dark:bg-green-900/30 dark:hover:bg-green-900/50 text-green-600 dark:text-green-400 rounded-lg flex items-center gap-1.5 font-bold text-xs transition-colors", 150 children: [ 151 /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 14 }), 152 " ", 153 algo.phase2Upvotes || 0 154 ] 155 } 156 ), 157 /* @__PURE__ */ jsxRuntimeExports.jsxs( 158 "button", 159 { 160 type: "button", 161 onClick: () => handleVote(-1), 162 title: "Downvote logic", 163 className: "px-3 py-1.5 bg-red-100 hover:bg-red-200 dark:bg-red-900/30 dark:hover:bg-red-900/50 text-red-600 dark:text-red-400 rounded-lg flex items-center gap-1.5 font-bold text-xs transition-colors", 164 children: [
165 /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 14 }), 166 " ", 167 algo.phase2Downvotes || 0 168 ] 169 } 170 ) 171 ] }) 172 ] }) }) 173 ] }), 174 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 rounded-xl border border-zinc-200 dark:border-zinc-800 p-3 mb-4 shrink-0 shadow-sm flex items-center justify-between gap-4 flex-wrap", children: [ 175 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-[320px]", children: [ 176 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-bold text-zinc-700 dark:text-zinc-300 flex items-center gap-1.5 shrink-0", children: [ 177 /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 14, className: "text-indigo-500" }), 178 "Select Benchmark Piece:" 179 ] }), 180 /* @__PURE__ */ jsxRuntimeExports.jsxs( 181 "select", 182 { 183 value: selectedBenchmark, 184 onChange: (e) => setSelectedBenchmark(e.target.value), 185 className: "flex-1 max-w-md px-3 py-1.5 bg-zinc-100 dark:bg-zinc-950 text-zinc-800 dark:text-zinc-200 border border-zinc-300 dark:border-zinc-800 rounded-lg outline-none text-xs font-medium cursor-pointer", 186 children: [
187 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "basic_scale", className: "bg-white dark:bg-zinc-900 text-zinc-800 dark:text-zinc-200", children: "C Major Scale Baseline (Fundamental Note & Measure Boundaries)" }), 188 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "twinkle_twinkle", className: "bg-white dark:bg-zinc-900 text-zinc-800 dark:text-zinc-200", children: "Twinkle Twinkle Little Star (Melodic Contour Benchmark)" }), 189 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "polyphonic_invention", className: "bg-white dark:bg-zinc-900 text-zinc-800 dark:text-zinc-200", children: "Two-Voice Counterpoint (Polyphonic Staves Benchmark)" }), 190 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "syncopated_rhythm", className: "bg-white dark:bg-zinc-900 text-zinc-800 dark:text-zinc-200", children: "Syncopated Rhythm Test (Off-beat 8ths & Tied Durations)" }), 191 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "custom", className: "bg-white dark:bg-zinc-900 text-zinc-800 dark:text-zinc-200", children: "Custom MIDI Track ID..." }) 192 ] 193 } 194 ), 195 selectedBenchmark === "custom" && /* @__PURE__ */ jsxRuntimeExports.jsx( 196 "input", 197 { 198 type: "text", 199 placeholder: "MIDI ID (e.g. 878)", 200 value: customMidiId, 201 onChange: (e) => setCustomMidiId(e.target.value), 202 className: "w-32 px-2.5 py-1.5 bg-zinc-100 dark:bg-zinc-950 text-zinc-800 dark:text-zinc-200 border border-zinc-300 dark:border-zinc-800 rounded-lg outline-none text-xs font-mono" 203 } 204 ) 205 ] }),
206 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 shrink-0", children: [ 207 (testDiagnostics == null ? void 0 : testDiagnostics.elapsedMs) !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-mono text-zinc-500", children: [ 208 "Execution: ", 209 /* @__PURE__ */ jsxRuntimeExports.jsxs("strong", { className: "text-zinc-800 dark:text-zinc-200", children: [ 210 testDiagnostics.elapsedMs, 211 "ms" 212 ] }) 213 ] }), 214 /* @__PURE__ */ jsxRuntimeExports.jsx( 215 "button", 216 { 217 type: "button", 218 onClick: runBenchmark, 219 disabled: isTesting, 220 className: "px-6 py-2 bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 text-white rounded-xl font-bold flex items-center gap-2 text-xs shadow-md shadow-indigo-600/20 transition-colors", 221 children: isTesting ? "Running Benchmark..." : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
222 /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { size: 14 }), 223 " Run Benchmark" 224 ] }) 225 } 226 ) 227 ] }) 228 ] }), 229 (testDiagnostics == null ? void 0 : testDiagnostics.error) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4 p-3 rounded-xl bg-red-50 dark:bg-red-950/30 border border-red-200 dark:border-red-900/50 text-red-600 dark:text-red-400 text-xs flex items-center gap-2 shrink-0", children: [ 230 /* @__PURE__ */ jsxRuntimeExports.jsx(Info, { size: 15, className: "shrink-0" }), 231 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: testDiagnostics.error }) 232 ] }), 233 /* @__PURE__ */ jsxRuntimeExports.jsx( 234 ScoreMusicXmlViewer, 235 { 236 xmlString: testResultXml, 237 isLoading: isTesting, 238 title: `Engraved Score â ${selectedBenchmark === "custom" ? `Track #${customMidiId}` : selectedBenchmark}`, 239 className: "flex-1 min-h-0" 240 } 241 ) 242 ] }); 243} 244export { 245 StagingArena as default 246};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.