From fd35cc57a8f9aa6b79e2acb0ec18797c11fbca98 Mon Sep 17 00:00:00 2001 From: Gerrit Cloete Date: Thu, 9 Jan 2025 21:49:58 +0200 Subject: [PATCH] Add: new shortform cardiology questions on arrhythmias and basics; update question indexing and filtering in the application --- questions/cardiology/shortform/arrhythmias.md | 77 +++++++++++++++++++ questions/cardiology/shortform/basics.md | 77 +++++++++++++++++++ scripts/indexQuestions.js | 56 ++++++++------ src/index.html | 24 +++++- 4 files changed, 208 insertions(+), 26 deletions(-) create mode 100644 questions/cardiology/shortform/arrhythmias.md create mode 100644 questions/cardiology/shortform/basics.md diff --git a/questions/cardiology/shortform/arrhythmias.md b/questions/cardiology/shortform/arrhythmias.md new file mode 100644 index 0000000..0e87e91 --- /dev/null +++ b/questions/cardiology/shortform/arrhythmias.md @@ -0,0 +1,77 @@ +--- +id: CARD-SF002 +specialty: cardiology +topic: arrhythmias +difficulty: medium +type: shortform +tags: [cardiology, arrhythmias, ecg, emergencies, copilot] +created: 2025-01-06 +lastUpdated: 2025-01-06 +--- + +# Arrhythmia Quick Questions + +## Question 1 +Drug of choice for stable wide-complex tachycardia: +A) Adenosine +B) Diltiazem +C) Amiodarone +D) Metoprolol + +
+Answer +C) Amiodarone - Safe in structural heart disease +
+ +## Question 2 +Which finding suggests VT over SVT with aberrancy: +A) Fusion beats +B) RS complex >100ms +C) AV dissociation +D) All of the above + +
+Answer +D) All of the above - Brugada criteria +
+ +## Question 3 +Most common cause of Torsades de Pointes: +A) Congenital long QT +B) Drug-induced QT prolongation +C) Hypokalemia +D) Bradycardia + +
+Answer +B) Drug-induced QT prolongation - Check QTc with risk medications +
+ +## Question 4 +Best acute treatment for SVT with hypotension: +A) Adenosine +B) Synchronized cardioversion +C) Metoprolol +D) Diltiazem + +
+Answer +B) Synchronized cardioversion - Unstable requires immediate electrical therapy +
+ +## Question 5 +First line for rate control in AF with preserved EF: +A) Digoxin +B) Beta blocker +C) Calcium channel blocker +D) Amiodarone + +
+Answer +B) Beta blocker - Most effective rate control +
+ +## References +- ACC/AHA Guidelines 2023 +- HRS Guidelines 2022 +- NEJM 2021: "Management of Cardiac Arrhythmias" diff --git a/questions/cardiology/shortform/basics.md b/questions/cardiology/shortform/basics.md new file mode 100644 index 0000000..53a1b2b --- /dev/null +++ b/questions/cardiology/shortform/basics.md @@ -0,0 +1,77 @@ +--- +id: CARD-SF001 +specialty: cardiology +topic: basics +difficulty: easy +type: shortform +tags: [cardiology, basics, ecg, pharmacology, copilot] +created: 2025-01-06 +lastUpdated: 2025-01-06 +--- + +# Cardiology Quick Questions + +## Question 1 +Which beta blocker is most cardioselective? +A) Metoprolol +B) Bisoprolol +C) Carvedilol +D) Propranolol + +
+Answer +B) Bisoprolol - Highest β1 selectivity +
+ +## Question 2 +Normal PR interval range is: +A) 120-200 ms +B) 80-120 ms +C) 200-400 ms +D) 400-600 ms + +
+Answer +A) 120-200 ms - Key ECG parameter +
+ +## Question 3 +Most specific troponin for myocardial injury: +A) Troponin I +B) Troponin T +C) CK-MB +D) Myoglobin + +
+Answer +A) Troponin I - Most cardiac-specific marker +
+ +## Question 4 +First-line treatment for stable angina: +A) Nitrates +B) Beta blockers +C) Calcium channel blockers +D) Ranolazine + +
+Answer +B) Beta blockers - Reduce myocardial oxygen demand +
+ +## Question 5 +Target INR for mechanical mitral valve: +A) 2.0-2.5 +B) 2.5-3.5 +C) 3.0-4.0 +D) 1.5-2.0 + +
+Answer +B) 2.5-3.5 - Higher than aortic valves +
+ +## References +- ACC/AHA Guidelines 2023 +- ESC Guidelines 2022 +- NEJM 2021: "Cardiovascular Medicine Updates" diff --git a/scripts/indexQuestions.js b/scripts/indexQuestions.js index ee7b3dd..5481a35 100644 --- a/scripts/indexQuestions.js +++ b/scripts/indexQuestions.js @@ -11,29 +11,39 @@ function indexQuestions(questionsDir) { if (fs.statSync(filepath).isDirectory()) { walkSync(filepath); } else if (path.extname(file) === '.md') { - const content = fs.readFileSync(filepath, 'utf8'); - const { data, content: markdownContent } = matter(content); - if (data.specialty) { - // Get the first non-empty line after frontmatter that starts with # - const title = markdownContent - .split('\n') - .find(line => line.trim().startsWith('# ')) - ?.replace('# ', '') - ?.trim() || 'Untitled Question'; - - const relativePath = filepath - .split(/[\/\\]questions[\/\\]/)[1] - .replace(/\\/g, '/') - .replace('.md', '.html'); - - questions.push({ - filepath: `questions/${relativePath}`, - specialty: data.specialty, - topic: data.topic, - difficulty: data.difficulty, - id: data.id, - title: title - }); + try { + const content = fs.readFileSync(filepath, 'utf8'); + const { data, content: markdownContent } = matter(content); + + // Verify required fields exist + if (data.specialty && data.topic && data.difficulty) { + // Get the first non-empty line after frontmatter that starts with # + const title = markdownContent + .split('\n') + .find(line => line.trim().startsWith('# ')) + ?.replace('# ', '') + ?.trim() || 'Untitled Question'; + + const relativePath = filepath + .split(/[\/\\]questions[\/\\]/)[1] + .replace(/\\/g, '/') + .replace('.md', '.html'); + + questions.push({ + filepath: `questions/${relativePath}`, + specialty: data.specialty, + topic: data.topic, + difficulty: data.difficulty, + id: data.id || `Q${questions.length + 1}`, + title: title, + type: data.type || 'regular', // Default to 'regular' if not specified + tags: data.tags || [] + }); + } else { + console.warn(`Warning: Missing required fields in ${filepath}`); + } + } catch (error) { + console.error(`Error processing file ${filepath}:`, error); } } }); diff --git a/src/index.html b/src/index.html index 9e9c8fd..5874153 100644 --- a/src/index.html +++ b/src/index.html @@ -36,6 +36,15 @@

