Skip to content

Commit

Permalink
Add: new shortform cardiology questions on arrhythmias and basics; up…
Browse files Browse the repository at this point in the history
…date question indexing and filtering in the application
  • Loading branch information
Skippou committed Jan 9, 2025
1 parent 4bb6303 commit fd35cc5
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 26 deletions.
77 changes: 77 additions & 0 deletions questions/cardiology/shortform/arrhythmias.md
Original file line number Diff line number Diff line change
@@ -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

<details>
<summary>Answer</summary>
C) Amiodarone - Safe in structural heart disease
</details>

## 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

<details>
<summary>Answer</summary>
D) All of the above - Brugada criteria
</details>

## Question 3
Most common cause of Torsades de Pointes:
A) Congenital long QT
B) Drug-induced QT prolongation
C) Hypokalemia
D) Bradycardia

<details>
<summary>Answer</summary>
B) Drug-induced QT prolongation - Check QTc with risk medications
</details>

## Question 4
Best acute treatment for SVT with hypotension:
A) Adenosine
B) Synchronized cardioversion
C) Metoprolol
D) Diltiazem

<details>
<summary>Answer</summary>
B) Synchronized cardioversion - Unstable requires immediate electrical therapy
</details>

## Question 5
First line for rate control in AF with preserved EF:
A) Digoxin
B) Beta blocker
C) Calcium channel blocker
D) Amiodarone

<details>
<summary>Answer</summary>
B) Beta blocker - Most effective rate control
</details>

## References
- ACC/AHA Guidelines 2023
- HRS Guidelines 2022
- NEJM 2021: "Management of Cardiac Arrhythmias"
77 changes: 77 additions & 0 deletions questions/cardiology/shortform/basics.md
Original file line number Diff line number Diff line change
@@ -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

<details>
<summary>Answer</summary>
B) Bisoprolol - Highest β1 selectivity
</details>

## Question 2
Normal PR interval range is:
A) 120-200 ms
B) 80-120 ms
C) 200-400 ms
D) 400-600 ms

<details>
<summary>Answer</summary>
A) 120-200 ms - Key ECG parameter
</details>

## Question 3
Most specific troponin for myocardial injury:
A) Troponin I
B) Troponin T
C) CK-MB
D) Myoglobin

<details>
<summary>Answer</summary>
A) Troponin I - Most cardiac-specific marker
</details>

## Question 4
First-line treatment for stable angina:
A) Nitrates
B) Beta blockers
C) Calcium channel blockers
D) Ranolazine

<details>
<summary>Answer</summary>
B) Beta blockers - Reduce myocardial oxygen demand
</details>

## 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

<details>
<summary>Answer</summary>
B) 2.5-3.5 - Higher than aortic valves
</details>

## References
- ACC/AHA Guidelines 2023
- ESC Guidelines 2022
- NEJM 2021: "Cardiovascular Medicine Updates"
56 changes: 33 additions & 23 deletions scripts/indexQuestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
});
Expand Down
24 changes: 21 additions & 3 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ <h1>Internal Medicine Questions</h1>
<option value="unviewed">Unviewed Only</option>
</select>
</div>

<div class="filter-group">
<label for="typeFilter">Question Type:</label>
<select id="typeFilter">
<option value="all">All Types</option>
<option value="regular">Regular</option>
<option value="shortform">Shortform</option>
</select>
</div>
</div>
<!-- Add count display -->
<div id="questionCount" class="question-count"></div>
Expand All @@ -49,15 +58,17 @@ <h1>Internal Medicine Questions</h1>
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);
Expand Down Expand Up @@ -94,9 +105,10 @@ <h1>Internal Medicine Questions</h1>
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');
Expand All @@ -117,6 +129,9 @@ <h1>Internal Medicine Questions</h1>
return viewedFilter === 'viewed' ? isViewed : !isViewed;
});
}
if (typeFilter !== 'all') {
filtered = filtered.filter(q => q.type === typeFilter);
}

// Update question count
const countDisplay = document.getElementById('questionCount');
Expand Down Expand Up @@ -206,11 +221,13 @@ <h3>
});

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', () => {
Expand All @@ -222,6 +239,7 @@ <h3>
option.selected = params.difficulties.includes(option.value);
});
document.getElementById('viewedFilter').value = params.viewed;
document.getElementById('typeFilter').value = params.type;
filterQuestions(false);
});

Expand Down

0 comments on commit fd35cc5

Please sign in to comment.