211 lines
No EOL
18 KiB
HTML
211 lines
No EOL
18 KiB
HTML
<!DOCTYPE html><html lang="en" class="dark" data-astro-cid-sckkx6r4> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><meta name="generator" content="Astro v6.1.7"><title>PR Dojo - Code Review Practice</title><link rel="stylesheet" href="/_astro/Layout.D3ovbguN.css">
|
|
<style>tr[data-astro-cid-2ex44dsa]{line-height:1.6}tr[data-astro-cid-2ex44dsa]:hover{background-color:#161b22}td[data-astro-cid-2ex44dsa]:first-child{border-right:1px solid #30363d}tr[data-astro-cid-2ex44dsa].bugged td[data-astro-cid-2ex44dsa]:first-child{border-left:3px solid #f85149}tr[data-astro-cid-2ex44dsa].bugged .line-number[data-astro-cid-2ex44dsa]{color:#f85149}tr[data-astro-cid-2ex44dsa].bugged{background-color:#f8514918}#fix-editor-container[data-astro-cid-7fgtuneg] textarea[data-astro-cid-7fgtuneg]{resize:vertical;min-height:48px}
|
|
</style></head> <body data-astro-cid-sckkx6r4> <div class="min-h-screen" data-astro-cid-7fgtuneg> <!-- Header --> <header class="bg-[#161b22] border-b border-[#30363d]" data-astro-cid-7fgtuneg> <div class="max-w-6xl mx-auto px-4 py-3 flex items-center gap-4" data-astro-cid-7fgtuneg> <a href="/" class="text-[#58a6ff] text-sm font-medium no-underline focus:outline-none focus:ring-0" data-astro-cid-7fgtuneg>← Back to Challenges</a> <span class="text-[#8b949e] text-sm" data-astro-cid-7fgtuneg>/ Challenge #2</span> </div> </header> <main class="max-w-6xl mx-auto px-4 py-6" data-astro-cid-7fgtuneg> <!-- Challenge Header --> <div class="bg-[#161b22] border border-[#30363d] rounded-md p-6 mb-6" data-astro-cid-7fgtuneg> <div class="flex justify-between items-start mb-4" data-astro-cid-7fgtuneg> <div data-astro-cid-7fgtuneg> <h1 class="text-2xl font-semibold text-[#c9d1d9] mb-2 no-underline" data-astro-cid-7fgtuneg>Null Pointer Dereference in User Service</h1> <div class="mb-4" data-astro-cid-7fgtuneg> <span class="text-[#79c0ff] text-xl no-underline" data-astro-cid-7fgtuneg>★★☆☆☆</span> </div> <div class="flex flex-wrap items-center gap-4 text-sm" data-astro-cid-7fgtuneg> <span class="text-[#8b949e]" data-astro-cid-7fgtuneg>📁 <span class="text-[#a5d6ff]" data-astro-cid-7fgtuneg>expressjs/express</span></span> <span class="text-[#8b949e]" data-astro-cid-7fgtuneg>🔢 <code class="bg-[#21262d] px-2 py-0.5 rounded text-xs" data-astro-cid-7fgtuneg>def5678</code></span> <span class="px-2 py-0.5 bg-[#0a3064] rounded text-xs text-[#79c0ff]" data-astro-cid-7fgtuneg>Null Pointer</span> </div> </div> <div class="text-right" data-astro-cid-7fgtuneg> <div class="text-[#79c0ff] text-lg mb-1 no-underline" data-astro-cid-7fgtuneg>★★☆☆☆</div> <div class="text-xs text-[#8b949e]" data-astro-cid-7fgtuneg>Difficulty</div> </div> </div> <div class="bg-[#0a3064] rounded p-3 flex items-center gap-2" data-astro-cid-7fgtuneg> <svg class="w-5 h-5 text-[#58a6ff]" fill="currentColor" viewBox="0 0 20 20" data-astro-cid-7fgtuneg> <path d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-11a1 1 0 10-2 0v2H7a1 1 0 100 2h2v2a1 1 0 102 0v-2h2a1 1 0 100-2h-2V7z" data-astro-cid-7fgtuneg></path> </svg> <span class="text-[#79c0ff] font-semibold" data-astro-cid-7fgtuneg>+75 XP reward</span> </div> </div> <!-- Code Viewer --> <div id="dv-f5n3kgt" class="diff-viewer-container" data-dv-id="dv-f5n3kgt" data-astro-cid-2ex44dsa> <div class="bg-[#0d1117] border border-[#30363d] rounded-md overflow-hidden" data-astro-cid-2ex44dsa> <div class="bg-[#161b22] px-4 py-3 border-b border-[#30363d]" data-astro-cid-2ex44dsa> <span class="text-sm text-[#8b949e]" data-astro-cid-2ex44dsa>file.js</span> </div> <div class="overflow-x-auto" data-astro-cid-2ex44dsa> <table class="w-full font-mono text-sm" data-astro-cid-2ex44dsa> <tbody data-astro-cid-2ex44dsa> <tr data-line="1" class="group hover:bg-[#161b22] cursor-pointer transition-colors" title="Mark line 1 as buggy" data-astro-cid-2ex44dsa> <td class="w-16 text-right pr-4 select-none" data-astro-cid-2ex44dsa> <span class="text-[#8b949e] line-number " data-astro-cid-2ex44dsa> 1 </span> </td> <td class="px-4 py-0.5 whitespace-pre" data-astro-cid-2ex44dsa> <span class="text-[#e6edf3] " data-astro-cid-2ex44dsa> function getUserProfile(userId) { </span> </td> </tr><tr data-line="2" class="group hover:bg-[#161b22] cursor-pointer transition-colors" title="Mark line 2 as buggy" data-astro-cid-2ex44dsa> <td class="w-16 text-right pr-4 select-none" data-astro-cid-2ex44dsa> <span class="text-[#8b949e] line-number " data-astro-cid-2ex44dsa> 2 </span> </td> <td class="px-4 py-0.5 whitespace-pre" data-astro-cid-2ex44dsa> <span class="text-[#e6edf3] " data-astro-cid-2ex44dsa> const user = database.findUser(userId); </span> </td> </tr><tr data-line="3" class="group hover:bg-[#161b22] cursor-pointer transition-colors" title="Mark line 3 as buggy" data-astro-cid-2ex44dsa> <td class="w-16 text-right pr-4 select-none" data-astro-cid-2ex44dsa> <span class="text-[#8b949e] line-number text-[#ff7b72] font-semibold" data-astro-cid-2ex44dsa> 3 </span> </td> <td class="px-4 py-0.5 whitespace-pre" data-astro-cid-2ex44dsa> <span class="text-[#e6edf3] bg-[#ff7b7233] px-2 -mx-2" data-astro-cid-2ex44dsa> return { </span> <span class="ml-2 hint text-[#79c0ff] text-xs opacity-0 group-hover:opacity-100 transition-opacity" data-astro-cid-2ex44dsa>
|
|
• No null check before accessing user properties </span> </td> </tr><tr data-line="4" class="group hover:bg-[#161b22] cursor-pointer transition-colors" title="Mark line 4 as buggy" data-astro-cid-2ex44dsa> <td class="w-16 text-right pr-4 select-none" data-astro-cid-2ex44dsa> <span class="text-[#8b949e] line-number " data-astro-cid-2ex44dsa> 4 </span> </td> <td class="px-4 py-0.5 whitespace-pre" data-astro-cid-2ex44dsa> <span class="text-[#e6edf3] " data-astro-cid-2ex44dsa> name: user.name, </span> </td> </tr><tr data-line="5" class="group hover:bg-[#161b22] cursor-pointer transition-colors" title="Mark line 5 as buggy" data-astro-cid-2ex44dsa> <td class="w-16 text-right pr-4 select-none" data-astro-cid-2ex44dsa> <span class="text-[#8b949e] line-number " data-astro-cid-2ex44dsa> 5 </span> </td> <td class="px-4 py-0.5 whitespace-pre" data-astro-cid-2ex44dsa> <span class="text-[#e6edf3] " data-astro-cid-2ex44dsa> email: user.email, </span> </td> </tr><tr data-line="6" class="group hover:bg-[#161b22] cursor-pointer transition-colors" title="Mark line 6 as buggy" data-astro-cid-2ex44dsa> <td class="w-16 text-right pr-4 select-none" data-astro-cid-2ex44dsa> <span class="text-[#8b949e] line-number text-[#ff7b72] font-semibold" data-astro-cid-2ex44dsa> 6 </span> </td> <td class="px-4 py-0.5 whitespace-pre" data-astro-cid-2ex44dsa> <span class="text-[#e6edf3] bg-[#ff7b7233] px-2 -mx-2" data-astro-cid-2ex44dsa> profile: user.profile.displayName </span> <span class="ml-2 hint text-[#79c0ff] text-xs opacity-0 group-hover:opacity-100 transition-opacity" data-astro-cid-2ex44dsa>
|
|
• Potential null pointer on user.profile </span> </td> </tr><tr data-line="7" class="group hover:bg-[#161b22] cursor-pointer transition-colors" title="Mark line 7 as buggy" data-astro-cid-2ex44dsa> <td class="w-16 text-right pr-4 select-none" data-astro-cid-2ex44dsa> <span class="text-[#8b949e] line-number " data-astro-cid-2ex44dsa> 7 </span> </td> <td class="px-4 py-0.5 whitespace-pre" data-astro-cid-2ex44dsa> <span class="text-[#e6edf3] " data-astro-cid-2ex44dsa> }; </span> </td> </tr><tr data-line="8" class="group hover:bg-[#161b22] cursor-pointer transition-colors" title="Mark line 8 as buggy" data-astro-cid-2ex44dsa> <td class="w-16 text-right pr-4 select-none" data-astro-cid-2ex44dsa> <span class="text-[#8b949e] line-number " data-astro-cid-2ex44dsa> 8 </span> </td> <td class="px-4 py-0.5 whitespace-pre" data-astro-cid-2ex44dsa> <span class="text-[#e6edf3] " data-astro-cid-2ex44dsa> } </span> </td> </tr> </tbody> </table> </div> <div class="bg-[#161b22] px-4 py-3 border-t border-[#30363d]" data-astro-cid-2ex44dsa> <h3 class="text-sm font-semibold text-[#c9d1d9] mb-2" data-astro-cid-2ex44dsa>Hints:</h3> <ul class="space-y-1" data-astro-cid-2ex44dsa> <li class="text-sm text-[#8b949e] flex items-start gap-2" data-astro-cid-2ex44dsa> <span class="text-[#79c0ff] mt-0.5" data-astro-cid-2ex44dsa>•</span> <span data-astro-cid-2ex44dsa>Line 3: No null check before accessing user properties</span> </li><li class="text-sm text-[#8b949e] flex items-start gap-2" data-astro-cid-2ex44dsa> <span class="text-[#79c0ff] mt-0.5" data-astro-cid-2ex44dsa>•</span> <span data-astro-cid-2ex44dsa>Line 6: Potential null pointer on user.profile</span> </li> </ul> </div> </div> </div> <script client:load>
|
|
(() => {
|
|
const el = document.querySelector('[data-dv-id]');
|
|
if (!el) return;
|
|
|
|
const buggedLines = new Set();
|
|
|
|
function updateBuggedState() {
|
|
const rows = el.querySelectorAll('tr[data-line]');
|
|
rows.forEach(row => {
|
|
const lineNum = parseInt(row.getAttribute('data-line') || '0', 10);
|
|
row.classList.toggle('bugged', buggedLines.has(lineNum));
|
|
});
|
|
}
|
|
|
|
el.addEventListener('click', function(e) {
|
|
const target = e.target;
|
|
if (!(target instanceof HTMLElement)) return;
|
|
const row = target.closest('tr[data-line]');
|
|
if (!row) return;
|
|
|
|
const lineNum = parseInt(row.getAttribute('data-line') || '0', 10);
|
|
if (buggedLines.has(lineNum)) {
|
|
buggedLines.delete(lineNum);
|
|
} else {
|
|
buggedLines.add(lineNum);
|
|
}
|
|
|
|
updateBuggedState();
|
|
|
|
el.dispatchEvent(new CustomEvent('bugged-line-toggle', {
|
|
bubbles: true,
|
|
detail: { line: lineNum, bugged: buggedLines.has(lineNum), allBugged: [...buggedLines] }
|
|
}));
|
|
});
|
|
})();
|
|
</script> <!-- Fix Submission --> <div id="fix-panel" class="mt-6 bg-[#161b22] border border-[#30363d] rounded-md overflow-hidden" data-astro-cid-7fgtuneg> <div class="bg-[#161b22] px-4 py-3 border-b border-[#30363d] flex items-center justify-between" data-astro-cid-7fgtuneg> <h2 class="text-lg font-semibold text-[#c9d1d9]" data-astro-cid-7fgtuneg>Submit Your Fix</h2> <div id="bugged-count" class="text-sm text-[#8b949e]" data-astro-cid-7fgtuneg>
|
|
Lines marked: <span id="bugged-count-num" class="text-[#f85149] font-semibold" data-astro-cid-7fgtuneg>0</span> </div> </div> <!-- Marked lines summary --> <div id="marked-lines-summary" class="px-4 py-3 border-b border-[#30363d] hidden" data-astro-cid-7fgtuneg> <p class="text-sm text-[#8b949e] mb-2" data-astro-cid-7fgtuneg>Marked lines:</p> <div id="marked-lines-tags" class="flex flex-wrap gap-2" data-astro-cid-7fgtuneg></div> </div> <!-- Inline fix editor --> <div class="p-4" data-astro-cid-7fgtuneg> <div class="mb-4" data-astro-cid-7fgtuneg> <label class="block text-sm font-medium text-[#c9d1d9] mb-2" data-astro-cid-7fgtuneg>
|
|
Line-by-line fix:
|
|
</label> <p class="text-xs text-[#8b949e] mb-3" data-astro-cid-7fgtuneg>Click a marked line number below to edit its fix.</p> <div id="fix-editor-container" class="space-y-2" data-astro-cid-7fgtuneg> <p id="fix-editor-placeholder" class="text-sm text-[#484f58] italic" data-astro-cid-7fgtuneg>Click on lines in the diff above to mark them, then add your fixes here.</p> </div> </div> <!-- Unified diff textarea --> <div class="mb-4" data-astro-cid-7fgtuneg> <label class="block text-sm font-medium text-[#c9d1d9] mb-2" data-astro-cid-7fgtuneg>
|
|
Or provide as unified diff:
|
|
</label> <textarea id="diff-textarea" placeholder="- old line
|
|
+ new line" rows="6" class="w-full bg-[#0d1117] border border-[#30363d] text-[#c9d1d9] rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#58a6ff] focus:border-transparent text-sm font-mono" data-astro-cid-7fgtuneg></textarea> </div> <div class="flex gap-3" data-astro-cid-7fgtuneg> <button id="submit-fix-btn" class="flex-1 bg-[#1f6feb] hover:bg-[#388bfd] disabled:bg-[#21262d] disabled:text-[#484f58] disabled:cursor-not-allowed text-white font-semibold py-2.5 px-4 rounded-md transition-colors focus:outline-none focus:ring-0" data-astro-cid-7fgtuneg>
|
|
Submit Fix
|
|
</button> <button id="clear-all-btn" class="bg-[#21262d] hover:bg-[#30363d] text-[#8b949e] font-semibold py-2.5 px-4 rounded-md transition-colors focus:outline-none focus:ring-0" data-astro-cid-7fgtuneg>
|
|
Clear All
|
|
</button> </div> <div id="submission-message" class="mt-3 text-sm hidden" data-astro-cid-7fgtuneg></div> </div> </div> </main> </div> </body></html> <script client:load>
|
|
(() => {
|
|
const buggedLines = new Set();
|
|
const fixEditorContainer = document.getElementById('fix-editor-container');
|
|
const markedLinesTags = document.getElementById('marked-lines-tags');
|
|
const markedLinesSummary = document.getElementById('marked-lines-summary');
|
|
const buggedCountNum = document.getElementById('bugged-count-num');
|
|
const submitBtn = document.getElementById('submit-fix-btn');
|
|
const clearBtn = document.getElementById('clear-all-btn');
|
|
const diffTextarea = document.getElementById('diff-textarea');
|
|
const submissionMessage = document.getElementById('submission-message');
|
|
const fixEditorPlaceholder = document.getElementById('fix-editor-placeholder');
|
|
|
|
function updateUI() {
|
|
const arr = [...buggedLines].sort((a, b) => a - b);
|
|
buggedCountNum.textContent = arr.length.toString();
|
|
|
|
if (markedLinesTags) {
|
|
markedLinesTags.innerHTML = '';
|
|
arr.forEach(lineNum => {
|
|
const tag = document.createElement('span');
|
|
tag.className = 'inline-flex items-center gap-1 bg-[#f8514920] text-[#f85149] text-xs px-2 py-0.5 rounded cursor-pointer hover:bg-[#f8514930] transition-colors';
|
|
tag.textContent = `Line ${lineNum}`;
|
|
tag.addEventListener('click', () => {
|
|
showLineFixEditor(lineNum);
|
|
});
|
|
markedLinesTags.appendChild(tag);
|
|
});
|
|
}
|
|
|
|
if (markedLinesSummary) {
|
|
markedLinesSummary.classList.toggle('hidden', arr.length === 0);
|
|
}
|
|
|
|
if (fixEditorPlaceholder) {
|
|
fixEditorPlaceholder.classList.toggle('hidden', arr.length > 0);
|
|
}
|
|
|
|
if (submitBtn) {
|
|
submitBtn.disabled = arr.length === 0 && !diffTextarea?.value.trim();
|
|
}
|
|
}
|
|
|
|
function showLineFixEditor(lineNum) {
|
|
if (!fixEditorContainer) return;
|
|
|
|
const existing = document.getElementById(`fix-editor-${lineNum}`);
|
|
if (existing) {
|
|
existing.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
existing.querySelector('textarea')?.focus();
|
|
return;
|
|
}
|
|
|
|
const editorDiv = document.createElement('div');
|
|
editorDiv.id = `fix-editor-${lineNum}`;
|
|
editorDiv.className = 'bg-[#0d1117] border border-[#30363d] rounded-md p-3';
|
|
|
|
const header = document.createElement('div');
|
|
header.className = 'flex items-center justify-between mb-2';
|
|
|
|
const label = document.createElement('span');
|
|
label.className = 'text-sm font-medium text-[#f85149]';
|
|
label.textContent = `Line ${lineNum} — Your fix:`;
|
|
|
|
const removeBtn = document.createElement('button');
|
|
removeBtn.className = 'text-xs text-[#484f58] hover:text-[#f85149] transition-colors';
|
|
removeBtn.textContent = '✕';
|
|
removeBtn.addEventListener('click', () => {
|
|
buggedLines.delete(lineNum);
|
|
editorDiv.remove();
|
|
updateUI();
|
|
});
|
|
|
|
header.appendChild(label);
|
|
header.appendChild(removeBtn);
|
|
|
|
const textarea = document.createElement('textarea');
|
|
textarea.rows = 3;
|
|
textarea.className = 'w-full bg-[#0d1117] border border-[#30363d] text-[#c9d1d9] rounded px-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-[#58a6ff] focus:border-transparent text-sm font-mono';
|
|
textarea.placeholder = 'Enter the corrected line...';
|
|
textarea.addEventListener('input', updateUI);
|
|
|
|
editorDiv.appendChild(header);
|
|
editorDiv.appendChild(textarea);
|
|
|
|
fixEditorContainer.appendChild(editorDiv);
|
|
}
|
|
|
|
// Listen for bugged-line-toggle events from DiffViewer
|
|
document.addEventListener('bugged-line-toggle', (e) => {
|
|
const detail = e.detail;
|
|
if (detail.bugged) {
|
|
buggedLines.add(detail.line);
|
|
showLineFixEditor(detail.line);
|
|
} else {
|
|
buggedLines.delete(detail.line);
|
|
const editor = document.getElementById(`fix-editor-${detail.line}`);
|
|
if (editor) editor.remove();
|
|
}
|
|
updateUI();
|
|
});
|
|
|
|
// Diff textarea input
|
|
if (diffTextarea) {
|
|
diffTextarea.addEventListener('input', updateUI);
|
|
}
|
|
|
|
// Submit
|
|
if (submitBtn) {
|
|
submitBtn.addEventListener('click', () => {
|
|
const lineFixes = {};
|
|
buggedLines.forEach(lineNum => {
|
|
const editor = document.getElementById(`fix-editor-${lineNum}`);
|
|
if (editor) {
|
|
const ta = editor.querySelector('textarea');
|
|
if (ta?.value.trim()) {
|
|
lineFixes[lineNum] = ta.value.trim();
|
|
}
|
|
}
|
|
});
|
|
|
|
const unifiedDiff = diffTextarea?.value.trim() || '';
|
|
|
|
if (Object.keys(lineFixes).length === 0 && !unifiedDiff) {
|
|
if (submissionMessage) {
|
|
submissionMessage.textContent = 'Please mark some lines or provide a diff.';
|
|
submissionMessage.className = 'mt-3 text-sm text-[#f85149]';
|
|
submissionMessage.classList.remove('hidden');
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Show success message
|
|
if (submissionMessage) {
|
|
submissionMessage.textContent = 'Fix submitted! (Backend integration coming soon)';
|
|
submissionMessage.className = 'mt-3 text-sm text-[3ac840]';
|
|
submissionMessage.classList.remove('hidden');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Clear all
|
|
if (clearBtn) {
|
|
clearBtn.addEventListener('click', () => {
|
|
buggedLines.clear();
|
|
const editors = fixEditorContainer?.querySelectorAll('[id^="fix-editor-"]');
|
|
editors?.forEach(e => e.remove());
|
|
if (diffTextarea) diffTextarea.value = '';
|
|
if (submissionMessage) submissionMessage.classList.add('hidden');
|
|
updateUI();
|
|
|
|
// Reset bugged state in DiffViewer
|
|
document.querySelectorAll('tr.bugged').forEach(row => {
|
|
row.classList.remove('bugged');
|
|
});
|
|
});
|
|
}
|
|
|
|
updateUI();
|
|
})();
|
|
</script> |