Internal Medicine Questions

+ +
+ + +
@@ -49,15 +58,17 @@

Internal Medicine Questions

return { specialties: params.getAll('specialty'), difficulties: params.getAll('difficulty'), - viewed: params.get('viewed') || 'all' + viewed: params.get('viewed') || 'all', + type: params.get('type') || 'all' }; } - function updateUrlParams(specialties, difficulties, viewed) { + function updateUrlParams(specialties, difficulties, viewed, type) { const params = new URLSearchParams(); specialties.forEach(s => params.append('specialty', s)); difficulties.forEach(d => params.append('difficulty', d)); if (viewed !== 'all') params.set('viewed', viewed); + if (type !== 'all') params.set('type', type); const newUrl = `${window.location.pathname}${params.toString() ? '?' + params.toString() : ''}`; history.pushState({}, '', newUrl); @@ -94,9 +105,10 @@

Internal Medicine Questions

const selectedSpecialties = Array.from(specialtySelect.selectedOptions).map(opt => opt.value).filter(Boolean); const selectedDifficulties = Array.from(document.getElementById('difficulty').selectedOptions).map(opt => opt.value).filter(Boolean); const viewedFilter = document.getElementById('viewedFilter').value; + const typeFilter = document.getElementById('typeFilter').value; if (updateUrl) { - updateUrlParams(selectedSpecialties, selectedDifficulties, viewedFilter); + updateUrlParams(selectedSpecialties, selectedDifficulties, viewedFilter, typeFilter); } const viewedQuestions = getFromLocalStorage('viewedQuestions'); @@ -117,6 +129,9 @@

Internal Medicine Questions

return viewedFilter === 'viewed' ? isViewed : !isViewed; }); } + if (typeFilter !== 'all') { + filtered = filtered.filter(q => q.type === typeFilter); + } // Update question count const countDisplay = document.getElementById('questionCount'); @@ -206,11 +221,13 @@

}); document.getElementById('viewedFilter').value = urlParams.viewed; + document.getElementById('typeFilter').value = urlParams.type; // Add event listeners specialtySelect.addEventListener('change', () => filterQuestions(true)); difficultySelect.addEventListener('change', () => filterQuestions(true)); document.getElementById('viewedFilter').addEventListener('change', () => filterQuestions(true)); + document.getElementById('typeFilter').addEventListener('change', () => filterQuestions(true)); // Handle browser back/forward window.addEventListener('popstate', () => { @@ -222,6 +239,7 @@

option.selected = params.difficulties.includes(option.value); }); document.getElementById('viewedFilter').value = params.viewed; + document.getElementById('typeFilter').value = params.type; filterQuestions(false); });