Lab reference intervals nclex
NCLEX lab reference intervals normal values 2024
https://goodnurse.com/article/200/lab-values-cheat-sheet-for…
NCLEX note (Next Gen NCLEX update): As of the NGN format, exam items that include a numeric lab value provide the reference range alongside it. You still need to recognize what is abnormal and know the clinical action to take.
| Lab | Normal Range | Key NCLEX Flag |
|---|---|---|
| Hemoglobin (male) | 13.5 - 17.5 g/dL | <7 = likely transfusion threshold |
| Hemoglobin (female) | 12.0 - 16.0 g/dL | |
| Hematocrit (male) | 41 - 53% | Roughly 3x Hgb |
| Hematocrit (female) | 36 - 46% | |
| RBC (male) | 4.5 - 5.9 million/mcL | |
| RBC (female) | 4.0 - 5.2 million/mcL | |
| WBC | 5,000 - 10,000/mcL | <1,000 neutrophils = neutropenic precautions |
| Platelets | 150,000 - 400,000/mcL | <50,000 = bleeding risk; <20,000 = spontaneous bleed risk |
| MCV | 80 - 100 fL | Low = microcytic; High = macrocytic |
| Lab | Normal Range | Critical Values / Clinical Flag |
|---|---|---|
| Sodium (Na+) | 136 - 145 mEq/L | <120 or >160 = seizure/neuro risk |
| Potassium (K+) | 3.5 - 5.0 mEq/L | <3.0 or >6.0 = cardiac arrhythmia; hold digoxin if low K+ |
| Chloride (Cl-) | 98 - 106 mEq/L | Follows Na+ and pH changes |
| CO2/Bicarb (HCO3-) | 22 - 26 mEq/L | Metabolic component of ABG |
| BUN | 10 - 20 mg/dL | Elevated = dehydration, renal disease |
| Creatinine | 0.6 - 1.3 mg/dL | Best indicator of renal function |
| BUN:Creatinine ratio | 10:1 to 20:1 | >20:1 = prerenal azotemia |
| Glucose (fasting) | 70 - 100 mg/dL | <70 = hypoglycemia; >126 = diabetes threshold |
| Calcium (Ca2+) | 9.0 - 10.5 mg/dL | <8.0 = Trousseau/Chvostek signs; >12 = cardiac issues |
| Magnesium (Mg2+) | 1.5 - 2.5 mEq/L | Low = cardiac arrhythmia, seizures |
| Phosphate | 3.0 - 4.5 mg/dL | Inverse relationship with Ca2+ |
| Component | Normal Range | Interpretation |
|---|---|---|
| pH | 7.35 - 7.45 | <7.35 = acidosis; >7.45 = alkalosis |
| PaCO2 | 35 - 45 mmHg | Respiratory component (inverse with pH) |
| HCO3- | 22 - 26 mEq/L | Metabolic component (moves same direction as pH) |
| PaO2 | 80 - 100 mmHg | <60 = hypoxemia; needs supplemental O2 |
| SaO2 | 95 - 100% | <90% = critical |
| Lab | Normal Range | Key Flag |
|---|---|---|
| PT (Prothrombin Time) | 11 - 13.5 seconds | Monitors warfarin (Coumadin) |
| INR | 0.8 - 1.1 (therapeutic for warfarin: 2 - 3) | >3 = hold warfarin; antidote = Vitamin K |
| aPTT | 25 - 35 seconds | Monitors heparin; therapeutic = 60 - 80 seconds |
| Thrombin Time | 17 - 23 seconds |
| Lab | Normal Range |
|---|---|
| AST (SGOT) | 10 - 40 units/L |
| ALT (SGPT) | 9 - 45 units/L (slight sex variation) |
| ALP | 30 - 120 units/L |
| Total Bilirubin | 0.2 - 1.2 mg/dL |
| Direct Bilirubin | 0 - 0.3 mg/dL |
| Albumin | 3.5 - 5.0 g/dL |
| Total Protein | 6.0 - 8.0 g/dL |
| Lab | Normal Range | Key Flag |
|---|---|---|
| Troponin I | <0.04 ng/mL | Any elevation = cardiac injury; most specific for MI |
| Troponin T | <0.01 ng/mL | Rises 3-4 hrs after MI, peaks 24-48 hrs |
| CK-MB | 0 - 3 ng/mL | Rises 4-6 hrs; back to normal in 48-72 hrs |
| BNP | <100 pg/mL | >500 = heart failure likely |
| NT-proBNP | <125 pg/mL | Age-adjusted; elevated in HF |
| Lab | Normal Range |
|---|---|
| Urine specific gravity | 1.005 - 1.030 |
| Urine pH | 4.5 - 8.0 |
| Urine protein | Negative / trace |
| Urine glucose | Negative |
| Urine RBCs | 0 - 2/hpf |
| Urine WBCs | 0 - 4/hpf |
| GFR | >60 mL/min/1.73m2 (CKD if <60 for 3+ months) |
| Lab | Value | Meaning |
|---|---|---|
| Fasting glucose | <100 mg/dL | Normal |
| Fasting glucose | 100 - 125 mg/dL | Prediabetes |
| Fasting glucose | ≥126 mg/dL | Diabetes |
| HbA1c | <5.7% | Normal |
| HbA1c | 5.7 - 6.4% | Prediabetes |
| HbA1c | ≥6.5% | Diabetes; goal for diabetics: <7% |
| Lab | Normal Range |
|---|---|
| TSH | 0.4 - 4.0 mIU/L |
| Free T4 | 0.8 - 1.8 ng/dL |
| Free T3 | 2.3 - 4.2 pg/mL |
| Drug | Therapeutic Range | Toxic Level |
|---|---|---|
| Digoxin | 0.5 - 2.0 ng/mL | >2.0 ng/mL |
| Lithium | 0.6 - 1.2 mEq/L (acute: 0.8-1.4) | >1.5 mEq/L |
| Phenytoin (Dilantin) | 10 - 20 mcg/mL | >20 mcg/mL |
| Theophylline | 10 - 20 mcg/mL | >20 mcg/mL |
| Vancomycin (trough) | 10 - 20 mcg/mL | >20 mcg/mL |
| Carbamazepine | 4 - 12 mcg/mL |
Create a printable lab values PDF I can study from
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace not found"
mkdir -p /home/daytona/workspace/nclex-lab-values
~/nclex-lab-values/generate_pdf.py
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph,
Spacer, HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import PageBreak
OUTPUT = "/home/daytona/workspace/nclex-lab-values/NCLEX_Lab_Values.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1B3A6B")
TEAL = colors.HexColor("#1A7F8E")
LIGHT_BG = colors.HexColor("#EBF4F7")
HEADER_BG = colors.HexColor("#1B3A6B")
ROW_ALT = colors.HexColor("#F0F7FA")
WARN_RED = colors.HexColor("#C0392B")
WARN_AMB = colors.HexColor("#E67E22")
WHITE = colors.white
BLACK = colors.black
GREY_LINE = colors.HexColor("#BDC3C7")
def make_doc():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=letter,
leftMargin=0.6*inch, rightMargin=0.6*inch,
topMargin=0.6*inch, bottomMargin=0.6*inch,
title="NCLEX Lab Reference Intervals",
author="Orris Study Aid"
)
return doc
# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
title_style = ParagraphStyle(
"DocTitle", fontSize=22, leading=28,
textColor=WHITE, alignment=TA_CENTER, fontName="Helvetica-Bold"
)
subtitle_style = ParagraphStyle(
"Subtitle", fontSize=11, leading=14,
textColor=WHITE, alignment=TA_CENTER, fontName="Helvetica"
)
section_style = ParagraphStyle(
"Section", fontSize=13, leading=17,
textColor=WHITE, alignment=TA_LEFT, fontName="Helvetica-Bold",
leftIndent=6
)
body_style = ParagraphStyle(
"Body", fontSize=8.5, leading=12,
textColor=BLACK, fontName="Helvetica"
)
tip_style = ParagraphStyle(
"Tip", fontSize=8, leading=11,
textColor=NAVY, fontName="Helvetica-Oblique",
leftIndent=8, rightIndent=8
)
flag_style = ParagraphStyle(
"Flag", fontSize=7.5, leading=10,
textColor=WARN_RED, fontName="Helvetica-Bold"
)
mnemonic_style = ParagraphStyle(
"Mnemonic", fontSize=8.5, leading=12,
textColor=NAVY, fontName="Helvetica-Bold"
)
# ── Helpers ──────────────────────────────────────────────────────────────────
def section_banner(title_text):
"""Coloured banner acting as a section header."""
tbl = Table([[Paragraph(title_text, section_style)]], colWidths=[7.3*inch])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("ROUNDEDCORNERS", [4]),
]))
return tbl
def data_table(headers, rows, col_widths, critical_rows=None):
"""Styled data table with alternating rows and optional red-highlight rows."""
critical_rows = critical_rows or []
data = [headers] + rows
tbl = Table(data, colWidths=col_widths, repeatRows=1)
style_cmds = [
# Header row
("BACKGROUND", (0,0), (-1,0), HEADER_BG),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 8),
("ALIGN", (0,0), (-1,0), "CENTER"),
("TOPPADDING", (0,0), (-1,0), 5),
("BOTTOMPADDING", (0,0), (-1,0), 5),
# Body
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 7.5),
("TOPPADDING", (0,1), (-1,-1), 3),
("BOTTOMPADDING", (0,1), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
for i, row in enumerate(rows, start=1):
if i in critical_rows:
style_cmds.append(("BACKGROUND", (0,i), (-1,i), colors.HexColor("#FDECEA")))
style_cmds.append(("TEXTCOLOR", (0,i), (-1,i), WARN_RED))
elif i % 2 == 0:
style_cmds.append(("BACKGROUND", (0,i), (-1,i), ROW_ALT))
tbl.setStyle(TableStyle(style_cmds))
return tbl
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD CONTENT
# ═══════════════════════════════════════════════════════════════════════════════
story = []
# ── Title block ──────────────────────────────────────────────────────────────
title_block = Table(
[[Paragraph("NCLEX Lab Reference Intervals", title_style)],
[Paragraph("Complete Study Guide · All Critical Values · Mnemonics", subtitle_style)]],
colWidths=[7.3*inch]
)
title_block.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 12),
("ROUNDEDCORNERS", [6]),
]))
story.append(title_block)
story.append(Spacer(1, 10))
# ─── IMPORTANT NOTE ──────────────────────────────────────────────────────────
note = Table([[Paragraph(
"📌 NGN NCLEX Update: Items that include a numeric lab value now provide "
"the reference range alongside it. Focus on recognising abnormal patterns "
"and selecting the correct nursing action.", tip_style
)]], colWidths=[7.3*inch])
note.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#FFF9E6")),
("BOX", (0,0), (-1,-1), 0.8, WARN_AMB),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
story.append(note)
story.append(Spacer(1, 10))
# ════════════════════════════════════════════════════════════════════════════
# 1. CBC
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("1. Complete Blood Count (CBC)"),
Spacer(1, 4),
data_table(
headers=["Lab Test", "Normal Range", "Critical Flags / NCLEX Tips"],
col_widths=[1.9*inch, 1.5*inch, 3.9*inch],
rows=[
["Hemoglobin – Male", "13.5 – 17.5 g/dL", "< 7 g/dL → likely transfusion threshold"],
["Hemoglobin – Female", "12.0 – 16.0 g/dL", "Pale, fatigue, tachycardia = anemia signs"],
["Hematocrit – Male", "41 – 53 %", "Hct ≈ 3× Hgb rule-of-thumb"],
["Hematocrit – Female", "36 – 46 %", "< 30% = significant; needs intervention"],
["RBC – Male", "4.5 – 5.9 M/mcL", "Low = anemia; high = polycythemia/dehydration"],
["RBC – Female", "4.0 – 5.2 M/mcL", ""],
["WBC (Total)", "5,000 – 10,000/mcL","ANC < 1,000 = neutropenic precautions"],
["Platelets", "150,000 – 400,000/mcL", "< 50,000 = bleeding precautions; < 20,000 = spontaneous bleed"],
["MCV", "80 – 100 fL", "Low = microcytic (iron-def); High = macrocytic (B12/folate)"],
["MCH", "27 – 33 pg", "Reflects Hgb content per RBC"],
],
critical_rows=[1, 8]
),
Spacer(1, 4),
]))
story.append(Spacer(1, 8))
# ════════════════════════════════════════════════════════════════════════════
# 2. Serum Electrolytes
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("2. Serum Electrolytes (BMP / CMP)"),
Spacer(1, 4),
data_table(
headers=["Electrolyte", "Normal Range", "Critical Flags / NCLEX Tips"],
col_widths=[1.9*inch, 1.5*inch, 3.9*inch],
rows=[
["Sodium (Na⁺)", "136 – 145 mEq/L", "< 120 or > 160 = seizures / neuro changes"],
["Potassium (K⁺)", "3.5 – 5.0 mEq/L", "< 3.0 or > 6.0 = cardiac arrhythmia; hold digoxin if K⁺ low"],
["Chloride (Cl⁻)", "98 – 106 mEq/L", "Follows Na⁺ and acid–base changes"],
["CO₂ / HCO₃⁻", "22 – 26 mEq/L", "Metabolic component; low = metabolic acidosis"],
["BUN", "10 – 20 mg/dL", "Elevated = dehydration, renal disease, GI bleed"],
["Creatinine", "0.6 – 1.3 mg/dL", "Best single indicator of glomerular filtration"],
["BUN : Creatinine", "10:1 – 20:1", "> 20:1 = pre-renal azotemia (dehydration)"],
["Glucose (fasting)", "70 – 100 mg/dL", "< 70 = hypoglycemia; > 126 = diabetes threshold"],
["Calcium (Ca²⁺)", "9.0 – 10.5 mg/dL", "< 8.0 = Chvostek/Trousseau; > 12.0 = cardiac effects"],
["Magnesium (Mg²⁺)", "1.5 – 2.5 mEq/L", "Low = arrhythmias, tremors, seizures; repleted before K⁺"],
["Phosphate (PO₄)", "3.0 – 4.5 mg/dL", "Inverse to Ca²⁺; low in refeeding syndrome"],
],
critical_rows=[1, 2, 9, 10]
),
Spacer(1, 4),
]))
story.append(Spacer(1, 8))
# ════════════════════════════════════════════════════════════════════════════
# 3. ABG
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("3. Arterial Blood Gas (ABG)"),
Spacer(1, 4),
data_table(
headers=["Component", "Normal Range", "Interpretation"],
col_widths=[1.5*inch, 1.5*inch, 4.3*inch],
rows=[
["pH", "7.35 – 7.45", "< 7.35 = acidosis | > 7.45 = alkalosis"],
["PaCO₂", "35 – 45 mmHg", "RESPIRATORY component; rises in hypoventilation (acidosis); falls in hyperventilation (alkalosis)"],
["HCO₃⁻", "22 – 26 mEq/L", "METABOLIC component; low in metabolic acidosis; high in metabolic alkalosis"],
["PaO₂", "80 – 100 mmHg", "< 60 mmHg = hypoxemia; supplement O₂; < 40 = severe"],
["SaO₂", "95 – 100 %", "< 90% = critical; correlate with PaO₂"],
["Anion Gap","8 – 12 mEq/L", "High-gap acidosis: MUDPILES (Methanol, Uraemia, DKA, Propylene glycol, INH, Lactic acidosis, Ethylene glycol, Salicylates)"],
],
critical_rows=[1, 4, 5]
),
Spacer(1, 4),
Table([[Paragraph(
"ROME Mnemonic: Respiratory = Opposite (pH ↑, PaCO₂ ↓ / pH ↓, PaCO₂ ↑) | "
"Metabolic = Equal (pH ↑, HCO₃⁻ ↑ / pH ↓, HCO₃⁻ ↓)",
mnemonic_style
)]], colWidths=[7.3*inch], style=[
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#E8F4FD")),
("BOX", (0,0), (-1,-1), 0.6, TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]),
]))
story.append(Spacer(1, 8))
# ════════════════════════════════════════════════════════════════════════════
# 4. Coagulation
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("4. Coagulation Studies"),
Spacer(1, 4),
data_table(
headers=["Test", "Normal Range", "Therapeutic / Critical / NCLEX Tips"],
col_widths=[1.7*inch, 1.7*inch, 3.9*inch],
rows=[
["PT", "11 – 13.5 sec", "Monitors WARFARIN (Coumadin); prolonged = bleeding risk"],
["INR", "0.8 – 1.1", "Therapeutic (warfarin) = 2.0–3.0; > 3.0 → hold warfarin; antidote = Vitamin K"],
["aPTT", "25 – 35 sec", "Monitors HEPARIN; therapeutic = 60–80 sec; antidote = Protamine Sulfate"],
["Fibrinogen", "200 – 400 mg/dL", "Low = DIC, liver disease, massive transfusion"],
["D-Dimer", "< 0.5 mcg/mL", "Elevated = DVT/PE, DIC; not specific alone"],
],
critical_rows=[1, 3]
),
Spacer(1, 4),
Table([[Paragraph(
"Memory Hook: PT/INR → Warfarin (starts with W like Warfarin = 'W'arfarin → 'W'arfarin monitors P'T') | "
"aPTT → Heparin (both have a 'P' and are IV/injectable)",
mnemonic_style
)]], colWidths=[7.3*inch], style=[
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#E8F4FD")),
("BOX", (0,0), (-1,-1), 0.6, TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]),
]))
story.append(Spacer(1, 8))
# ════════════════════════════════════════════════════════════════════════════
# 5. LFTs
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("5. Liver Function Tests (LFTs)"),
Spacer(1, 4),
data_table(
headers=["Test", "Normal Range", "NCLEX Tips"],
col_widths=[1.9*inch, 1.5*inch, 3.9*inch],
rows=[
["AST (SGOT)", "10 – 40 units/L", "Elevated in hepatitis, MI, muscle damage (less liver-specific)"],
["ALT (SGPT)", "9 – 45 units/L", "Most liver-specific transaminase; elevated in hepatitis/cirrhosis"],
["ALP", "30 – 120 units/L", "Elevated in cholestasis, bone disease, pregnancy"],
["Total Bilirubin", "0.2 – 1.2 mg/dL", "> 2.5 = visible jaundice; monitor in newborns"],
["Direct Bilirubin", "0 – 0.3 mg/dL", "Conjugated; elevated in obstructive jaundice"],
["Albumin", "3.5 – 5.0 g/dL", "Best marker of chronic liver function; low = malnutrition/cirrhosis"],
["Total Protein", "6.0 – 8.0 g/dL", "Low = malnutrition, nephrotic syndrome"],
["Ammonia", "15 – 45 mcg/dL", "Elevated in hepatic encephalopathy; low-protein diet helps"],
],
critical_rows=[6, 8]
),
]))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# 6. Cardiac Markers
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("6. Cardiac Markers"),
Spacer(1, 4),
data_table(
headers=["Marker", "Normal Range", "Timing / NCLEX Tips"],
col_widths=[1.9*inch, 1.7*inch, 3.7*inch],
rows=[
["Troponin I", "< 0.04 ng/mL", "Rises 3–4 hr after MI; peaks 24–48 hr; returns to normal in 7–10 days; GOLD STANDARD"],
["Troponin T", "< 0.01 ng/mL", "Same timing as Troponin I; most specific for myocardial injury"],
["CK-MB", "0 – 3 ng/mL", "Rises 4–6 hr; peaks 18–24 hr; normalises in 48–72 hr; re-elevation = re-infarction"],
["BNP", "< 100 pg/mL", "> 500 = heart failure likely; used for HF diagnosis & monitoring"],
["NT-proBNP", "< 125 pg/mL", "Age-adjusted; elevated in HF; better for outpatient monitoring"],
["Myoglobin", "< 90 ng/mL", "Earliest to rise (1–3 hr) but NOT cardiac-specific"],
],
critical_rows=[1, 2]
),
]))
story.append(Spacer(1, 8))
# ════════════════════════════════════════════════════════════════════════════
# 7. Renal / Urinalysis
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("7. Renal Function & Urinalysis"),
Spacer(1, 4),
data_table(
headers=["Test", "Normal Range", "NCLEX Tips"],
col_widths=[1.9*inch, 1.5*inch, 3.9*inch],
rows=[
["GFR", "> 60 mL/min/1.73m²", "< 60 for ≥ 3 months = CKD; < 15 = kidney failure (dialysis)"],
["Urine Specific Gravity","1.005 – 1.030", "Low (1.001–1.005) = dilute/overhydration; High (> 1.030) = dehydration/SIADH"],
["Urine pH", "4.5 – 8.0", "Alkaline urine helps with uric-acid stones; acidic with UTI prevention"],
["Urine Protein", "Negative / trace", "Proteinuria = glomerular damage, nephrotic syndrome"],
["Urine Glucose", "Negative", "Glycosuria if blood glucose > 180 mg/dL (renal threshold)"],
["Urine RBCs", "0 – 2 /hpf", "> 3 = hematuria; rule out UTI, stones, cancer"],
["Urine WBCs", "0 – 4 /hpf", "> 5 = pyuria; indicates UTI or pyelonephritis"],
["Urine Output", "≥ 30 mL/hr (adult)", "< 30 mL/hr = oliguria; notify provider; may indicate shock/AKI"],
],
critical_rows=[1, 8]
),
]))
story.append(Spacer(1, 8))
# ════════════════════════════════════════════════════════════════════════════
# 8. Glucose / Diabetes
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("8. Glucose & Diabetes Lab Values"),
Spacer(1, 4),
data_table(
headers=["Test", "Normal / Threshold", "NCLEX Tips"],
col_widths=[2.0*inch, 1.6*inch, 3.7*inch],
rows=[
["Fasting Glucose – Normal", "70 – 99 mg/dL", "Euglycemic; no action needed"],
["Fasting Glucose – Prediabetes", "100 – 125 mg/dL", "Lifestyle modification; monitor annually"],
["Fasting Glucose – Diabetes", "≥ 126 mg/dL", "Two separate tests required for diagnosis"],
["Random Glucose – Diabetes", "≥ 200 mg/dL", "With symptoms (polyuria, polydipsia, weight loss)"],
["2-hr OGTT – Diabetes", "≥ 200 mg/dL", "75 g oral glucose load"],
["HbA1c – Normal", "< 5.7 %", "Reflects 2–3 month average glucose"],
["HbA1c – Prediabetes", "5.7 – 6.4 %", ""],
["HbA1c – Diabetes", "≥ 6.5 %", "Diabetic goal: < 7.0 % (ADA); < 8.0 % in elderly"],
["Critical Hypoglycemia", "< 40 mg/dL", "Give 15–20 g fast-acting carbs OR IV D50; recheck in 15 min"],
["Critical Hyperglycemia (DKA)", "> 250 + ketones", "Kussmaul breathing, fruity breath, anion-gap acidosis"],
],
critical_rows=[3, 9, 10]
),
]))
story.append(Spacer(1, 8))
# ════════════════════════════════════════════════════════════════════════════
# 9. Thyroid
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("9. Thyroid Function Tests"),
Spacer(1, 4),
data_table(
headers=["Test", "Normal Range", "NCLEX Tips"],
col_widths=[1.9*inch, 1.5*inch, 3.9*inch],
rows=[
["TSH", "0.4 – 4.0 mIU/L", "High TSH = HYPOTHYROID (pituitary compensating); Low TSH = HYPERTHYROID"],
["Free T4", "0.8 – 1.8 ng/dL", "Low T4 + High TSH = primary hypothyroidism; treat with levothyroxine"],
["Free T3", "2.3 – 4.2 pg/mL", "Most active thyroid hormone; T3 toxicosis possible with normal T4"],
],
critical_rows=[]
),
Spacer(1, 4),
Table([[Paragraph(
"Thyroid Memory: TSH is the THERMOSTAT — if temp is too low (hypothyroid), "
"the thermostat turns UP (high TSH). If temp is too high (hyperthyroid), "
"the thermostat turns DOWN (low TSH).",
mnemonic_style
)]], colWidths=[7.3*inch], style=[
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#E8F4FD")),
("BOX", (0,0), (-1,-1), 0.6, TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]),
]))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# 10. Therapeutic Drug Levels
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("10. Therapeutic Drug Monitoring"),
Spacer(1, 4),
data_table(
headers=["Drug", "Therapeutic Range", "Toxic Level", "Key Nursing Actions"],
col_widths=[1.5*inch, 1.4*inch, 1.1*inch, 3.3*inch],
rows=[
["Digoxin", "0.5 – 2.0 ng/mL", "> 2.0", "Hold if K⁺ < 3.5; check apical pulse 1 min; antidote = Digibind"],
["Lithium", "0.6 – 1.2 mEq/L", "> 1.5", "Maintain hydration; monitor Na⁺; toxic: tremor, ataxia, confusion"],
["Phenytoin", "10 – 20 mcg/mL", "> 20", "Nystagmus, ataxia at toxic levels; gingival hyperplasia with long use"],
["Carbamazepine", "4 – 12 mcg/mL", "> 12", "Monitor CBC (aplastic anemia risk); teratogenic"],
["Vancomycin (trough)","10–20 mcg/mL", "> 20", "Nephrotoxic; monitor SCr; 'Red Man Syndrome' = too-rapid infusion"],
["Theophylline", "10 – 20 mcg/mL", "> 20", "N/V, seizures, arrhythmias at toxic levels; caffeine interaction"],
["Methotrexate", "Variable", "> threshold","Monitor CBC, LFTs; leucovorin rescue; avoid NSAIDs"],
["Cyclosporine", "100–400 ng/mL", "Variable", "Nephrotoxic; monitor BP, SCr; grapefruit interaction"],
],
critical_rows=[1, 2, 3]
),
]))
story.append(Spacer(1, 8))
# ════════════════════════════════════════════════════════════════════════════
# 11. Lipid Panel
# ════════════════════════════════════════════════════════════════════════════
story.append(KeepTogether([
section_banner("11. Lipid Panel"),
Spacer(1, 4),
data_table(
headers=["Test", "Desirable Level", "NCLEX Tips"],
col_widths=[1.9*inch, 1.5*inch, 3.9*inch],
rows=[
["Total Cholesterol", "< 200 mg/dL", "200–239 = borderline; ≥ 240 = high"],
["LDL (bad)", "< 100 mg/dL", "Goal < 70 in high CV risk (post-MI, DM with CV disease)"],
["HDL (good)", "≥ 60 mg/dL", "< 40 (M) / < 50 (F) = risk factor for CVD"],
["Triglycerides", "< 150 mg/dL", "150–199 = borderline; ≥ 500 = pancreatitis risk"],
],
critical_rows=[]
),
]))
story.append(Spacer(1, 8))
# ════════════════════════════════════════════════════════════════════════════
# 12. Quick-Memorise Summary
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("12. Quick-Memorise Cheat Sheet"))
story.append(Spacer(1, 6))
quick = [
["K⁺ 3.5 – 5.0", "Na⁺ 136 – 145", "Ca²⁺ 9.0 – 10.5", "Mg²⁺ 1.5 – 2.5"],
["Glucose 70 – 100", "BUN 10 – 20", "Creatinine 0.6–1.3", "HCO₃⁻ 22 – 26"],
["Hgb M 13.5–17.5", "Hgb F 12.0–16.0", "Hct M 41–53%", "Hct F 36–46%"],
["WBC 5,000–10,000", "Platelets 150–400K", "INR 0.8–1.1", "aPTT 25–35 sec"],
["pH 7.35–7.45", "PaCO₂ 35–45 mmHg", "PaO₂ 80–100 mmHg", "SaO₂ 95–100%"],
["TSH 0.4–4.0", "HbA1c < 5.7% normal","BNP < 100 pg/mL", "Troponin I < 0.04"],
["Digoxin 0.5–2.0", "Lithium 0.6–1.2", "Phenytoin 10–20", "Vancomycin 10–20"],
]
quick_tbl = Table(quick, colWidths=[1.82*inch]*4)
quick_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("BACKGROUND", (0,1), (-1,1), colors.HexColor("#1A7F8E")),
("BACKGROUND", (0,2), (-1,2), NAVY),
("BACKGROUND", (0,3), (-1,3), colors.HexColor("#1A7F8E")),
("BACKGROUND", (0,4), (-1,4), NAVY),
("BACKGROUND", (0,5), (-1,5), colors.HexColor("#1A7F8E")),
("BACKGROUND", (0,6), (-1,6), NAVY),
("TEXTCOLOR", (0,0), (-1,-1), WHITE),
("FONTNAME", (0,0), (-1,-1), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.5, WHITE),
]))
story.append(quick_tbl)
story.append(Spacer(1, 8))
# ════════════════════════════════════════════════════════════════════════════
# Footer note
# ════════════════════════════════════════════════════════════════════════════
story.append(HRFlowable(width="100%", thickness=0.5, color=GREY_LINE))
story.append(Spacer(1, 4))
story.append(Paragraph(
"Reference: Goldman-Cecil Medicine (Appendix 2 – Reference Intervals) | "
"Values reflect typical adult non-pregnant ranges. Always verify against your facility's reference ranges.",
ParagraphStyle("Footer", fontSize=7, textColor=colors.grey, alignment=TA_CENTER)
))
# ════════════════════════════════════════════════════════════════════════════
# BUILD
# ════════════════════════════════════════════════════════════════════════════
doc = make_doc()
doc.build(story)
print(f"PDF written to: {OUTPUT}")
python /home/daytona/workspace/nclex-lab-values/generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/nclex-lab-values/NCLEX_Lab_Values.pdf
NCLEX Lab Values
PDF Document · PDF
| Section | Content |
|---|---|
| CBC | Hgb, Hct, RBC, WBC, Platelets, MCV with critical flags |
| Electrolytes (BMP/CMP) | Na, K, Cl, HCO3, BUN, Creatinine, Glucose, Ca, Mg, Phosphate |
| ABG | pH, PaCO2, HCO3, PaO2, SaO2, Anion Gap + ROME mnemonic |
| Coagulation | PT, INR, aPTT, Fibrinogen, D-Dimer + Warfarin/Heparin tips |
| LFTs | AST, ALT, ALP, Bilirubin, Albumin, Ammonia |
| Cardiac Markers | Troponin I/T, CK-MB, BNP, NT-proBNP with timing |
| Renal/Urinalysis | GFR, specific gravity, proteinuria, urine output thresholds |
| Glucose/Diabetes | Fasting, OGTT, HbA1c, DKA flags |
| Thyroid | TSH, T3, T4 + thermostat mnemonic |
| Therapeutic Drugs | Digoxin, Lithium, Phenytoin, Vancomycin, and more |
| Lipid Panel | LDL, HDL, Total Cholesterol, Triglycerides |
| Quick Cheat Sheet | All key values in a compact color-coded grid |
Provision of safe environment nclex
NCLEX provision safe environment safety and infection control topics 2024
https://www.kaptest.com/study/nclex/whats-tested-on-the-ncle…
| Topic Area | Weight on Exam |
|---|---|
| Safety & Infection Control (total) | ~12% of NCLEX |
| Management of Care (parent category) | ~20% of NCLEX |
| Element | Action |
|---|---|
| Hand hygiene | Before/after every patient contact; after removing gloves |
| Gloves | Contact with blood, body fluids, mucous membranes, non-intact skin |
| Gown | If clothing/skin likely to be soiled |
| Mask + eye protection | Splashing or spraying of body fluids likely |
| Safe needle handling | No recapping; sharps container at point of use |
| Patient care equipment | Clean and disinfect between patients |
| Right | Details |
|---|---|
| Right patient | 2 identifiers: name + date of birth (never room number) |
| Right drug | Verify order; clarify if unclear |
| Right dose | Calculate; double-check with second nurse for high-alert drugs |
| Right route | Oral vs IV vs IM vs sublingual - never substitute |
| Right time | Within 30-60 min of scheduled time (facility policy) |
| Right documentation | Sign off immediately after giving, not before |
| Right reason | Know why the patient is receiving the drug |
| Right to refuse | Patient has the right; document and notify provider |
| Requirement | Detail |
|---|---|
| Order required | Yes - with time limit |
| Assessment frequency | Every 2 hours |
| Release and reposition | Every 2 hours |
| Circulation check | Each assessment |
| Documentation | Type, rationale, alternatives, response |
| Tie to | Bed frame (NOT side rail) |
| Knot type | Quick-release knot |
| Color | Priority | Meaning |
|---|---|---|
| Red | Immediate | Life-threatening but salvageable |
| Yellow | Delayed | Serious but stable |
| Green | Minor | "Walking wounded" |
| Black | Expectant | Dead or unsurvivable injuries |
Create a study guide PDF on safe environment topics
mkdir -p /home/daytona/workspace/nclex-safe-env
~/nclex-safe-env/generate_safe_env.py
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph,
Spacer, HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
OUTPUT = "/home/daytona/workspace/nclex-safe-env/NCLEX_Safe_Environment.pdf"
# ── Colour palette ─────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1B3A6B")
TEAL = colors.HexColor("#1A7F8E")
GREEN = colors.HexColor("#1E7E34")
ORANGE = colors.HexColor("#E67E22")
RED_DARK = colors.HexColor("#C0392B")
LIGHT_BG = colors.HexColor("#EBF4F7")
ROW_ALT = colors.HexColor("#F0F7FA")
ROW_GREEN = colors.HexColor("#EAF7EC")
ROW_RED = colors.HexColor("#FDECEA")
ROW_AMBER = colors.HexColor("#FEF9E7")
WHITE = colors.white
GREY_LINE = colors.HexColor("#BDC3C7")
GREY_TEXT = colors.HexColor("#555555")
# ── Document ───────────────────────────────────────────────────────────────
def make_doc():
return SimpleDocTemplate(
OUTPUT, pagesize=letter,
leftMargin=0.55*inch, rightMargin=0.55*inch,
topMargin=0.55*inch, bottomMargin=0.55*inch,
title="NCLEX – Provision of a Safe Environment",
author="Orris Study Aid"
)
# ── Styles ─────────────────────────────────────────────────────────────────
title_style = ParagraphStyle("T", fontSize=21, leading=27, textColor=WHITE,
alignment=TA_CENTER, fontName="Helvetica-Bold")
sub_style = ParagraphStyle("S", fontSize=10, leading=14, textColor=WHITE,
alignment=TA_CENTER, fontName="Helvetica")
sec_style = ParagraphStyle("Sec", fontSize=12, leading=16, textColor=WHITE,
fontName="Helvetica-Bold", leftIndent=6)
body_style = ParagraphStyle("B", fontSize=8.5, leading=12, textColor=colors.black,
fontName="Helvetica")
tip_style = ParagraphStyle("Tip", fontSize=8, leading=11, textColor=NAVY,
fontName="Helvetica-Oblique", leftIndent=8)
mnem_style = ParagraphStyle("M", fontSize=8.5, leading=12, textColor=NAVY,
fontName="Helvetica-Bold", leftIndent=6)
bullet_style= ParagraphStyle("Bul", fontSize=8.5, leading=13, textColor=colors.black,
fontName="Helvetica", leftIndent=12, bulletIndent=4)
warn_style = ParagraphStyle("W", fontSize=8.5, leading=12, textColor=RED_DARK,
fontName="Helvetica-Bold", leftIndent=6)
footer_style= ParagraphStyle("F", fontSize=6.8, textColor=GREY_TEXT,
alignment=TA_CENTER, fontName="Helvetica")
def B(text): return Paragraph(text, bullet_style)
def T(text): return Paragraph(text, body_style)
def M(text): return Paragraph(text, mnem_style)
def W(text): return Paragraph(text, warn_style)
# ── Helpers ────────────────────────────────────────────────────────────────
def banner(text, color=TEAL):
tbl = Table([[Paragraph(text, sec_style)]], colWidths=[7.4*inch])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return tbl
def dtable(headers, rows, col_widths, hi_rows=None, hi_color=None):
hi_rows = hi_rows or []
hi_color = hi_color or ROW_RED
data = [headers] + rows
tbl = Table(data, colWidths=col_widths, repeatRows=1)
cmds = [
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 8),
("ALIGN", (0,0), (-1,0), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 7.5),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
for i, _ in enumerate(rows, 1):
if i in hi_rows:
cmds.append(("BACKGROUND", (0,i), (-1,i), hi_color))
elif i % 2 == 0:
cmds.append(("BACKGROUND", (0,i), (-1,i), ROW_ALT))
tbl.setStyle(TableStyle(cmds))
return tbl
def mbox(text, bg=colors.HexColor("#E8F4FD"), border=TEAL):
tbl = Table([[M(text)]], colWidths=[7.4*inch])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 0.7, border),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return tbl
def wbox(text):
tbl = Table([[W(text)]], colWidths=[7.4*inch])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#FFF3CD")),
("BOX", (0,0), (-1,-1), 0.7, ORANGE),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return tbl
sp = lambda n=6: Spacer(1, n)
# ══════════════════════════════════════════════════════════════════════════════
# STORY
# ══════════════════════════════════════════════════════════════════════════════
story = []
# ── Title block ───────────────────────────────────────────────────────────
hdr = Table([
[Paragraph("NCLEX – Provision of a Safe Environment", title_style)],
[Paragraph("Safety & Infection Control · 12% of Exam | Safe & Effective Care Environment Client Need", sub_style)],
], colWidths=[7.4*inch])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 12),
]))
story += [hdr, sp(8)]
# NGN note
story += [
mbox("📌 NGN Update: Reference ranges are now provided with lab items. For safe-environment questions, "
"focus on identifying the RISK, selecting the PRIORITY nursing action, and knowing the correct "
"SEQUENCE (e.g. don before patient contact; doff gloves first).",
bg=colors.HexColor("#FFF9E6"), border=ORANGE),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# 1. STANDARD PRECAUTIONS
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("1. Standard Precautions — Apply to EVERY Patient, EVERY Time"),
sp(4),
dtable(
headers=["Element", "When to Use", "NCLEX Tips"],
col_widths=[1.4*inch, 2.2*inch, 3.8*inch],
rows=[
["Hand Hygiene", "Before & after ALL patient contact; after glove removal",
"Soap & water REQUIRED for C. diff and norovirus — alcohol gel does NOT kill spores"],
["Gloves", "Blood, body fluids, mucous membranes, non-intact skin",
"Change between tasks on same patient; remove before touching clean surfaces"],
["Gown", "Clothing/skin likely to be soiled",
"Single use; discard before leaving room"],
["Mask + Eye Protection","Splash or spray of body fluids possible",
"Face shield covers eyes + face; surgical mask + goggles are equivalent"],
["Safe Needle Handling", "After every injection/IV procedure",
"NO recapping; activate safety device immediately; sharps container at point of use"],
["Patient Equipment", "Between every patient use",
"Dedicate equipment (stethoscope, BP cuff) for isolation patients"],
["Respiratory Hygiene", "Symptomatic patients in waiting areas",
"'Cough etiquette': mask the coughing patient; tissues available"],
],
hi_rows=[1], hi_color=ROW_GREEN,
),
sp(4),
wbox("⚠ C. difficile & Norovirus: SOAP AND WATER only — alcohol-based hand rub is ineffective against spores."),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# 2. TRANSMISSION-BASED PRECAUTIONS
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("2. Transmission-Based Precautions"),
sp(4),
dtable(
headers=["Type", "PPE Required", "Room", "Key Diseases"],
col_widths=[1.1*inch, 1.8*inch, 1.2*inch, 3.3*inch],
rows=[
["CONTACT", "Gown + Gloves on room entry",
"Private or cohort", "MRSA, VRE, C. diff, scabies, RSV, wound infections, norovirus"],
["DROPLET", "Surgical mask within 3 ft",
"Private preferred", "Influenza, pertussis, meningococcal meningitis, rubella, mumps, Group A strep, Mycoplasma pneumoniae"],
["AIRBORNE", "N-95 respirator (fit-tested)",
"NEGATIVE PRESSURE; door closed", "TB, Measles (rubeola), Varicella (chickenpox), Disseminated herpes zoster"],
["CONTACT + AIRBORNE", "Gown + Gloves + N-95",
"Negative pressure", "Disseminated/open herpes zoster, SARS, smallpox"],
],
hi_rows=[3, 4], hi_color=ROW_RED,
),
sp(4),
mbox('🔑 Memory: "My Chicken Needs Airborne" = Measles · Chickenpox (varicella) · TB → all require N-95 + negative-pressure room'),
sp(4),
mbox("PPE Donning Order: Gown → Mask/Respirator → Goggles/Face Shield → Gloves\n"
"PPE Doffing Order: Gloves FIRST (most contaminated) → Goggles/Face Shield → Gown → Mask LAST"),
sp(4),
dtable(
headers=["Scenario", "Correct Precaution Type"],
col_widths=[3.7*inch, 3.7*inch],
rows=[
["Patient admitted with active pulmonary TB", "Airborne — N-95, negative-pressure room"],
["Post-op patient with MRSA wound", "Contact — gown + gloves"],
["Child with meningococcal meningitis", "Droplet — surgical mask"],
["Patient with chickenpox", "Airborne — N-95, negative-pressure room"],
["Patient with C. difficile diarrhea", "Contact + soap-and-water hand hygiene"],
["Patient with active influenza", "Droplet — surgical mask"],
["Shingles (disseminated)", "Airborne + Contact"],
],
hi_rows=[1, 4, 7],
),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# 3. SURGICAL ASEPSIS / STERILE TECHNIQUE
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("3. Surgical Asepsis — Sterile Technique"),
sp(4),
]
sterile_rules = [
["Rule", "Detail"],
["1-inch border", "Outer 1 inch of sterile field is CONTAMINATED — never place sterile items there"],
["Never reach across", "Reaching over a sterile field contaminates it; always work from the sides"],
["Below waist = contaminated", "Any item dropped below waist level is considered unsterile"],
["Sterile ↔ sterile only", "Only sterile items may touch sterile items; gloved hands touch sterile field only"],
["Doubt = contaminated", "If you question sterility of an item, discard it and start over — never assume"],
["Wet = contaminated", "Moisture wicks microorganisms through packaging (strike-through contamination)"],
["Back = unsterile", "Your back is never sterile — never turn your back on the sterile field"],
["Cough/sneeze", "Turn away from the field or discard and restart if coughing/sneezing near it"],
]
sr_tbl = Table(sterile_rules, colWidths=[2.0*inch, 5.4*inch])
sr_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
*[("BACKGROUND", (0,i), (-1,i), ROW_ALT) for i in range(2, 9, 2)],
]))
story += [sr_tbl, sp(4),
mbox("Required for: urinary catheterisation, IV insertion, central line care, wound care, surgical prep, "
"lumbar puncture, thoracentesis, amniocentesis"),
sp(10),
]
# PAGE BREAK
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# 4. FALL PREVENTION
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("4. Fall Prevention"),
sp(4),
dtable(
headers=["Intervention", "Details / NCLEX Tips"],
col_widths=[2.2*inch, 5.2*inch],
rows=[
["Fall Risk Assessment", "Morse Fall Scale or STRATIFY on admission, every shift, after a fall, after change in condition"],
["Environment", "Bed in LOWEST position; call light within reach; non-slip footwear; clear path to bathroom; adequate lighting"],
["Side Rails", "Raising all 4 = RESTRAINT (requires order); 2 rails up = positional support (generally allowed)"],
["Hourly Rounding", "Ask about the 4 Ps: Pain, Position, Potty, Personal items"],
["High-Risk Armband", "Yellow 'Fall Risk' band + door/bed signage — communicate to all staff"],
["Medications", "Opioids, sedatives, antihypertensives, diuretics, hypoglycemics increase fall risk — reassess after giving"],
["Post-Fall Protocol", "Assess patient first; call provider; complete incident report; document in chart objectively; no mention of incident report in chart"],
],
hi_rows=[3, 7],
),
sp(4),
mbox("Priority NCLEX: A confused patient trying to get out of bed → Re-orient, lower bed, place call light, increase surveillance. "
"Restraint is LAST resort — try alternatives first."),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# 5. RESTRAINTS
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("5. Use of Restraints / Safety Devices"),
sp(4),
dtable(
headers=["Requirement", "Detail"],
col_widths=[2.4*inch, 5.0*inch],
rows=[
["Try alternatives FIRST", "Reorientation, sitter/family presence, bed alarm, remove tubes if possible, mitt gloves"],
["Order required", "Written, time-limited physician order; must be renewed per facility policy (usually q24h)"],
["Assessment frequency", "Every 2 HOURS — circulation, sensation, skin integrity, ROM"],
["Release & reposition", "Every 2 hours — perform ROM, offer fluids/toileting, re-evaluate need"],
["Tie to", "BED FRAME (not side rail) — use quick-release knot; never tie in a knot that pulls tighter"],
["Documentation", "Type of restraint, rationale, alternatives tried, patient response, neurovascular checks"],
["Chemical restraints", "Sedation given for behaviour control carries same ethical/legal standards as physical restraint"],
["Least restrictive", "Use least restrictive device that meets patient safety need; wrist > vest > full body"],
],
hi_rows=[3, 5],
),
sp(4),
wbox("⚠ NEVER tie restraints to a side rail — side rails move and can injure the patient. "
"ALWAYS use a quick-release knot tied to the fixed bed frame."),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# 6. MEDICATION SAFETY — 8 RIGHTS
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("6. Medication Safety — The 8 Rights"),
sp(4),
dtable(
headers=["Right", "How to Apply"],
col_widths=[1.8*inch, 5.6*inch],
rows=[
["Right Patient", "2 identifiers: name + date of birth — NEVER room number; scan armband if available"],
["Right Drug", "Verify order; question unusual drugs or doses; know generic AND brand names"],
["Right Dose", "Calculate independently; double-check with second RN for high-alert meds"],
["Right Route", "Never substitute routes; oral ≠ sublingual ≠ IV; verify route before administration"],
["Right Time", "Within 30–60 min of scheduled time; STAT orders immediately"],
["Right Documentation", "Sign off AFTER giving — never chart medication before administering"],
["Right Reason", "Know the indication; question if unclear; patient education required"],
["Right to Refuse", "Patient has right to refuse; document, educate, and notify provider"],
],
hi_rows=[1, 6],
),
sp(4),
]
# high-alert meds
high_alert = Table(
[["HIGH-ALERT MEDICATIONS — Always Double-Check with 2nd RN"],
["Insulin | Heparin / Anticoagulants | IV Potassium (KCl) | Opioids / Narcotics | Chemotherapy | Concentrated Electrolytes | Neuromuscular Blocking Agents"]],
colWidths=[7.4*inch]
)
high_alert.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), RED_DARK),
("BACKGROUND", (0,1), (0,1), ROW_RED),
("TEXTCOLOR", (0,0), (0,0), WHITE),
("TEXTCOLOR", (0,1), (0,1), RED_DARK),
("FONTNAME", (0,0), (-1,-1), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("BOX", (0,0), (-1,-1), 0.8, RED_DARK),
]))
story += [high_alert, sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# 7. FIRE SAFETY
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("7. Fire Safety — RACE & PASS"),
sp(4),
]
fire_tbl = Table([
[
Table([
[Paragraph("RACE — Fire Response", ParagraphStyle("FH", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE, alignment=TA_CENTER))],
[dtable(
headers=["Letter", "Action"],
col_widths=[0.5*inch, 2.9*inch],
rows=[
["R", "RESCUE — move patients from immediate danger"],
["A", "ALARM — pull fire alarm; call facility number"],
["C", "CONTAIN — close all doors to confine smoke/fire"],
["E", "EXTINGUISH or EVACUATE (if safe to do so)"],
],
)],
], colWidths=[3.6*inch]),
Table([
[Paragraph("PASS — Fire Extinguisher", ParagraphStyle("FH2", fontSize=9, fontName="Helvetica-Bold", textColor=WHITE, alignment=TA_CENTER))],
[dtable(
headers=["Letter", "Action"],
col_widths=[0.5*inch, 2.9*inch],
rows=[
["P", "PULL the pin"],
["A", "AIM at the base of the fire"],
["S", "SQUEEZE the handle"],
["S", "SWEEP side to side"],
],
)],
], colWidths=[3.6*inch]),
]
], colWidths=[3.7*inch, 3.7*inch])
fire_tbl.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 4),
]))
story += [fire_tbl, sp(4),
mbox("RACE comes BEFORE PASS — rescue patients and activate alarm BEFORE attempting to extinguish fire. "
"Only use extinguisher if fire is small, contained, and you have an exit behind you."),
sp(10),
]
# PAGE BREAK
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# 8. DISASTER / MASS CASUALTY TRIAGE
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("8. Emergency Response — Disaster & Mass Casualty (START Triage)"),
sp(4),
dtable(
headers=["Tag Color", "Priority", "Condition", "Examples"],
col_widths=[1.0*inch, 1.0*inch, 2.0*inch, 3.4*inch],
rows=[
["RED", "Immediate", "Life-threatening but SALVAGEABLE", "Airway obstruction, uncontrolled bleeding, tension pneumothorax"],
["YELLOW", "Delayed", "Serious but currently STABLE", "Fractures without vascular compromise, burns < 20% BSA"],
["GREEN", "Minor", "'Walking wounded'", "Minor lacerations, sprains, psychological distress"],
["BLACK", "Expectant", "Dead OR unsurvivable injuries", "No pulse after airway repositioning, unsurvivable head trauma"],
],
hi_rows=[1, 4], hi_color=ROW_RED,
),
sp(4),
mbox("In a mass casualty event, the nurse DOES NOT leave assigned area to help others unless directed. "
"Follow incident command structure. The charge nurse/supervisor directs reassignment."),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# 9. ERGONOMICS & SAFE PATIENT HANDLING
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("9. Ergonomic Principles & Safe Patient Handling"),
sp(4),
dtable(
headers=["Principle", "Application"],
col_widths=[2.2*inch, 5.2*inch],
rows=[
["Body mechanics", "Wide base of support; bend at KNEES not waist; keep load close to body; pivot do not twist"],
["Mechanical lifts", "Use for dependent patients; weight limit per lift type; 2 nurses for lateral transfers"],
["Slide boards / sheets", "For lateral transfers in bed; reduce friction and shear forces on patient skin"],
["Transfer belts (gait)", "Always used for ambulation assistance; grasp belt, not clothing; stand on patient's weaker side"],
["Ask for help", "Safe lifting limit = 35 lbs; never lift alone above this; back injury is #1 occupational hazard in nursing"],
["Footwear", "Non-slip shoes for nurse; non-slip socks or shoes for patient"],
],
hi_rows=[5],
),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# 10. HAZARDOUS / INFECTIOUS MATERIALS
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("10. Handling Hazardous & Infectious Materials"),
sp(4),
dtable(
headers=["Material Type", "Container / Disposal", "Nurse Action"],
col_widths=[1.8*inch, 2.2*inch, 3.4*inch],
rows=[
["Sharps", "Puncture-resistant container at point of use", "Never recap; never overfill past fill line; activate safety device immediately"],
["Biohazard waste", "Red biohazard bags / labeled containers", "All blood/body fluid–saturated items; double-bag if leaking"],
["Chemotherapy waste","Yellow or purple labeled containers", "PPE: gown, gloves, eye protection; closed-system transfer; special spill kit"],
["Radioactive waste", "Lead-shielded containers; label clearly", "Time, distance, shielding principles; dosimeter badge required"],
["Needlestick", "Wash with soap & water immediately", "Report to supervisor; baseline labs; follow facility exposure protocol; do NOT squeeze wound"],
],
hi_rows=[5],
),
sp(4),
wbox("⚠ Needlestick Protocol: Wash → Report immediately → Baseline labs (HIV, HBV, HCV) → "
"Post-exposure prophylaxis (PEP) if HIV exposure — must start within 72 hours."),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# 11. INCIDENT REPORTING
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("11. Reporting Incidents / Variance Reports"),
sp(4),
dtable(
headers=["What to Do", "What NOT to Do"],
col_widths=[3.7*inch, 3.7*inch],
rows=[
["File an incident report for: falls, med errors, equipment failure, elopement, needlesticks",
"Do NOT document that an incident report was filed in the patient's chart"],
["Document objective facts in the chart: what happened, patient response, actions taken",
"Do NOT include opinions, judgments, or blame in documentation"],
["Report to charge nurse and provider immediately",
"Do NOT delay reporting to complete paperwork first"],
["Incident reports are for quality improvement and risk management",
"Incident reports are NOT part of the legal medical record — not discoverable in same way"],
],
),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# 12. HOME SAFETY
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("12. Home Safety"),
sp(4),
]
home_data = [
["Category", "Teaching Points"],
["Fall Prevention", "Remove throw rugs, loose cords, clutter; install grab bars in bathroom; handrails on stairs; adequate lighting (especially nightlights)"],
["Fire Safety", "Smoke detector on every floor; test monthly; change battery annually; carbon monoxide detector near sleeping areas; escape plan practiced"],
["Medication Safety", "Original labeled containers; child-resistant caps; store away from heat/moisture; safe disposal (take-back programs or coffee grounds/kitty litter + sealed bag before trashing)"],
["Poisoning", "Lock up cleaning products and medications; poison control number posted: 1-800-222-1222; never store chemicals in food containers"],
["Electrical Safety", "GFCI outlets near water; no overloaded outlets; repair frayed cords immediately; avoid extension cords as permanent solution"],
["Infant/Child Safety", "Car seat use; never leave in hot car; pool fencing; outlet covers; safety gates on stairs; crib safety (firm mattress, no soft bedding)"],
]
ht = Table(home_data, colWidths=[1.6*inch, 5.8*inch])
ht.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
*[("BACKGROUND", (0,i), (-1,i), ROW_ALT) for i in range(2, 7, 2)],
]))
story += [ht, sp(10)]
# PAGE BREAK
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# 13. SECURITY
# ══════════════════════════════════════════════════════════════════════════════
story += [
banner("13. Security Plan"),
sp(4),
dtable(
headers=["Scenario", "Nursing Action"],
col_widths=[2.5*inch, 4.9*inch],
rows=[
["Infant abduction", "Verify matching ID bands on mother and infant; never hand baby to unverified individual; activate abduction protocol immediately"],
["Patient elopement", "Locked/alarmed units for confused/dementia patients; document elopement risk; notify provider; search protocol"],
["Workplace violence", "De-escalate when safe; maintain exit access; call security; document; follow facility zero-tolerance policy"],
["Visitor management", "Verify identity before sharing ANY patient info; HIPAA applies to all; patient may restrict visitors"],
["Confidentiality", "Patient info shared only on need-to-know basis; even family members have no automatic right to info without patient consent"],
],
),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# 14. QUICK-MEMORISE CHEAT SHEET
# ══════════════════════════════════════════════════════════════════════════════
story += [banner("14. High-Yield Quick-Memorise Summary"), sp(6)]
cheat = [
["Airborne diseases", "TB · Measles · Varicella · Disseminated zoster",
"C. diff / Norovirus hand hygiene", "Soap & water ONLY (no alcohol gel)"],
["Donning PPE order", "Gown → Mask → Goggles → Gloves",
"Doffing PPE order", "Gloves FIRST → Goggles → Gown → Mask LAST"],
["Restraint checks", "Every 2 hours; release + ROM each time",
"Tie restraints to", "BED FRAME — quick-release knot"],
["2 patient identifiers", "Name + Date of Birth (NEVER room number)",
"Incident report in chart?","NEVER document that one was filed"],
["RACE", "Rescue → Alarm → Contain → Extinguish/Evacuate",
"PASS", "Pull → Aim → Squeeze → Sweep"],
["Triage: RED", "Immediate — life-threatening, salvageable",
"Triage: BLACK", "Expectant — dead or unsurvivable"],
["Needlestick first action", "Wash with soap & water immediately",
"HIV PEP window", "Must start within 72 hours of exposure"],
["Safe lift limit", "35 lbs maximum — use mechanical lift above this",
"Sterile field doubt", "Discard — NEVER assume sterility"],
]
cheat_tbl = Table(cheat, colWidths=[1.9*inch, 1.85*inch, 1.9*inch, 1.75*inch])
cheat_tbl.setStyle(TableStyle([
*[("BACKGROUND", (0,i), (0,i), NAVY if i%2==0 else TEAL) for i in range(len(cheat))],
*[("BACKGROUND", (2,i), (2,i), NAVY if i%2==0 else TEAL) for i in range(len(cheat))],
*[("BACKGROUND", (1,i), (1,i), ROW_ALT) for i in range(len(cheat))],
*[("BACKGROUND", (3,i), (3,i), ROW_ALT) for i in range(len(cheat))],
*[("TEXTCOLOR", (0,i), (0,i), WHITE) for i in range(len(cheat))],
*[("TEXTCOLOR", (2,i), (2,i), WHITE) for i in range(len(cheat))],
("FONTNAME", (0,0), (-1,-1), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("ALIGN", (0,0), (-1,-1), "LEFT"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("GRID", (0,0), (-1,-1), 0.4, WHITE),
]))
story += [cheat_tbl, sp(8)]
# ══════════════════════════════════════════════════════════════════════════════
# 15. NCLEX PRACTICE QUESTIONS
# ══════════════════════════════════════════════════════════════════════════════
story += [banner("15. NCLEX-Style Practice Questions", color=GREEN), sp(6)]
qs = [
("Q1. A nurse is preparing to enter the room of a patient placed on airborne precautions for active TB. "
"Which PPE should the nurse put on first?",
"A. Gloves\nB. Gown\nC. N-95 respirator\nD. Face shield",
"Answer: B — Gown is donned first in the correct sequence: Gown → Mask/Respirator → Goggles → Gloves."),
("Q2. A patient with C. difficile diarrhea requires contact precautions. After removing gloves, "
"what hand hygiene method should the nurse use?",
"A. Alcohol-based hand rub\nB. Soap and water for at least 20 seconds\nC. Either method is acceptable\nD. Hand sanitizer wipes",
"Answer: B — Soap and water is mandatory for C. difficile (and norovirus). Alcohol-based products do not kill C. diff spores."),
("Q3. A confused patient is attempting to climb out of bed at night. Which intervention should the nurse "
"implement FIRST?",
"A. Apply wrist restraints\nB. Request a bed alarm from the charge nurse\nC. Lower the bed, place call light within reach, and reorient the patient\nD. Request a sitter",
"Answer: C — Least restrictive alternatives (environment, reorientation) are attempted before bed alarms, sitters, or restraints."),
("Q4. The nurse administered the wrong dose of metoprolol to a patient. What is the FIRST action?",
"A. Complete an incident report\nB. Notify the charge nurse and physician\nC. Assess the patient\nD. Document the error in the chart",
"Answer: C — Patient safety is the priority; assess for adverse effects first, then notify provider, then document and complete incident report."),
("Q5. Which action by a nursing student indicates correct understanding of restraint use?",
"A. Checking restraints once per shift\nB. Tying restraints to the side rail for easy removal\nC. Using a quick-release knot tied to the bed frame\nD. Restraining patient without a physician order in an emergency",
"Answer: C — Restraints are always tied to the fixed bed frame using a quick-release knot. Side rails move and can harm patients."),
]
for i, (q, choices, ans) in enumerate(qs, 1):
q_block = Table([
[Paragraph(q, body_style)],
[Paragraph(choices.replace("\n", " "), tip_style)],
[Paragraph(ans, ParagraphStyle("Ans", fontSize=8, fontName="Helvetica-Bold",
textColor=GREEN, leftIndent=6))],
], colWidths=[7.4*inch])
q_block.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), colors.HexColor("#EBF4F7")),
("BACKGROUND", (0,1), (0,1), WHITE),
("BACKGROUND", (0,2), (0,2), colors.HexColor("#EAF7EC")),
("BOX", (0,0), (-1,-1), 0.6, TEAL),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
story += [q_block, sp(6)]
# ── Footer ────────────────────────────────────────────────────────────────
story += [
HRFlowable(width="100%", thickness=0.5, color=GREY_LINE),
sp(4),
Paragraph(
"Source: NCSBN NCLEX-RN Test Plan · Kaplan NCLEX Safe & Effective Care Environment · "
"Red Book 2021 (Committee on Infectious Diseases) · CDC Standard & Transmission-Based Precautions. "
"Values reflect general guidelines; always follow your facility's policies.",
footer_style
),
]
# ── Build ─────────────────────────────────────────────────────────────────
doc = make_doc()
doc.build(story)
print(f"PDF written to: {OUTPUT}")
python /home/daytona/workspace/nclex-safe-env/generate_safe_env.py 2>&1
ls -lh /home/daytona/workspace/nclex-safe-env/NCLEX_Safe_Environment.pdf
NCLEX Safe Environment
PDF Document · PDF
| Section | What's Covered |
|---|---|
| 1. Standard Precautions | Hand hygiene, gloves, gown, masks, sharps - with C. diff/norovirus soap-only warning |
| 2. Transmission-Based Precautions | Contact / Droplet / Airborne table with diseases, PPE, room types + donning/doffing order |
| 3. Surgical Asepsis | All 8 sterile field rules, when sterile technique is required |
| 4. Fall Prevention | Morse scale, hourly rounding 4 Ps, side rail rules, high-risk meds |
| 5. Restraints | Order requirements, 2-hour checks, bed frame rule, quick-release knot |
| 6. Medication Safety | All 8 Rights + highlighted high-alert medication list |
| 7. Fire Safety | RACE and PASS in side-by-side layout |
| 8. Disaster / Triage | START triage color codes with examples |
| 9. Ergonomics | 35 lb rule, mechanical lifts, gait belt technique |
| 10. Hazardous Materials | Sharps, biohazard, chemo, needlestick protocol with 72-hr PEP window |
| 11. Incident Reporting | Do/don't table - including never charting that a report was filed |
| 12. Home Safety | Falls, fire, meds, poison control, child safety |
| 13. Security | Infant abduction, elopement, HIPAA, workplace violence |
| 14. Quick Cheat Sheet | All key mnemonics and rules in a compact color-coded grid |
| 15. Practice Questions | 5 NCLEX-style questions with rationales |
Biological warfar and chemical warfar weapons nclex
NCLEX biological chemical warfare weapons bioterrorism nursing study guide
| Category | Risk Level | Examples |
|---|---|---|
| Category A | Highest priority - easy to disseminate, high mortality, major public health impact | Anthrax, Smallpox, Plague, Botulism, Tularemia, Viral hemorrhagic fevers (Ebola, Marburg) |
| Category B | Moderately easy to disseminate, lower mortality | Brucellosis, Q fever, Ricin toxin, Salmonella (food safety threats) |
| Category C | Emerging pathogens that could be engineered for mass dissemination | Nipah virus, hantavirus |
| Form | Route | Incubation | Key Signs/Symptoms |
|---|---|---|---|
| Cutaneous (95% of natural cases) | Skin contact with spores | < 1 week | Painless papule → ulcer with vesicles → black eschar (painless); edema, lymphadenopathy |
| Inhalation (bioweapon concern) | Respiratory | 2 days – 6 weeks (spores can persist in lungs) | Flu-like prodrome → rapid deterioration → widened mediastinum on CXR, hemorrhagic meningitis, septic shock |
| GI | Ingesting contaminated meat | < 1 week | Ulcers, bloody diarrhea, ascites |
| Feature | Details |
|---|---|
| Transmission | Airborne + Contact - highly contagious |
| Incubation | 7-19 days (average 12) |
| Prodrome | High fever, headache, backache, malaise 2-4 days BEFORE rash |
| Rash | All lesions are in the SAME stage (synchronous); centrifugal distribution (face, palms, soles first) |
| Lesions | Deep, firm, umbilicated pustules |
| Feature | Smallpox | Chickenpox (Varicella) |
|---|---|---|
| Lesion stages | All SAME stage | Multiple stages simultaneously |
| Distribution | Centrifugal (face, palms, soles) | Centripetal (trunk > extremities) |
| Lesion depth | Deep, firm, hard | Superficial, soft |
| Prodrome fever | 2-4 days BEFORE rash | Mild, appears WITH rash |
| Contagiousness | Extremely high | High |
| Form | Transmission | Symptoms | Precautions |
|---|---|---|---|
| Bubonic | Flea bite from infected rodent | Sudden fever, swollen tender bubo (lymph node, especially groin/axilla), septicemia | Standard precautions |
| Pneumonic | Person-to-person via respiratory droplets; most likely bioweapon form | Severe pneumonia, bloody frothy sputum, rapid progression | Droplet precautions |
| Septicemic | Blood-borne spread | DIC, acral necrosis ("Black Death"), shock | Standard precautions |
| Feature | Details |
|---|---|
| Key presentation | Descending flaccid paralysis (starts with cranial nerves: double vision, drooping eyelids, dysphagia → descends) |
| Classic "3 Ds" | Diplopia, Dysarthria, Dysphagia (then descending weakness) |
| Sensorium | Afebrile, alert, no sensory loss (differentiates from Guillain-Barré) |
| Respiratory | Respiratory failure from descending paralysis - PRIORITY nursing concern |
| Foodborne | Bulging cans, home-canned foods, honey in infants |
95% recover with proper supportive care even without antitoxin
| Form | Symptoms | Notes |
|---|---|---|
| Ulceroglandular | Ulcer at inoculation site + lymphadenopathy | Most common natural form |
| Pneumonic (bioweapon form) | Pneumonia, chest pain, cough | Highly infectious via inhalation |
| Typhoidal | Sepsis-like, no lymphadenopathy | Most severe form |
| Feature | Details |
|---|---|
| Transmission | Contact with blood/body fluids; some airborne potential in outbreak |
| Symptoms | High fever, hemorrhage (bleeding from mucous membranes, IV sites), organ failure |
| Precautions | Airborne + Contact + Eye protection (full PPE); negative-pressure room |
| Treatment | Supportive; fluid resuscitation; Zmapp/remdesivir for Ebola |
| Letter | Symptom |
|---|---|
| D | Defecation / Diarrhea |
| U | Urination |
| M | Miosis (pinpoint pupils) |
| B | Bradycardia / Bronchospasm / Bronchorrhea |
| E | Emesis |
| L | Lacrimation |
| S | Salivation / Seizures / Secretions |
| Drug | Mechanism | Target |
|---|---|---|
| Atropine | Muscarinic antagonist | Blocks DUMBELS symptoms; large doses may be needed (up to 20 mg IV); titrate to drying of secretions NOT to pupil size |
| Pralidoxime (2-PAM) | Reactivates acetylcholinesterase | Counters nicotinic/neuromuscular effects; must give BEFORE "aging" of enzyme occurs |
| Benzodiazepines | CNS | Treats seizures |
| Feature | Mustard Gas | Lewisite |
|---|---|---|
| Onset of symptoms | Delayed 2-24 hours after exposure | Immediate pain |
| Eyes | Severe conjunctivitis, corneal damage | Immediate eye pain |
| Skin | Delayed blisters, erythema | Immediate blistering |
| Respiratory | Airway damage, chemical burns | Airway damage |
| Antidote | None (supportive care) | BAL (British Anti-Lewisite / dimercaprol) |
| Feature | Details |
|---|---|
| Mechanism | Destroy alveolar-capillary membrane → pulmonary edema |
| Chlorine smell | "Pool/bleach" odor |
| Phosgene smell | "Freshly cut hay/grass" odor |
| Symptoms | Eye/respiratory irritation → cough → dyspnea → pulmonary edema (phosgene has delayed onset) |
| Treatment | Remove from exposure; fresh air; O2; bronchodilators; treat pulmonary edema |
| Feature | Details |
|---|---|
| Mechanism | Blocks cytochrome oxidase → cells cannot use oxygen → histotoxic hypoxia |
| Smell | Bitter almonds (classic but many people cannot detect) |
| Symptoms | Rapid onset: headache, dizziness, anxiety → seizures → cardiac arrest; cyanosis is ABSENT (venous blood remains oxygenated) |
| Antidote | Hydroxocobalamin (Cyanokit) - first line; OR sodium thiosulfate + sodium nitrite |
| Feature | Details |
|---|---|
| Mechanism | Irritants to mucous membranes |
| Symptoms | Tearing, burning eyes, rhinorrhea, cough (self-limiting) |
| Treatment | Fresh air, water irrigation to eyes/skin; supportive |
| Duration | Symptoms resolve within 30 min of removal from exposure |
| Agent | Key Sign | Precaution | Antidote / Treatment |
|---|---|---|---|
| Anthrax (inhalation) | Widened mediastinum; flu → collapse | Standard | Ciprofloxacin or doxycycline |
| Anthrax (cutaneous) | Painless black eschar | Standard | Ciprofloxacin |
| Smallpox | Synchronous umbilicated lesions; centrifugal | Airborne + Contact | Vaccinia vaccine within 4 days |
| Plague (pneumonic) | Bloody frothy sputum | Droplet | Streptomycin / doxycycline |
| Botulism | Descending flaccid paralysis, afebrile, alert | Standard | BAT antitoxin (stops progression only) |
| Tularemia | Ulcer + lymphadenopathy or pneumonia | Standard | Streptomycin |
| Nerve agents | DUMBELS + miosis | Decontaminate + standard | Atropine + Pralidoxime + Benzo |
| Mustard gas | Delayed blisters | Contact | None (supportive) |
| Lewisite | Immediate pain + blisters | Contact | BAL (dimercaprol) |
| Cyanide | Dyspnea, NO cyanosis, bitter almonds | Standard | Hydroxocobalamin |
| Chlorine/Phosgene | Pulmonary edema | Standard + decontaminate | O2, bronchodilators |
Create a colorful pdf of biological warfar and chemical warfar saprate
mkdir -p /home/daytona/workspace/nclex-warfare
~/nclex-warfare/bio_warfare.py
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph,
Spacer, HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
OUTPUT = "/home/daytona/workspace/nclex-warfare/NCLEX_Biological_Warfare.pdf"
# ── Palette ──────────────────────────────────────────────────────────────────
DARK_GREEN = colors.HexColor("#145A32")
MID_GREEN = colors.HexColor("#1E8449")
LIME = colors.HexColor("#27AE60")
OLIVE = colors.HexColor("#7D6608")
AMBER = colors.HexColor("#E67E22")
RED_DARK = colors.HexColor("#922B21")
RED_MED = colors.HexColor("#C0392B")
PURPLE = colors.HexColor("#6C3483")
TEAL = colors.HexColor("#117A65")
NAVY = colors.HexColor("#1A237E")
WHITE = colors.white
BLACK = colors.black
ROW_LG = colors.HexColor("#D5F5E3")
ROW_LA = colors.HexColor("#FEF9E7")
ROW_LR = colors.HexColor("#FADBD8")
ROW_LP = colors.HexColor("#E8DAEF")
ROW_LT = colors.HexColor("#D1F2EB")
ROW_ALT = colors.HexColor("#EBF5FB")
GREY_LINE = colors.HexColor("#BDC3C7")
GREY_TXT = colors.HexColor("#555555")
# ── Styles ────────────────────────────────────────────────────────────────────
def ps(name, size=8.5, color=BLACK, bold=False, italic=False, align=TA_LEFT,
leading=None, left=0):
fn = "Helvetica" + ("-BoldOblique" if bold and italic else
"-Bold" if bold else "-Oblique" if italic else "")
return ParagraphStyle(name, fontSize=size, fontName=fn,
textColor=color, alignment=align,
leading=leading or size*1.4, leftIndent=left)
title_s = ps("T", 22, WHITE, bold=True, align=TA_CENTER)
sub_s = ps("S", 10, WHITE, italic=True, align=TA_CENTER)
sec_s = ps("Se", 12, WHITE, bold=True, left=6)
body_s = ps("B", 8.5)
tip_s = ps("Ti", 8, NAVY, italic=True, left=8)
mnem_s = ps("M", 8.5, DARK_GREEN, bold=True, left=6)
warn_s = ps("W", 8.5, RED_DARK, bold=True, left=6)
foot_s = ps("F", 6.8, GREY_TXT, align=TA_CENTER)
agent_s = ps("A", 10, WHITE, bold=True, left=6)
cat_s = ps("C", 9, WHITE, bold=True, align=TA_CENTER)
def sp(n=6): return Spacer(1, n)
# ── Helpers ───────────────────────────────────────────────────────────────────
def banner(text, color=MID_GREEN, style=None):
st = style or sec_s
t = Table([[Paragraph(text, st)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def agent_header(text, color):
t = Table([[Paragraph(text, agent_s)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def dtable(headers, rows, col_widths, row_colors=None):
data = [headers] + rows
tbl = Table(data, colWidths=col_widths, repeatRows=1)
cmds = [
("BACKGROUND", (0,0), (-1,0), DARK_GREEN),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 8),
("ALIGN", (0,0), (-1,0), "CENTER"),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 7.5),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
if row_colors:
for i, c in enumerate(row_colors, 1):
if c:
cmds.append(("BACKGROUND", (0,i), (-1,i), c))
else:
for i in range(2, len(rows)+1, 2):
cmds.append(("BACKGROUND", (0,i), (-1,i), ROW_ALT))
tbl.setStyle(TableStyle(cmds))
return tbl
def mbox(text, bg=ROW_LG, border=MID_GREEN):
t = Table([[Paragraph(text, mnem_s)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 0.8, border),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def wbox(text):
t = Table([[Paragraph(text, warn_s)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), ROW_LR),
("BOX", (0,0), (-1,-1), 0.8, RED_MED),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def two_col(left_items, right_items, left_color, right_color):
"""Two coloured boxes side by side."""
def box(items, color):
rows = [[Paragraph(x, body_s)] for x in items]
t = Table(rows, colWidths=[3.55*inch])
cmds = [
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 8),
("BOX", (0,0), (-1,-1), 0.5, GREY_LINE),
]
for i in range(len(rows)):
if i % 2 == 1:
cmds.append(("BACKGROUND", (0,i), (0,i),
colors.HexColor(
hex(int(color.hexval(), 16) - 0x0A0A0A if color != WHITE else 0xEEEEEE)[2:].zfill(6)
) if False else color))
t.setStyle(TableStyle(cmds))
return t
outer = Table([[box(left_items, left_color), box(right_items, right_color)]],
colWidths=[3.6*inch, 3.6*inch])
outer.setStyle(TableStyle([
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 3),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return outer
# ══════════════════════════════════════════════════════════════════════════════
story = []
doc = SimpleDocTemplate(OUTPUT, pagesize=letter,
leftMargin=0.55*inch, rightMargin=0.55*inch,
topMargin=0.55*inch, bottomMargin=0.55*inch,
title="NCLEX – Biological Warfare Agents", author="Orris Study Aid")
# ── TITLE ─────────────────────────────────────────────────────────────────────
hdr = Table([
[Paragraph("☣ BIOLOGICAL WARFARE AGENTS", title_s)],
[Paragraph("NCLEX Study Guide · Category A, B & C Agents · Signs, Precautions & Antidotes", sub_s)],
], colWidths=[7.4*inch])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_GREEN),
("TOPPADDING", (0,0), (-1,-1), 14),
("BOTTOMPADDING", (0,0), (-1,-1), 14),
]))
story += [hdr, sp(8)]
# CDC Categories overview
story += [banner("CDC BIOTERRORISM AGENT CATEGORIES", DARK_GREEN), sp(4)]
cat_data = [
[Paragraph("CATEGORY A", cat_s), Paragraph("CATEGORY B", cat_s), Paragraph("CATEGORY C", cat_s)],
[Paragraph("Highest priority\nEasily disseminated\nHigh mortality\nMajor public health impact", body_s),
Paragraph("Moderately easy to spread\nLower mortality than A\nMay cause illness in large numbers", body_s),
Paragraph("Emerging agents\nCould be engineered\nfor mass dissemination", body_s)],
[Paragraph("Anthrax · Smallpox\nPlague · Botulism\nTularemia · VHF\n(Ebola, Marburg)", ps("ca", 8, RED_DARK, bold=True)),
Paragraph("Brucellosis · Q fever\nRicin toxin\nSalmonella (food safety)\nGlanders", ps("cb", 8, AMBER, bold=True)),
Paragraph("Nipah virus\nHantavirus\nYellow fever", ps("cc", 8, OLIVE, bold=True))],
]
cat_tbl = Table(cat_data, colWidths=[2.46*inch]*3)
cat_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), RED_DARK),
("BACKGROUND", (1,0), (1,0), AMBER),
("BACKGROUND", (2,0), (2,0), OLIVE),
("BACKGROUND", (0,1), (0,1), ROW_LR),
("BACKGROUND", (1,1), (1,1), ROW_LA),
("BACKGROUND", (2,1), (2,1), colors.HexColor("#F9F3E3")),
("BACKGROUND", (0,2), (0,2), colors.HexColor("#FDECEA")),
("BACKGROUND", (1,2), (1,2), colors.HexColor("#FEF5E7")),
("BACKGROUND", (2,2), (2,2), colors.HexColor("#FDFDE7")),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.5, WHITE),
("BOX", (0,0), (-1,-1), 1.0, DARK_GREEN),
]))
story += [cat_tbl, sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# ANTHRAX
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("1. ANTHRAX (Bacillus anthracis) — Category A", RED_DARK), sp(4)]
story += [dtable(
headers=["Form", "Route", "Incubation", "Key Signs & Symptoms"],
col_widths=[1.3*inch, 1.1*inch, 1.3*inch, 3.7*inch],
rows=[
["Cutaneous\n(95% natural)", "Skin contact\nwith spores", "< 1 week",
"Painless papule → vesicles → BLACK ESCHAR with edema; lymphadenopathy"],
["Inhalation\n★ BIOWEAPON", "Aerosolized\nspores", "2 days – 6 WEEKS\n(spores persist!)",
"Flu-like prodrome → rapid collapse → WIDENED MEDIASTINUM on CXR → haemorrhagic meningitis, septic shock"],
["GI", "Ingesting\ninfected meat", "< 1 week",
"Ulcers, bloody diarrhea, nausea, ascites, septicaemia"],
],
row_colors=[ROW_LA, ROW_LR, ROW_LG],
), sp(4)]
story += [
dtable(
headers=["Precautions", "Treatment / Prophylaxis", "Antidote?"],
col_widths=[1.5*inch, 3.8*inch, 2.1*inch],
rows=[["Standard\n(rare person-to-person)",
"Ciprofloxacin OR Doxycycline (60 days post-exposure prophylaxis)\nPenicillin for susceptible strains\nAnthrax vaccine (AVA) for high-risk/military",
"No antitoxin;\nantibiotics are key"]],
), sp(4),
mbox("🔑 NCLEX Keys: (1) BLACK PAINLESS ESCHAR = cutaneous anthrax\n"
"(2) WIDENED MEDIASTINUM on chest X-ray = inhalation anthrax until proven otherwise\n"
"(3) Inhalation incubation up to 6 WEEKS — patient may seem fine initially"),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# SMALLPOX
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("2. SMALLPOX (Variola virus) — Category A", PURPLE), sp(4)]
# Side-by-side comparison
comp_data = [
[Paragraph("SMALLPOX", ps("sh", 9, WHITE, bold=True, align=TA_CENTER)),
Paragraph("CHICKENPOX (Varicella)", ps("ch", 9, WHITE, bold=True, align=TA_CENTER))],
[Paragraph("All lesions SAME STAGE", body_s), Paragraph("Multiple stages simultaneously", body_s)],
[Paragraph("Centrifugal: face → palms/soles first", body_s), Paragraph("Centripetal: trunk > extremities", body_s)],
[Paragraph("Deep, firm, UMBILICATED pustules", body_s), Paragraph("Superficial, soft vesicles", body_s)],
[Paragraph("Prodrome fever 2–4 days BEFORE rash", body_s), Paragraph("Mild fever WITH rash", body_s)],
[Paragraph("Extremely contagious", body_s), Paragraph("Highly contagious", body_s)],
[Paragraph("AIRBORNE + CONTACT precautions", ps("sp", 8, RED_DARK, bold=True)), Paragraph("AIRBORNE precautions", body_s)],
]
comp_tbl = Table(comp_data, colWidths=[3.7*inch, 3.7*inch])
comp_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), PURPLE),
("BACKGROUND", (1,0), (1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (0,1), ROW_LP),
("BACKGROUND", (1,1), (1,1), ROW_LT),
("BACKGROUND", (0,2), (0,2), ROW_LP),
("BACKGROUND", (1,2), (1,2), ROW_LT),
("BACKGROUND", (0,3), (0,3), ROW_LP),
("BACKGROUND", (1,3), (1,3), ROW_LT),
("BACKGROUND", (0,4), (0,4), ROW_LP),
("BACKGROUND", (1,4), (1,4), ROW_LT),
("BACKGROUND", (0,5), (0,5), ROW_LP),
("BACKGROUND", (1,5), (1,5), ROW_LT),
("BACKGROUND", (0,6), (0,6), colors.HexColor("#FDECEA")),
("BACKGROUND", (1,6), (1,6), ROW_LT),
("FONTNAME", (0,0), (-1,-1), "Helvetica"),
("FONTSIZE", (0,0), (-1,-1), 8),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
("GRID", (0,0), (-1,-1), 0.5, GREY_LINE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story += [comp_tbl, sp(4),
mbox("🔑 NCLEX Keys: Smallpox = SAME STAGE lesions + centrifugal distribution\n"
"Vaccinia vaccine (ACAM2000) within 4 DAYS of exposure = prevention\n"
"Precautions: AIRBORNE + CONTACT (N-95 + negative pressure room + gown + gloves)",
bg=ROW_LP, border=PURPLE),
sp(10),
]
# PAGE BREAK
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# PLAGUE
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("3. PLAGUE (Yersinia pestis) — Category A", colors.HexColor("#5D4037")), sp(4)]
story += [dtable(
headers=["Form", "Transmission", "Key Symptoms", "Precautions"],
col_widths=[1.2*inch, 1.6*inch, 2.8*inch, 1.8*inch],
rows=[
["BUBONIC", "Flea bite from\ninfected rodent",
"Sudden high fever + painful swollen BUBO\n(lymph node, especially groin/axilla)\n→ bacteremia/septicaemia",
"STANDARD precautions"],
["PNEUMONIC ★\n(Bioweapon)", "Person-to-person\nRESPIRATORY DROPLETS",
"Severe pneumonia, bloody frothy sputum,\nrapid deterioration, high mortality if untreated",
"⚠ DROPLET\nprecautions"],
["SEPTICAEMIC", "Blood-borne spread\nfrom bubonic/pneumonic",
"DIC, acral necrosis (BLACK DEATH), septic shock,\npurpuric skin lesions",
"STANDARD precautions"],
],
row_colors=[ROW_LG, ROW_LR, ROW_LA],
), sp(4),
mbox("🔑 NCLEX Keys: ONLY PNEUMONIC plague requires DROPLET precautions\n"
"Painful BUBOES = bubonic plague (distinguish from painless anthrax eschar)\n"
"Treatment: Streptomycin (first-line) or Gentamicin; Doxycycline alternative\n"
"Post-exposure prophylaxis: Doxycycline or Ciprofloxacin × 7 days",
bg=colors.HexColor("#EFEBE9"), border=colors.HexColor("#5D4037")),
sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# BOTULISM
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("4. BOTULISM (Clostridium botulinum toxin) — Category A", NAVY), sp(4)]
story += [dtable(
headers=["Feature", "Details"],
col_widths=[2.0*inch, 5.4*inch],
rows=[
["Mechanism", "Toxin blocks ACh release at NMJ → DESCENDING flaccid paralysis (cranial nerves affected first)"],
["Classic '3 Ds'", "Diplopia · Dysarthria · Dysphagia → then descending paralysis → respiratory failure"],
["KEY: Patient is ALERT", "Afebrile, NO sensory loss, CONSCIOUS but 'locked in' — always warn caregivers, explain all procedures"],
["Respiratory", "PRIORITY: Monitor respiratory rate, O2 sat, vital capacity — intubate early if needed"],
["Forms", "Foodborne (bulging cans, home-canned) · Wound · Infant (HONEY contraindicated < 1 yr) · Inhalation (bioweapon)"],
["Precautions", "STANDARD (no person-to-person transmission)"],
],
row_colors=[ROW_LT, ROW_ALT, ROW_LR, ROW_LA, ROW_ALT, ROW_LG],
), sp(4),
dtable(
headers=["Treatment", "Action", "NCLEX Notes"],
col_widths=[2.2*inch, 2.8*inch, 2.4*inch],
rows=[
["Heptavalent BAT\n(equine antitoxin)", "STOPS PROGRESSION of paralysis;\ndoes NOT reverse existing paralysis",
"Must give EARLY; call state health dept for BAT from federal stockpile"],
["BabyBIG\n(infants)", "Human-derived botulism immune globulin\nfor infant botulism types A & B",
"Honey strictly contraindicated in infants < 12 months"],
["Mechanical ventilation", "For respiratory failure from\ndescending paralysis",
"Paralysis lasts weeks–months; intensive supportive care required"],
["Supportive care", ">95% recover with proper supportive care\neven without antitoxin",
"Signage: patient is CONSCIOUS — communicate with patient"],
],
row_colors=[ROW_LA, ROW_LP, ROW_LR, ROW_LG],
), sp(4),
wbox("⚠ ANTITOXIN STOPS PROGRESSION — it does NOT reverse paralysis already present. Give as early as possible."),
sp(4),
mbox("🔑 NCLEX Keys: Descending paralysis + afebrile + alert = BOTULISM\n"
"Baby + constipation + weak cry + poor feeding = INFANT BOTULISM\n"
"HONEY contraindicated in infants under 1 year"),
sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# TULAREMIA
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("5. TULAREMIA (Francisella tularensis) — Category A", TEAL), sp(4)]
story += [dtable(
headers=["Form", "Transmission", "Symptoms", "Precautions"],
col_widths=[1.5*inch, 1.7*inch, 2.7*inch, 1.5*inch],
rows=[
["Ulceroglandular\n(most common)", "Tick/deer fly bite;\nskin contact",
"Ulcer at inoculation site + regional lymphadenopathy", "Standard"],
["Pneumonic\n(bioweapon form)", "Aerosolized F. tularensis",
"Pneumonia, chest pain, cough, haemoptysis", "Standard\n(not person-to-person)"],
["Typhoidal", "Various", "Fever, sepsis-like illness, no bubo, very severe", "Standard"],
["Oculoglandular", "Conjunctival contact", "Conjunctivitis + preauricular lymphadenopathy", "Standard"],
],
row_colors=[ROW_LT, ROW_LA, ROW_LR, ROW_LG],
), sp(4),
mbox("Treatment: Streptomycin or Gentamicin (first-line) · Doxycycline or Ciprofloxacin (alternatives)\n"
"🔑 NCLEX: No person-to-person transmission → Standard precautions only",
bg=ROW_LT, border=TEAL),
sp(10)]
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# VIRAL HEMORRHAGIC FEVERS
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("6. VIRAL HEMORRHAGIC FEVERS (VHF) — Category A (Ebola, Marburg, Lassa)", RED_DARK), sp(4)]
story += [dtable(
headers=["Feature", "Details"],
col_widths=[1.8*inch, 5.6*inch],
rows=[
["Pathogens", "Filoviruses (Ebola, Marburg), Arenaviruses (Lassa fever), Bunyaviruses"],
["Transmission", "Direct contact with blood/body fluids; some droplet potential; NOT airborne in normal conditions"],
["Symptoms", "High fever, severe headache → bleeding from mucous membranes and IV sites, organ failure, DIC"],
["Incubation", "2–21 days (Ebola); 5–10 days (Marburg)"],
["Precautions", "AIRBORNE + CONTACT + EYE PROTECTION — full PPE; NEGATIVE-PRESSURE room; strict isolation"],
["Treatment", "Supportive: IV fluids, electrolytes, O2; Zmapp/Remdesivir for Ebola; no specific cure for most"],
["Waste management", "All waste treated as highly infectious; double-bag; autoclave; dedicated staff cohort"],
],
row_colors=[ROW_ALT, ROW_LR, ROW_LA, ROW_ALT, ROW_LR, ROW_LG, ROW_LA],
), sp(4),
wbox("⚠ FULL PPE mandatory: gown + gloves + N-95 + face shield/goggles. Dedicate staff. No visitors. "
"Report immediately to infection control and public health."),
sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# MASTER QUICK REFERENCE
# ══════════════════════════════════════════════════════════════════════════════
story += [banner("MASTER QUICK-REFERENCE — Biological Warfare Agents", DARK_GREEN), sp(4)]
story += [dtable(
headers=["Agent", "Category", "Key Presentation", "Precautions", "Treatment / Antidote"],
col_widths=[1.2*inch, 0.7*inch, 2.3*inch, 1.3*inch, 2.0*inch],
rows=[
["Anthrax\n(cutaneous)", "A", "Painless BLACK ESCHAR", "Standard", "Ciprofloxacin / Doxycycline"],
["Anthrax\n(inhalation)", "A", "Widened mediastinum, flu → collapse", "Standard", "Ciprofloxacin / Doxycycline"],
["Smallpox", "A", "Synchronous umbilicated lesions;\ncentrifugal rash",
"AIRBORNE +\nCONTACT", "Vaccinia vaccine\nwithin 4 days"],
["Plague\n(bubonic)", "A", "Painful BUBO + fever", "Standard", "Streptomycin / Doxycycline"],
["Plague\n(pneumonic)", "A", "Bloody frothy sputum, pneumonia", "DROPLET", "Streptomycin (dual Abx)"],
["Botulism", "A", "Descending flaccid paralysis; afebrile;\nalert/conscious",
"Standard", "BAT antitoxin\n(stops progression)"],
["Tularemia", "A", "Ulcer + lymphadenopathy OR pneumonia", "Standard", "Streptomycin / Gentamicin"],
["VHF (Ebola)", "A", "Fever + haemorrhage + organ failure", "AIRBORNE + CONTACT\n+ Eye protection",
"Supportive; Remdesivir"],
],
row_colors=[ROW_LA, ROW_LR, ROW_LP, ROW_LG, ROW_LR, colors.HexColor("#EBF5FB"),
ROW_LT, ROW_LR],
), sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# PRACTICE QUESTIONS
# ══════════════════════════════════════════════════════════════════════════════
story += [banner("NCLEX-STYLE PRACTICE QUESTIONS — Biological Warfare", MID_GREEN), sp(6)]
qs = [
("Q1. A patient presents with a painless black skin lesion on the forearm after handling animal hides. "
"Which condition does the nurse suspect, and what is the priority nursing action?",
"A. Plague — initiate droplet precautions\n"
"B. Cutaneous anthrax — initiate standard precautions and notify public health\n"
"C. Smallpox — initiate airborne and contact precautions\n"
"D. Tularemia — initiate contact precautions",
"✔ Answer: B — A painless black eschar after animal-hide exposure = cutaneous anthrax. "
"Standard precautions are sufficient (rare person-to-person transmission). Notify public health immediately."),
("Q2. A patient with suspected inhalation anthrax asks the nurse why antibiotics need to be taken for "
"60 days. What is the nurse's best response?",
"A. 'Anthrax bacteria are resistant and need a long course to kill.'\n"
"B. 'Anthrax spores can remain dormant in the lungs and germinate weeks later, so prolonged treatment prevents reactivation.'\n"
"C. 'The antibiotics prevent you from infecting others for 60 days.'\n"
"D. 'This is the standard course for all respiratory infections.'",
"✔ Answer: B — Inhalation anthrax has an incubation of up to 6 weeks due to spore dormancy. "
"60-day prophylaxis covers this window."),
("Q3. A nurse caring for a patient with botulism notes he is unable to move his limbs but his eyes "
"follow the nurse's movements. Which action is the PRIORITY?",
"A. Reassure the patient that botulism always resolves spontaneously\n"
"B. Assess respiratory rate, O2 saturation, and vital capacity frequently\n"
"C. Initiate contact precautions immediately\n"
"D. Administer atropine as ordered",
"✔ Answer: B — The patient is conscious (eyes following = alert) but paralysed. "
"Respiratory failure from descending paralysis is the life-threatening priority. "
"Atropine is NOT used for botulism (that is for nerve agents)."),
("Q4. During a mass casualty bioterrorism event, a patient is brought in with a rash where all lesions "
"appear identical in stage and are concentrated on the face, palms, and soles. "
"Which precautions does the nurse implement?",
"A. Standard precautions only\n"
"B. Droplet precautions\n"
"C. Airborne AND contact precautions; place in negative-pressure room\n"
"D. Contact precautions only",
"✔ Answer: C — Synchronous same-stage lesions with centrifugal distribution (face, palms, soles) = smallpox. "
"Requires both airborne (N-95, negative-pressure room) and contact (gown, gloves) precautions."),
]
for q, choices, ans in qs:
blk = Table([
[Paragraph(q, body_s)],
[Paragraph(choices.replace("\n", " "), ps("qc", 7.8, italic=True))],
[Paragraph(ans, ps("qa", 8, MID_GREEN, bold=True))],
], colWidths=[7.4*inch])
blk.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), colors.HexColor("#EBF5FB")),
("BACKGROUND", (0,1), (0,1), WHITE),
("BACKGROUND", (0,2), (0,2), ROW_LG),
("BOX", (0,0), (-1,-1), 0.7, MID_GREEN),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
story += [blk, sp(6)]
# FOOTER
story += [
HRFlowable(width="100%", thickness=0.5, color=GREY_LINE), sp(4),
Paragraph("Sources: Harrison's Principles of Internal Medicine 22E · Red Book 2021 · CDC Bioterrorism Agent List · "
"Goldman-Cecil Medicine · NCSBN NCLEX-RN Test Plan", foot_s),
]
doc.build(story)
print(f"Biological Warfare PDF: {OUTPUT}")
~/nclex-warfare/chem_warfare.py
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph,
Spacer, HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
OUTPUT = "/home/daytona/workspace/nclex-warfare/NCLEX_Chemical_Warfare.pdf"
# ── Palette ───────────────────────────────────────────────────────────────────
DARK_MAROON = colors.HexColor("#7B241C")
MED_RED = colors.HexColor("#C0392B")
BRIGHT_RED = colors.HexColor("#E74C3C")
ORANGE = colors.HexColor("#E67E22")
AMBER = colors.HexColor("#F39C12")
YELLOW_DK = colors.HexColor("#B7950B")
DARK_BLUE = colors.HexColor("#1A237E")
TEAL = colors.HexColor("#117A65")
PURPLE = colors.HexColor("#6C3483")
GREY_DK = colors.HexColor("#4A4A4A")
WHITE = colors.white
BLACK = colors.black
ROW_LR = colors.HexColor("#FADBD8")
ROW_LO = colors.HexColor("#FDEBD0")
ROW_LY = colors.HexColor("#FEF9E7")
ROW_LB = colors.HexColor("#D6EAF8")
ROW_LT = colors.HexColor("#D1F2EB")
ROW_LP = colors.HexColor("#E8DAEF")
ROW_ALT = colors.HexColor("#F2F3F4")
GREY_LINE = colors.HexColor("#BDC3C7")
GREY_TXT = colors.HexColor("#555555")
def ps(name, size=8.5, color=BLACK, bold=False, italic=False, align=TA_LEFT, leading=None, left=0):
fn = "Helvetica" + ("-BoldOblique" if bold and italic else
"-Bold" if bold else "-Oblique" if italic else "")
return ParagraphStyle(name, fontSize=size, fontName=fn,
textColor=color, alignment=align,
leading=leading or size*1.4, leftIndent=left)
title_s = ps("T", 22, WHITE, bold=True, align=TA_CENTER)
sub_s = ps("S", 10, WHITE, italic=True, align=TA_CENTER)
sec_s = ps("Se",12, WHITE, bold=True, left=6)
body_s = ps("B", 8.5)
tip_s = ps("Ti", 8, DARK_BLUE, italic=True, left=8)
mnem_s = ps("M", 8.5, DARK_MAROON, bold=True, left=6)
warn_s = ps("W", 8.5, MED_RED, bold=True, left=6)
foot_s = ps("F", 6.8, GREY_TXT, align=TA_CENTER)
agent_s = ps("A", 10, WHITE, bold=True, left=6)
def sp(n=6): return Spacer(1, n)
def banner(text, color=DARK_MAROON):
t = Table([[Paragraph(text, sec_s)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def agent_header(text, color):
t = Table([[Paragraph(text, agent_s)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def dtable(headers, rows, col_widths, row_colors=None):
data = [headers] + rows
tbl = Table(data, colWidths=col_widths, repeatRows=1)
cmds = [
("BACKGROUND", (0,0), (-1,0), DARK_MAROON),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 8),
("ALIGN", (0,0), (-1,0), "CENTER"),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 7.5),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
if row_colors:
for i, c in enumerate(row_colors, 1):
if c:
cmds.append(("BACKGROUND", (0,i), (-1,i), c))
else:
for i in range(2, len(rows)+1, 2):
cmds.append(("BACKGROUND", (0,i), (-1,i), ROW_ALT))
tbl.setStyle(TableStyle(cmds))
return tbl
def mbox(text, bg=ROW_LO, border=ORANGE):
t = Table([[Paragraph(text, mnem_s)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 0.8, border),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def wbox(text):
t = Table([[Paragraph(text, warn_s)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), ROW_LR),
("BOX", (0,0), (-1,-1), 0.8, MED_RED),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
# ══════════════════════════════════════════════════════════════════════════════
story = []
doc = SimpleDocTemplate(OUTPUT, pagesize=letter,
leftMargin=0.55*inch, rightMargin=0.55*inch,
topMargin=0.55*inch, bottomMargin=0.55*inch,
title="NCLEX – Chemical Warfare Agents", author="Orris Study Aid")
# ── TITLE ─────────────────────────────────────────────────────────────────────
hdr = Table([
[Paragraph("⚗ CHEMICAL WARFARE AGENTS", title_s)],
[Paragraph("NCLEX Study Guide · Nerve Agents · Vesicants · Pulmonary · Blood Agents · Antidotes & Decontamination", sub_s)],
], colWidths=[7.4*inch])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), DARK_MAROON),
("TOPPADDING", (0,0), (-1,-1), 14),
("BOTTOMPADDING", (0,0), (-1,-1), 14),
]))
story += [hdr, sp(8)]
# Overview categories
story += [banner("CHEMICAL WARFARE AGENT CLASSES", DARK_MAROON), sp(4)]
cat_data = [
[Paragraph("NERVE AGENTS", ps("n", 9, WHITE, bold=True, align=TA_CENTER)),
Paragraph("VESICANTS\n(Blister Agents)", ps("v", 9, WHITE, bold=True, align=TA_CENTER)),
Paragraph("PULMONARY\n(Choking Agents)", ps("p", 9, WHITE, bold=True, align=TA_CENTER)),
Paragraph("BLOOD AGENTS\n(Cyanide)", ps("b2", 9, WHITE, bold=True, align=TA_CENTER))],
[Paragraph("Sarin (GB)\nVX · Soman (GD)\nTabun (GA)", ps("nd", 8, MED_RED, bold=True, align=TA_CENTER)),
Paragraph("Mustard Gas (HD)\nLewisite (L)\nPhosgene Oxime", ps("vd", 8, ORANGE, bold=True, align=TA_CENTER)),
Paragraph("Chlorine (Cl₂)\nPhosgene (CG)\nDiphosgene", ps("pd", 8, YELLOW_DK, bold=True, align=TA_CENTER)),
Paragraph("Hydrogen Cyanide\nCyanogen Chloride\n(AC / CK)", ps("bd", 8, PURPLE, bold=True, align=TA_CENTER))],
[Paragraph("Inhibit acetylcholinesterase\n→ cholinergic crisis (DUMBELS)", body_s),
Paragraph("Alkylate DNA\n→ tissue necrosis,\nblistering", body_s),
Paragraph("Destroy alveolar membrane\n→ pulmonary oedema", body_s),
Paragraph("Block cytochrome oxidase\n→ histotoxic hypoxia", body_s)],
]
cat_tbl = Table(cat_data, colWidths=[1.85*inch]*4)
cat_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), MED_RED),
("BACKGROUND", (1,0), (1,0), ORANGE),
("BACKGROUND", (2,0), (2,0), YELLOW_DK),
("BACKGROUND", (3,0), (3,0), PURPLE),
("BACKGROUND", (0,1), (0,1), ROW_LR),
("BACKGROUND", (1,1), (1,1), ROW_LO),
("BACKGROUND", (2,1), (2,1), ROW_LY),
("BACKGROUND", (3,1), (3,1), ROW_LP),
("BACKGROUND", (0,2), (0,2), ROW_ALT),
("BACKGROUND", (1,2), (1,2), ROW_ALT),
("BACKGROUND", (2,2), (2,2), ROW_ALT),
("BACKGROUND", (3,2), (3,2), ROW_ALT),
("FONTNAME", (0,0), (-1,-1), "Helvetica"),
("FONTSIZE", (0,0), (-1,-1), 8),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 4),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("GRID", (0,0), (-1,-1), 0.5, WHITE),
("BOX", (0,0), (-1,-1), 1.0, DARK_MAROON),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story += [cat_tbl, sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# 1. NERVE AGENTS
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("1. NERVE AGENTS — Sarin (GB), VX, Soman, Tabun", MED_RED), sp(4)]
story += [dtable(
headers=["Receptor Site", "Effect of ACh Excess", "Signs/Symptoms"],
col_widths=[1.8*inch, 2.0*inch, 3.6*inch],
rows=[
["MUSCARINIC\n(Parasympathetic)", "Glandular overstimulation\n& smooth muscle contraction",
"DUMBELS: Defecation, Urination, Miosis (PINPOINT PUPILS),\nBradycardia/Bronchospasm/Bronchorrhoea, Emesis, Lacrimation, Salivation"],
["NICOTINIC\n(NMJ)", "Neuromuscular\noverstimulation → failure",
"Muscle fasciculations → weakness → PARALYSIS → RESPIRATORY FAILURE"],
["CNS", "Excessive cholinergic\nstimulation in brain",
"Anxiety → seizures → coma → death"],
],
row_colors=[ROW_LO, ROW_LR, ROW_LP],
), sp(4)]
# DUMBELS big box
dumbels_data = [
[Paragraph("D U M B E L S — Nerve Agent Mnemonic", ps("dh", 11, WHITE, bold=True, align=TA_CENTER))],
[Table([
[Paragraph("D", ps("dl", 18, BRIGHT_RED, bold=True, align=TA_CENTER)),
Paragraph("U", ps("dl", 18, ORANGE, bold=True, align=TA_CENTER)),
Paragraph("M", ps("dl", 18, AMBER, bold=True, align=TA_CENTER)),
Paragraph("B", ps("dl", 18, MED_RED, bold=True, align=TA_CENTER)),
Paragraph("E", ps("dl", 18, PURPLE, bold=True, align=TA_CENTER)),
Paragraph("L", ps("dl", 18, TEAL, bold=True, align=TA_CENTER)),
Paragraph("S", ps("dl", 18, DARK_BLUE, bold=True, align=TA_CENTER))],
[Paragraph("Defecation\n/ Diarrhea", ps("dt", 7, align=TA_CENTER)),
Paragraph("Urination", ps("dt", 7, align=TA_CENTER)),
Paragraph("Miosis\n(pinpoint pupils)", ps("dt", 7, align=TA_CENTER)),
Paragraph("Bradycardia\nBronchospasm\nBronchorrhoea", ps("dt", 7, align=TA_CENTER)),
Paragraph("Emesis", ps("dt", 7, align=TA_CENTER)),
Paragraph("Lacrimation\n(tearing)", ps("dt", 7, align=TA_CENTER)),
Paragraph("Salivation\nSweating\nSeizures", ps("dt", 7, align=TA_CENTER))],
], colWidths=[1.0*inch]*7)],
]
dumbels_tbl = Table(dumbels_data, colWidths=[7.4*inch])
dumbels_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), DARK_MAROON),
("BACKGROUND", (0,1), (0,1), colors.HexColor("#FDF2F8")),
("BOX", (0,0), (-1,-1), 1.0, DARK_MAROON),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
]))
story += [dumbels_tbl, sp(6)]
# Also SLUDGE
story += [mbox("Also remembered as SLUDGE: Salivation · Lacrimation · Urination · Defecation · "
"GI distress · Emesis\nPlus: PINPOINT PUPILS (miosis) + Bronchospasm/Bronchorrhoea + Bradycardia",
bg=ROW_LO, border=ORANGE), sp(6)]
# Treatment table
story += [banner("NERVE AGENT TREATMENT — THREE DRUGS", MED_RED), sp(4)]
tx_data = [
[Paragraph("DRUG", ps("th", 9, WHITE, bold=True, align=TA_CENTER)),
Paragraph("MECHANISM", ps("th", 9, WHITE, bold=True, align=TA_CENTER)),
Paragraph("TREATS", ps("th", 9, WHITE, bold=True, align=TA_CENTER)),
Paragraph("NCLEX TIPS", ps("th", 9, WHITE, bold=True, align=TA_CENTER))],
[Paragraph("ATROPINE\n(first-line)", ps("td", 9, MED_RED, bold=True)),
Paragraph("Muscarinic receptor antagonist\n(blocks parasympathetic excess)", body_s),
Paragraph("DUMBELS symptoms:\ndrying secretions, bronchospasm,\nbradycardia", body_s),
Paragraph("Titrate to DRYING OF SECRETIONS — NOT pupil size or heart rate!\nLarge doses may be needed (up to 20 mg IV)\nAuto-injector (DuoDote) available", body_s)],
[Paragraph("PRALIDOXIME\n(2-PAM)", ps("td2", 9, ORANGE, bold=True)),
Paragraph("Reactivates acetylcholinesterase\nat NMJ (reverses enzyme inhibition)", body_s),
Paragraph("Nicotinic effects:\nmuscle fasciculations,\nweakness, paralysis", body_s),
Paragraph("Must give EARLY — loses effectiveness after\n'AGING' of enzyme (irreversible bond forms)\nGive with atropine", body_s)],
[Paragraph("BENZODIAZEPINES\n(e.g., Diazepam)", ps("td3", 9, PURPLE, bold=True)),
Paragraph("GABA-A agonist;\nreduces CNS excitability", body_s),
Paragraph("CNS effects:\nseizures, agitation", body_s),
Paragraph("Diazepam auto-injector also available\nfor mass casualty scenarios", body_s)],
]
tx_tbl = Table(tx_data, colWidths=[1.4*inch, 2.0*inch, 1.8*inch, 2.2*inch])
tx_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_MAROON),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("BACKGROUND", (0,1), (-1,1), ROW_LR),
("BACKGROUND", (0,2), (-1,2), ROW_LO),
("BACKGROUND", (0,3), (-1,3), ROW_LP),
("FONTNAME", (0,0), (-1,-1), "Helvetica"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("GRID", (0,0), (-1,-1), 0.5, GREY_LINE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story += [tx_tbl, sp(4)]
story += [
wbox("⚠ DECONTAMINATION before hospital entry: Remove ALL clothing (eliminates ~80% of contamination). "
"Flush skin with copious water. Protect healthcare workers — do NOT allow contaminated patients to enter facility."),
sp(4),
mbox("🔑 NCLEX Keys for Nerve Agents:\n"
" (1) PINPOINT PUPILS + DUMBELS = nerve agent / organophosphate poisoning\n"
" (2) Atropine titrated to DRYING OF SECRETIONS — not pupil size or heart rate\n"
" (3) Pralidoxime must be given EARLY before enzyme 'aging' makes it ineffective\n"
" (4) Decontaminate OUTSIDE hospital before patient enters"),
sp(10),
]
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# 2. VESICANTS
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("2. VESICANTS / BLISTER AGENTS — Mustard Gas (HD), Lewisite", ORANGE), sp(4)]
story += [dtable(
headers=["Agent", "Onset", "Smell", "Eyes", "Skin", "Respiratory", "Antidote"],
col_widths=[0.8*inch, 1.0*inch, 0.9*inch, 1.2*inch, 1.3*inch, 1.2*inch, 1.0*inch],
rows=[
["MUSTARD\nGAS (HD)", "DELAYED\n2–24 hours\n(key!)", "Garlic / mustard",
"Delayed burning, conjunctivitis, corneal damage; photophobia",
"Delayed erythema → blisters → necrosis; 2nd/3rd degree-like burns",
"Airway damage, pseudo-membrane formation; pulmonary oedema",
"NONE\n(supportive care only)"],
["LEWISITE (L)", "IMMEDIATE\npain on contact", "Geraniums",
"Immediate severe pain, tearing, blepharospasm",
"Immediate blister formation; severe pain",
"Immediate airway pain and damage",
"BAL\n(dimercaprol)\n= antidote"],
],
row_colors=[ROW_LO, ROW_LR],
), sp(4),
wbox("⚠ MUSTARD GAS: Asymptomatic period after exposure → patient FEELS FINE initially → "
"then dramatic deterioration 2–24 hours later. Do NOT be reassured by absence of symptoms at scene."),
sp(4),
dtable(
headers=["Treatment Principle", "Details"],
col_widths=[2.2*inch, 5.2*inch],
rows=[
["Decontamination", "Remove clothing; flush with large amounts of water; soap and water for skin"],
["Eye irrigation", "Copious normal saline irrigation; do not patch eye if corneal involvement"],
["Wound/blister care", "Treat blisters like partial-thickness burns; do NOT rupture large blisters"],
["Respiratory support", "Bronchodilators, O2, mechanical ventilation if needed; airway management is priority"],
["BAL/dimercaprol", "Lewisite antidote only; given IM; also useful for arsenic/mercury/gold poisoning"],
["Precautions", "Contact precautions; full decontamination; PPE gown + gloves + eye protection"],
],
row_colors=[ROW_LO, ROW_ALT, ROW_LO, ROW_ALT, ROW_LR, ROW_LT],
), sp(4),
mbox("🔑 NCLEX Keys for Vesicants:\n"
" (1) Mustard gas = DELAYED onset (2–24 hours) — no immediate symptoms\n"
" (2) Lewisite = IMMEDIATE severe pain on contact\n"
" (3) Lewisite antidote = BAL (British Anti-Lewisite / dimercaprol)\n"
" (4) Mustard gas = NO antidote (supportive care only)\n"
" (5) Garlic smell = mustard gas; Geranium smell = lewisite",
bg=ROW_LO, border=ORANGE),
sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# 3. PULMONARY AGENTS
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("3. PULMONARY / CHOKING AGENTS — Chlorine, Phosgene", YELLOW_DK), sp(4)]
story += [dtable(
headers=["Agent", "Odour", "Onset", "Mechanism", "Symptoms", "Treatment"],
col_widths=[0.9*inch, 1.2*inch, 1.0*inch, 1.5*inch, 1.5*inch, 1.3*inch],
rows=[
["CHLORINE\n(Cl₂)", "Pool/bleach\n(greenish-yellow gas)",
"Rapid", "Hydrolyses to HCl + hypochlorous acid → airway/lung damage",
"Burning eyes & throat → cough → wheezing → dyspnoea → pulmonary oedema",
"Fresh air; O2; bronchodilators; treat pulmonary oedema; no antidote"],
["PHOSGENE\n(CG)", "Freshly cut hay\nor newly mown grass",
"DELAYED\n(4–24 hours)", "Carbonylates proteins in lung → destroys alveolar-capillary membrane → massive pulmonary oedema",
"Initial mild irritation → latent 'well' period → delayed pulmonary oedema & respiratory failure",
"Fresh air; O2; mechanical ventilation; corticosteroids; no antidote"],
],
row_colors=[ROW_LY, ROW_LO],
), sp(4),
wbox("⚠ PHOSGENE: Patient may appear well after initial brief irritation — then develops DELAYED "
"massive pulmonary oedema 4–24 hours later. Do NOT discharge or reassure early."),
sp(4),
mbox("🔑 NCLEX Keys for Pulmonary Agents:\n"
" (1) 'Pool/bleach' smell = CHLORINE\n"
" (2) 'Freshly cut hay/mown grass' smell = PHOSGENE (more dangerous)\n"
" (3) Phosgene = DELAYED pulmonary oedema — latent 'well' period is deceptive\n"
" (4) Chlorine = rapid onset of respiratory symptoms\n"
" (5) Both: Fresh air + high-flow O2 + respiratory support; NO specific antidote",
bg=ROW_LY, border=YELLOW_DK),
sp(10)]
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# 4. BLOOD AGENTS / CYANIDE
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("4. BLOOD AGENTS — Hydrogen Cyanide (AC), Cyanogen Chloride (CK)", PURPLE), sp(4)]
story += [dtable(
headers=["Feature", "Details"],
col_widths=[1.8*inch, 5.6*inch],
rows=[
["Mechanism", "Binds cytochrome oxidase (complex IV) → blocks aerobic respiration → "
"cells CANNOT use oxygen despite adequate delivery = HISTOTOXIC HYPOXIA"],
["Classic odour", "Bitter almonds (many people genetically unable to detect this smell — do not rely on it)"],
["KEY presentation", "Severe respiratory distress + rapid cardiovascular collapse — BUT NO CYANOSIS\n"
"(venous blood stays bright red because cells cannot extract O2)"],
["Symptoms onset", "Rapid: headache, dizziness, anxiety, confusion, tachycardia → seizures → cardiac arrest"],
["Smoke fires risk", "Burning synthetic materials (plastics, nylon, wool) release HCN → fire victims may have cyanide toxicity"],
["Precautions", "Standard precautions; decontaminate if liquid exposure; vapour dissipates quickly outdoors"],
],
row_colors=[ROW_LR, ROW_LA, ROW_LP, ROW_LO, ROW_ALT, ROW_LT],
), sp(4)]
# Antidote table
story += [banner("CYANIDE ANTIDOTE REGIMEN", PURPLE), sp(4)]
antidote_data = [
[Paragraph("ANTIDOTE", ps("ah", 9, WHITE, bold=True, align=TA_CENTER)),
Paragraph("MECHANISM", ps("ah", 9, WHITE, bold=True, align=TA_CENTER)),
Paragraph("NCLEX NOTES", ps("ah", 9, WHITE, bold=True, align=TA_CENTER))],
[Paragraph("Hydroxocobalamin\n(Cyanokit)\n★ PREFERRED", ps("ap", 9, PURPLE, bold=True)),
Paragraph("Binds cyanide directly forming cyanocobalamin (Vit B12); renal excretion", body_s),
Paragraph("Turns urine/skin RED-ORANGE (warn patient/family)\nSafe in smoke inhalation (no methHb risk)\nFirst-line in prehospital and ED settings", body_s)],
[Paragraph("Sodium Thiosulfate\n+\nSodium Nitrite", ps("as", 9, DARK_BLUE, bold=True)),
Paragraph("Sodium nitrite → forms methHb which binds cyanide\nSodium thiosulfate → converts thiocyanate for renal excretion", body_s),
Paragraph("Sodium nitrite causes methHb — AVOID in fire victims with CO poisoning\n(worsens O2 carrying capacity)\nHistorical regimen; now second-line", body_s)],
[Paragraph("100% Oxygen\n(supportive)", ps("ao", 9, TEAL, bold=True)),
Paragraph("Displaces CO (if present); supports cellular respiration", body_s),
Paragraph("Always give high-flow O2 to all suspected cyanide/CO victims", body_s)],
]
ad_tbl = Table(antidote_data, colWidths=[1.6*inch, 2.8*inch, 3.0*inch])
ad_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), PURPLE),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("BACKGROUND", (0,1), (-1,1), ROW_LP),
("BACKGROUND", (0,2), (-1,2), ROW_LB),
("BACKGROUND", (0,3), (-1,3), ROW_LT),
("FONTNAME", (0,0), (-1,-1), "Helvetica"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("GRID", (0,0), (-1,-1), 0.5, GREY_LINE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story += [ad_tbl, sp(4),
wbox("⚠ CYANIDE TRAP: Patient has SEVERE RESPIRATORY DISTRESS but NO CYANOSIS "
"(skin/lips may appear PINK/RED — venous blood is oxygenated but cells can't use it). "
"Hydroxocobalamin turns urine orange-red — document this and educate family."),
sp(4),
mbox("🔑 NCLEX Keys for Blood Agents:\n"
" (1) Dyspnoea + tachycardia + seizures + NO CYANOSIS = cyanide poisoning\n"
" (2) 'Bitter almonds' smell (not always detectable)\n"
" (3) Preferred antidote = HYDROXOCOBALAMIN (Cyanokit) → red-orange urine\n"
" (4) Fire/smoke victims → think cyanide + carbon monoxide together\n"
" (5) Avoid sodium nitrite in fire victims with suspected CO poisoning",
bg=ROW_LP, border=PURPLE),
sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# 5. DECONTAMINATION & PRIORITY NURSING ACTIONS
# ══════════════════════════════════════════════════════════════════════════════
story += [agent_header("5. DECONTAMINATION & PRIORITY NURSING ACTIONS", DARK_BLUE), sp(4)]
story += [dtable(
headers=["Step", "Action", "Rationale"],
col_widths=[0.5*inch, 3.2*inch, 3.7*inch],
rows=[
["1", "NURSE SAFETY FIRST — do NOT enter hot zone without appropriate PPE",
"Healthcare worker protection prevents secondary casualties"],
["2", "DECONTAMINATE outside facility — remove ALL clothing, flush with water",
"Clothing removal eliminates ~80% of contamination; prevents hospital contamination"],
["3", "Activate emergency response plan / incident command system",
"Coordinates resources, isolates patients, protects facility and staff"],
["4", "Notify charge nurse, administration, public health, CDC/local health dept",
"Legal reporting requirement; mobilises public health response"],
["5", "Triage using START system (Red/Yellow/Green/Black)",
"Efficiently allocates limited resources in mass casualty events"],
["6", "Identify agent based on signs/symptoms + smell + circumstance",
"Allows targeted antidote selection — wrong antidote can be fatal"],
["7", "Administer antidotes per protocol (atropine, pralidoxime, hydroxocobalamin, BAL)",
"Early antidote administration dramatically improves outcomes"],
["8", "Document all exposures; report to poison control (1-800-222-1222) & state health dept",
"Epidemiological tracking; medicolegal requirements"],
],
row_colors=[ROW_LR, ROW_LO, ROW_LY, ROW_ALT, ROW_LR, ROW_LO, ROW_LY, ROW_LT],
), sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# MASTER QUICK REFERENCE
# ══════════════════════════════════════════════════════════════════════════════
story += [banner("MASTER QUICK-REFERENCE — Chemical Warfare Agents", DARK_MAROON), sp(4)]
story += [dtable(
headers=["Agent", "Class", "Key Presentation", "Smell", "Antidote / Treatment"],
col_widths=[1.1*inch, 1.0*inch, 2.3*inch, 1.2*inch, 2.8*inch],
rows=[
["Sarin / VX", "Nerve", "DUMBELS + pinpoint pupils + paralysis",
"None / fruity", "Atropine + Pralidoxime (2-PAM) + Benzos"],
["Mustard Gas", "Vesicant", "DELAYED blisters (2–24 hrs); no pain initially",
"Garlic", "NONE — supportive care, wound care"],
["Lewisite", "Vesicant", "IMMEDIATE severe pain + blisters",
"Geraniums", "BAL (dimercaprol)"],
["Chlorine", "Pulmonary", "Rapid respiratory irritation; cough, wheeze",
"Pool/bleach", "O2, bronchodilators, no antidote"],
["Phosgene", "Pulmonary", "DELAYED pulmonary oedema (4–24 hrs); well initially",
"Fresh-cut hay", "O2, mechanical ventilation, no antidote"],
["Hydrogen Cyanide", "Blood", "Dyspnoea + seizures + NO CYANOSIS",
"Bitter almonds","Hydroxocobalamin (Cyanokit) — first-line"],
],
row_colors=[ROW_LR, ROW_LO, ROW_LA, ROW_LY, ROW_LO, ROW_LP],
), sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# PRACTICE QUESTIONS
# ══════════════════════════════════════════════════════════════════════════════
story += [banner("NCLEX-STYLE PRACTICE QUESTIONS — Chemical Warfare", MED_RED), sp(6)]
qs = [
("Q1. Multiple casualties arrive after a subway attack. Victims have pinpoint pupils, excessive salivation, "
"and muscle fasciculations. Which drug should the nurse prepare to administer FIRST?",
"A. Hydroxocobalamin\nB. Atropine\nC. Sodium thiosulfate\nD. Dimercaprol (BAL)",
"✔ Answer: B — DUMBELS signs (miosis, salivation, fasciculations) = nerve agent (organophosphate). "
"Atropine is the first-line muscarinic antidote. Pralidoxime follows."),
("Q2. A nurse is caring for a victim of a chemical attack who is alert and ambulatory. "
"The patient states he felt a brief eye sting 20 minutes ago at the scene but now feels fine. "
"The patient's clothing has a garlic-like odour. What is the nurse's priority action?",
"A. Reassure the patient and discharge home\n"
"B. Perform complete decontamination, remove clothing, and observe closely for delayed symptoms\n"
"C. Administer BAL (dimercaprol) immediately\nD. Apply antibiotic eye ointment",
"✔ Answer: B — Garlic odour = mustard gas, which has DELAYED onset (2–24 hours). "
"Patient feeling fine initially is characteristic and deceptive. "
"Decontaminate thoroughly and observe for delayed blistering and systemic effects. "
"BAL is for Lewisite, not mustard gas."),
("Q3. A victim of a suspected cyanide attack has rapid respiratory distress and seizures, "
"but the nurse notes the patient's lips and skin appear PINK rather than blue. "
"Which antidote does the nurse anticipate administering?",
"A. Atropine\nB. Naloxone\nC. Hydroxocobalamin (Cyanokit)\nD. Flumazenil",
"✔ Answer: C — Respiratory distress WITHOUT cyanosis = cyanide poisoning (histotoxic hypoxia). "
"Skin may appear pink/red because cells cannot extract O2 from blood. "
"Hydroxocobalamin (Cyanokit) is the preferred antidote."),
("Q4. The nurse is teaching staff about the odour associated with phosgene. "
"Which statement by a staff member indicates correct understanding?",
"A. 'Phosgene smells like bleach or pool chemicals.'\n"
"B. 'Phosgene has no odour.'\n"
"C. 'Phosgene smells like freshly cut hay or newly mown grass.'\n"
"D. 'Phosgene smells like bitter almonds.'",
"✔ Answer: C — Phosgene smells like freshly cut hay or mown grass. "
"Chlorine smells like bleach/pool. Cyanide smells like bitter almonds. "
"Mustard gas smells like garlic."),
("Q5. A nurse is treating a nerve agent victim and has administered atropine. "
"Which assessment finding indicates that a sufficient dose of atropine has been given?",
"A. Pupil dilation to normal size\nB. Heart rate increase to > 100 bpm\n"
"C. Drying of bronchial secretions\nD. Resolution of muscle fasciculations",
"✔ Answer: C — Atropine is titrated to DRYING OF SECRETIONS (bronchorrhoea). "
"Pupil size and heart rate are POOR indicators of adequate atropinisation in "
"organophosphate/nerve agent exposure per Tintinalli's Emergency Medicine."),
]
for q, choices, ans in qs:
blk = Table([
[Paragraph(q, body_s)],
[Paragraph(choices.replace("\n", " "), ps("qc", 7.8, italic=True))],
[Paragraph(ans, ps("qa", 8, DARK_MAROON, bold=True))],
], colWidths=[7.4*inch])
blk.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), colors.HexColor("#FEF5E7")),
("BACKGROUND", (0,1), (0,1), WHITE),
("BACKGROUND", (0,2), (0,2), ROW_LO),
("BOX", (0,0), (-1,-1), 0.7, ORANGE),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
story += [blk, sp(6)]
# FOOTER
story += [
HRFlowable(width="100%", thickness=0.5, color=GREY_LINE), sp(4),
Paragraph("Sources: Tintinalli's Emergency Medicine (Nerve Agents chapter) · Ganong's Medical Physiology · "
"Goldman-Cecil Medicine · CDC Emergency Preparedness · NCSBN NCLEX-RN Test Plan", foot_s),
]
doc.build(story)
print(f"Chemical Warfare PDF: {OUTPUT}")
python /home/daytona/workspace/nclex-warfare/bio_warfare.py 2>&1 && python /home…
~/nclex-warfare/chem_warfare.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/nclex-warfare/chem_warfare.py'
python /home/daytona/workspace/nclex-warfare/chem_warfare.py 2>&1
ls -lh /home/daytona/workspace/nclex-warfare/*.pdf
NCLEX Biological Warfare
PDF Document · PDF
| Section | Content |
|---|---|
| CDC Category A/B/C overview | Color-coded 3-column category table (red/amber/olive) |
| Anthrax | 3 forms (cutaneous/inhalation/GI) with color-coded rows + black eschar key |
| Smallpox vs. Chickenpox | Side-by-side purple vs. teal comparison table |
| Plague | Bubonic/Pneumonic/Septicaemic table - pneumonic row highlighted red |
| Botulism | Descending paralysis, antitoxin details, "locked-in" patient alert |
| Tularemia | 4 forms with transmissions |
| Viral Hemorrhagic Fevers | Ebola/Marburg/Lassa, full PPE requirements |
| Master Quick Reference | Color-coded summary of all 8 agents |
| 4 Practice Questions | With full rationales |
NCLEX Chemical Warfare
PDF Document · PDF
| Section | Content |
|---|---|
| 4-Class overview | Red/orange/amber/purple category boxes with mechanisms |
| Nerve Agents | DUMBELS letter-by-letter visual box; 3-receptor table |
| Treatment Table | Atropine + Pralidoxime + Benzodiazepines with titration tips |
| Vesicants | Mustard gas vs. Lewisite side-by-side; delayed vs. immediate onset |
| Pulmonary Agents | Chlorine vs. Phosgene; odour identification |
| Blood Agents / Cyanide | "No cyanosis" trap; hydroxocobalamin vs. sodium thiosulfate |
| Decontamination Steps | Priority nursing action sequence |
| Master Quick Reference | All 6 agents with smell, key sign, and antidote |
| 5 Practice Questions | Including atropine titration Q and cyanide "pink skin" Q |
Wow that so good
| Focus | |
|---|---|
| 📋 NCLEX Lab Values | All reference intervals, critical values, mnemonics |
| 🏥 Safe Environment | Precautions, restraints, fire safety, triage, PPE |
| ☣️ Biological Warfare | Anthrax, Smallpox, Plague, Botulism, VHF + practice Qs |
| ⚗️ Chemical Warfare | Nerve agents (DUMBELS), Vesicants, Cyanide + practice Qs |
But one thing nxt time uh can also use peregraph type also because in table mathode some collomes are mearge
| Agent | Mechanism | Symptoms | Treatment | Precautions | Antidote |
|---|---|---|---|---|---|
| (all squished) | ... | ... | ... | ... | ... |
🔴 Anthrax (Bacillus anthracis) Anthrax is caused by... (paragraph) Signs & Symptoms: Cutaneous form presents with a painless papule... Treatment: Ciprofloxacin or doxycycline... (then a small clean 2-col table for quick reference)
Sure can uh show me a demo pdf on that format
~/nclex-warfare/demo_format.py
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph,
Spacer, HRFlowable, KeepTogether, ListFlowable, ListItem
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
OUTPUT = "/home/daytona/workspace/nclex-warfare/DEMO_NewFormat.pdf"
# ── Palette ───────────────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1B3A6B")
TEAL = colors.HexColor("#1A7F8E")
RED_DARK = colors.HexColor("#922B21")
RED_MED = colors.HexColor("#C0392B")
GREEN_DK = colors.HexColor("#145A32")
GREEN_MD = colors.HexColor("#1E8449")
ORANGE = colors.HexColor("#E67E22")
PURPLE = colors.HexColor("#6C3483")
GREY_BG = colors.HexColor("#F4F6F7")
GREY_LINE = colors.HexColor("#BDC3C7")
GREY_TXT = colors.HexColor("#555555")
LIGHT_TEAL = colors.HexColor("#D1F2EB")
LIGHT_RED = colors.HexColor("#FADBD8")
LIGHT_AMB = colors.HexColor("#FDEBD0")
LIGHT_BLUE = colors.HexColor("#D6EAF8")
LIGHT_PUR = colors.HexColor("#E8DAEF")
LIGHT_GRN = colors.HexColor("#D5F5E3")
WHITE = colors.white
BLACK = colors.black
# ── Styles ────────────────────────────────────────────────────────────────────
def P(name, size=9, color=BLACK, bold=False, italic=False,
align=TA_LEFT, leading=None, left=0, right=0, space_before=0, space_after=0):
fn = "Helvetica" + ("-BoldOblique" if bold and italic else
"-Bold" if bold else "-Oblique" if italic else "")
return ParagraphStyle(name, fontSize=size, fontName=fn, textColor=color,
alignment=align, leading=leading or size * 1.5,
leftIndent=left, rightIndent=right,
spaceBefore=space_before, spaceAfter=space_after)
title_s = P("T", 22, WHITE, bold=True, align=TA_CENTER)
subtitle_s = P("St", 10, WHITE, italic=True, align=TA_CENTER)
sec_s = P("Se", 13, WHITE, bold=True, left=8)
agent_s = P("Ag", 11, WHITE, bold=True, left=8)
h3_s = P("H3", 10, NAVY, bold=True, space_before=4)
body_s = P("Bo", 9, BLACK, leading=14, align=TA_JUSTIFY)
body_b = P("BB", 9, BLACK, bold=True)
bullet_s = P("Bu", 9, BLACK, leading=14, left=14)
label_s = P("La", 8.5, GREY_TXT, bold=True)
key_s = P("Ke", 9, RED_DARK, bold=True, left=6)
mnem_s = P("Mn", 9, GREEN_DK, bold=True, left=6)
tip_s = P("Ti", 8.5, NAVY, italic=True, left=6)
foot_s = P("Fo", 6.8, GREY_TXT, align=TA_CENTER)
tag_s = P("Ta", 8, WHITE, bold=True, align=TA_CENTER)
def sp(n=6): return Spacer(1, n)
# ── Layout helpers ─────────────────────────────────────────────────────────────
def full_banner(line1, line2, bg=NAVY):
"""Full-width title banner."""
t = Table([
[Paragraph(line1, title_s)],
[Paragraph(line2, subtitle_s)],
], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 12),
]))
return t
def section_banner(text, bg=TEAL):
"""Section divider banner."""
t = Table([[Paragraph(text, sec_s)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
]))
return t
def agent_banner(number, name, category, bg=RED_DARK):
"""Per-agent coloured header with category tag."""
inner = Table([[
Paragraph(f"{number}. {name}", agent_s),
Paragraph(category, tag_s),
]], colWidths=[5.8*inch, 1.6*inch])
inner.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BACKGROUND", (1,0), (1,0), colors.HexColor(
hex(max(0, int(bg.hexval(), 16) - 0x202020))[2:].zfill(6)
if False else bg.hexval())),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (0,0), 10),
("ALIGN", (1,0), (1,0), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
return inner
def info_box(text_para, bg=LIGHT_BLUE, border=TEAL):
"""Coloured paragraph info box."""
t = Table([[text_para]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 0.8, border),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
return t
def two_box(left_title, left_items, right_title, right_items,
left_bg=LIGHT_BLUE, right_bg=LIGHT_GRN,
left_border=TEAL, right_border=GREEN_MD):
"""Two side-by-side coloured boxes."""
def make_box(title, items, bg, border):
rows = [[Paragraph(title, h3_s)]]
for item in items:
rows.append([Paragraph(f"• {item}", bullet_s)])
t = Table(rows, colWidths=[3.55*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 0.7, border),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
outer = Table([[
make_box(left_title, left_items, left_bg, left_border),
make_box(right_title, right_items, right_bg, right_border),
]], colWidths=[3.6*inch, 3.6*inch])
outer.setStyle(TableStyle([
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 2),
("TOPPADDING", (0,0), (-1,-1), 0),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return outer
def quick_ref_table(headers, rows, col_widths, header_bg=NAVY):
"""Compact quick-reference table — used sparingly."""
data = [headers] + rows
t = Table(data, colWidths=col_widths, repeatRows=1)
cmds = [
("BACKGROUND", (0,0), (-1,0), header_bg),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 8),
("ALIGN", (0,0), (-1,0), "CENTER"),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
for i in range(2, len(rows)+1, 2):
cmds.append(("BACKGROUND", (0,i), (-1,i), GREY_BG))
t.setStyle(TableStyle(cmds))
return t
def label_para(label, text):
"""Inline bold label + paragraph text as a single 2-col row."""
t = Table([[Paragraph(label, label_s), Paragraph(text, body_s)]],
colWidths=[1.3*inch, 6.1*inch])
t.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 2),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 0),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return t
# ══════════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ══════════════════════════════════════════════════════════════════════════════
story = []
doc = SimpleDocTemplate(OUTPUT, pagesize=letter,
leftMargin=0.6*inch, rightMargin=0.6*inch,
topMargin=0.6*inch, bottomMargin=0.6*inch,
title="NCLEX Demo – New Mixed Format", author="Orris Study Aid")
# ── TITLE ─────────────────────────────────────────────────────────────────────
story += [
full_banner("☣ Biological Warfare Agents", "NCLEX Demo · New Mixed Format · Paragraph + Bullet + Table"),
sp(8),
]
# ── INTRO PARAGRAPH ───────────────────────────────────────────────────────────
story += [
section_banner("Overview", NAVY),
sp(6),
Paragraph(
"Biological warfare agents are living organisms or toxins deliberately released to cause "
"disease in humans, animals, or plants. The CDC classifies them into three categories "
"based on their potential for mass casualties and ease of dissemination. Nurses must "
"recognise these agents quickly, apply the correct isolation precautions, and initiate "
"appropriate treatment without delay. This guide covers the four highest-yield Category A "
"agents tested on the NCLEX.",
body_s),
sp(6),
info_box(Paragraph(
"📌 NGN NCLEX Note: Questions will ask you to RECOGNISE the agent from clinical clues, "
"SELECT the correct precaution type, and PRIORITISE the nursing action. "
"Focus on the 'one key differentiator' for each agent.",
tip_s), bg=LIGHT_BLUE, border=TEAL),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# AGENT 1 — ANTHRAX
# ══════════════════════════════════════════════════════════════════════════════
story += [
KeepTogether([
agent_banner("1", "ANTHRAX (Bacillus anthracis)", "Category A", RED_DARK),
sp(6),
]),
]
# Mechanism paragraph
story += [
Paragraph("What is it?", h3_s),
sp(3),
Paragraph(
"Anthrax is caused by <i>Bacillus anthracis</i>, a spore-forming gram-positive bacillus. "
"It is considered the most likely agent to be used in a bioterrorism attack because "
"its spores are highly stable, can be aerosolized, and inhalation anthrax carries a "
"mortality rate greater than 80% if untreated. The 2001 U.S. mail attacks produced "
"11 inhalation and 11 cutaneous cases, with 5 inhalation deaths.",
body_s),
sp(8),
]
# Three forms side-by-side bullets + paragraph
story += [
Paragraph("Clinical Forms", h3_s),
sp(4),
two_box(
"Cutaneous (95% of natural cases)",
["Painless papule at site of skin contact",
"Progresses to vesicles, then ULCER",
"BLACK, painless ESCHAR forms (key finding)",
"Surrounding oedema and lymphadenopathy",
"Incubation: < 1 week"],
"Inhalation (Bioweapon form ★)",
["Flu-like prodrome (fever, malaise, myalgia)",
"Brief apparent improvement, then sudden collapse",
"WIDENED MEDIASTINUM on chest X-ray",
"Haemorrhagic meningitis, septic shock",
"Incubation: 2 days – 6 WEEKS (spore dormancy)"],
left_bg=LIGHT_AMB, right_bg=LIGHT_RED,
left_border=ORANGE, right_border=RED_MED,
),
sp(6),
Paragraph(
"Gastrointestinal anthrax, while rare, can occur after ingesting infected animal tissue. "
"It presents with ulcers, nausea, bloody diarrhoea, and ascites. All forms can "
"progress to systemic anthrax with bacteraemia and meningitis if untreated.",
body_s),
sp(8),
]
# Precautions & Treatment as labelled paragraphs
story += [
Paragraph("Precautions & Treatment", h3_s),
sp(4),
label_para("Precautions:", "Standard precautions for all forms. Person-to-person transmission is extremely rare. Cutaneous discharge is potentially infectious — wear gloves when handling wounds."),
sp(3),
label_para("Treatment:", "Ciprofloxacin or Doxycycline are first-line for all forms. Inhalation anthrax requires IV therapy initially, then oral step-down for a total of 60 days to cover spore dormancy."),
sp(3),
label_para("Prophylaxis:", "Post-exposure prophylaxis: Ciprofloxacin or Doxycycline × 60 days. Anthrax vaccine (AVA) is available for high-risk populations (military, laboratory workers)."),
sp(6),
]
# NCLEX key box
story += [
info_box(Paragraph(
"🔑 NCLEX Key Points for Anthrax\n"
" • PAINLESS black eschar = cutaneous anthrax (painless differentiates from other skin infections)\n"
" • WIDENED MEDIASTINUM on CXR = inhalation anthrax until proven otherwise\n"
" • Inhalation incubation can be up to 6 WEEKS — patient may seem well initially\n"
" • Standard precautions only (no airborne, no droplet needed)",
mnem_s), bg=LIGHT_GRN, border=GREEN_MD),
sp(12),
]
# ══════════════════════════════════════════════════════════════════════════════
# AGENT 2 — SMALLPOX
# ══════════════════════════════════════════════════════════════════════════════
story += [
KeepTogether([
agent_banner("2", "SMALLPOX (Variola virus)", "Category A", PURPLE),
sp(6),
]),
Paragraph("What is it?", h3_s),
sp(3),
Paragraph(
"Smallpox is caused by Variola virus and was declared eradicated in 1980. "
"Because routine vaccination stopped around 1980, most people under 45 have "
"no immunity, making it an extremely dangerous potential bioweapon. "
"The only known remaining stocks are held at the CDC (Atlanta, USA) and "
"VECTOR Institute (Russia). Smallpox is HIGHLY contagious via the airborne route "
"and close contact.",
body_s),
sp(8),
Paragraph("Key Clinical Features", h3_s),
sp(4),
Paragraph(
"The prodrome begins with high fever, severe headache, and backache "
"<b>2–4 days BEFORE the rash appears</b>. This is a critical differentiator from chickenpox, "
"where fever and rash appear together. The rash is centrifugal — it begins on the "
"face and spreads outward to the palms and soles. All lesions are in the "
"<b>same stage of development simultaneously</b> (deep, firm, umbilicated pustules). "
"Contrast this with chickenpox, where lesions in multiple stages (papules, vesicles, "
"crusts) appear at the same time.",
body_s),
sp(6),
]
# Comparison quick-ref table (used because it IS a true comparison)
story += [
Paragraph("Smallpox vs. Chickenpox — Quick Comparison", h3_s),
sp(4),
quick_ref_table(
headers=["Feature", "SMALLPOX", "CHICKENPOX (Varicella)"],
col_widths=[2.0*inch, 2.7*inch, 2.7*inch],
rows=[
["Lesion stages", "ALL same stage (synchronous)", "Multiple stages simultaneously"],
["Rash distribution", "Centrifugal: face → palms/soles", "Centripetal: trunk > extremities"],
["Lesion depth", "Deep, firm, hard, umbilicated", "Superficial, soft vesicles"],
["Prodrome fever", "2–4 days BEFORE rash", "Mild fever WITH rash"],
["Isolation", "Airborne + Contact precautions", "Airborne precautions"],
],
header_bg=PURPLE,
),
sp(6),
]
story += [
label_para("Precautions:", "AIRBORNE + CONTACT precautions. N-95 respirator, negative-pressure room, gown and gloves. Door must remain closed at all times. Patient wears surgical mask during transport."),
sp(3),
label_para("Treatment:", "No proven specific antiviral. Vaccinia vaccine (ACAM2000) given within 4 days of exposure can prevent or significantly reduce disease. Tecovirimat (TPOXX) is approved for treatment of smallpox."),
sp(6),
info_box(Paragraph(
"🔑 NCLEX Key Points for Smallpox\n"
" • ALL lesions = SAME stage (the single most testable fact)\n"
" • Centrifugal rash: face, palms, soles first\n"
" • Requires BOTH Airborne AND Contact precautions (N-95 + negative-pressure room)\n"
" • Vaccinate contacts within 4 DAYS of exposure for prevention",
mnem_s), bg=LIGHT_PUR, border=PURPLE),
sp(12),
]
# ══════════════════════════════════════════════════════════════════════════════
# AGENT 3 — BOTULISM (briefer — shows paragraph-only style)
# ══════════════════════════════════════════════════════════════════════════════
story += [
KeepTogether([
agent_banner("3", "BOTULISM (Clostridium botulinum toxin)", "Category A", NAVY),
sp(6),
]),
Paragraph("Mechanism & Presentation", h3_s),
sp(3),
Paragraph(
"Botulinum toxin blocks acetylcholine release at the neuromuscular junction, "
"producing a characteristic <b>descending flaccid paralysis</b>. Symptoms begin with the "
"cranial nerves — diplopia, dysarthria, dysphagia (the '3 Ds') — then descend to the "
"limbs and finally the respiratory muscles. The patient remains <b>afebrile, alert, "
"and without sensory loss</b>. This is a critical NCLEX distinguisher: the patient "
"appears 'locked in' but is fully conscious. All caregivers must be reminded of this — "
"explain every procedure and avoid insensitive comments at the bedside.",
body_s),
sp(6),
Paragraph("Nursing Priorities", h3_s),
sp(4),
]
# Bullet list using paragraph style
for bullet in [
"Monitor respiratory status continuously — rate, O2 saturation, vital capacity. Respiratory failure from descending paralysis is the immediate life threat.",
"Administer Botulinum Antitoxin (BAT) as early as possible. It stops progression but does NOT reverse paralysis already present.",
"Mechanical ventilation may be required for weeks to months — prepare patient and family for prolonged ICU stay.",
"Standard precautions only — no person-to-person transmission.",
"Infant botulism: HONEY is strictly contraindicated in infants under 12 months. Use BabyBIG (human-derived immunoglobulin) for treatment.",
]:
story += [Paragraph(f"• {bullet}", bullet_s), sp(2)]
story += [
sp(4),
info_box(Paragraph(
"⚠ ANTITOXIN ALERT: Botulinum antitoxin STOPS progression of paralysis — "
"it does NOT reverse paralysis that has already occurred. Give as early as possible. "
"The patient is CONSCIOUS even when completely paralysed — always communicate and explain.",
key_s), bg=LIGHT_RED, border=RED_MED),
sp(12),
]
# ══════════════════════════════════════════════════════════════════════════════
# MASTER QUICK REFERENCE (compact table — appropriate use)
# ══════════════════════════════════════════════════════════════════════════════
story += [
section_banner("Master Quick-Reference — All Agents at a Glance", GREEN_DK),
sp(6),
quick_ref_table(
headers=["Agent", "One Key Sign", "Precaution", "Antidote / Treatment"],
col_widths=[1.3*inch, 2.4*inch, 1.5*inch, 2.2*inch],
rows=[
["Anthrax\n(cutaneous)", "Painless BLACK ESCHAR", "Standard", "Ciprofloxacin / Doxycycline"],
["Anthrax\n(inhalation)", "Widened mediastinum on CXR", "Standard", "Ciprofloxacin IV then oral × 60 days"],
["Smallpox", "ALL lesions same stage; centrifugal","Airborne+Contact","Vaccinia vaccine within 4 days; Tecovirimat"],
["Plague (pneumonic)", "Bloody frothy sputum", "DROPLET", "Streptomycin / Doxycycline"],
["Botulism", "Descending paralysis; alert/afebrile","Standard", "BAT antitoxin (stops progression only)"],
["Tularemia", "Ulcer + lymphadenopathy", "Standard", "Streptomycin / Gentamicin"],
],
header_bg=GREEN_DK,
),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# PRACTICE QUESTION — shows mixed format
# ══════════════════════════════════════════════════════════════════════════════
story += [
section_banner("Sample NCLEX-Style Question", TEAL),
sp(6),
]
q_block = Table([
[Paragraph(
"Q. A patient presents with a rash where all skin lesions appear to be in the same stage "
"of development, are firm and deep, and are concentrated on the face and palms. "
"The patient reports a high fever that began 3 days before the rash. "
"Which action should the nurse take FIRST?",
body_s)],
[sp(4)],
[Paragraph(
"A. Apply contact precautions and a gown and gloves only\n"
"B. Place the patient in a negative-pressure room and apply airborne and contact precautions\n"
"C. Administer antiviral medication immediately\n"
"D. Place the patient in a standard room and notify the charge nurse",
P("qc", 8.5, italic=True, left=10))],
[sp(4)],
[Paragraph(
"✔ Answer: B\n"
"Rationale: The presentation describes smallpox — synchronous same-stage lesions, "
"centrifugal distribution (face and palms), and prodromal fever 2–4 days before the rash. "
"Smallpox requires BOTH airborne precautions (N-95, negative-pressure room) AND contact "
"precautions (gown and gloves). Option A is incomplete. Option C is not the priority "
"action before isolation is established.",
P("qa", 9, GREEN_DK, bold=False, left=6))],
], colWidths=[7.4*inch])
q_block.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), LIGHT_BLUE),
("BACKGROUND", (0,2), (0,2), WHITE),
("BACKGROUND", (0,4), (0,4), LIGHT_GRN),
("BOX", (0,0), (-1,-1), 0.8, TEAL),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
story += [q_block, sp(8)]
# ── FORMAT NOTE BOX ────────────────────────────────────────────────────────────
story += [
info_box(Paragraph(
"📐 About This Format\n"
"This demo uses a MIXED LAYOUT: paragraphs for explanations and mechanisms, "
"bullet lists for signs/symptoms and nursing actions, labelled paragraph rows for "
"treatment details, and compact tables ONLY where genuine side-by-side comparison "
"adds value. This prevents column merging and overflow issues and makes content "
"more readable when printed.",
tip_s), bg=LIGHT_BLUE, border=TEAL),
sp(6),
HRFlowable(width="100%", thickness=0.5, color=GREY_LINE),
sp(4),
Paragraph(
"Sources: Harrison's Principles of Internal Medicine 22E · Red Book 2021 · "
"Goldman-Cecil Medicine · CDC Bioterrorism Agent List · NCSBN NCLEX-RN Test Plan",
foot_s),
]
doc.build(story)
print(f"Demo PDF written to: {OUTPUT}")
python /home/daytona/workspace/nclex-warfare/demo_format.py 2>&1
ls -lh /home/daytona/workspace/nclex-warfare/DEMO_NewFormat.pdf
DEMO NewFormat
PDF Document · PDF
| Element | Used For |
|---|---|
| Coloured agent banner | Each agent gets its own header bar with category tag |
| Paragraph blocks | Mechanism, background, clinical description — flows naturally, no squishing |
| Labelled rows (bold label + paragraph) | Precautions / Treatment / Prophylaxis — clean, readable |
| Bullet lists | Signs & symptoms, nursing priorities — scannable |
| Two-box side layout | Only for true comparisons (e.g. cutaneous vs. inhalation anthrax) |
| Table | ONLY the Smallpox vs. Chickenpox comparison and the final quick-reference — where a table genuinely helps |
| Coloured info boxes | NCLEX key points, warnings, mnemonics — stand out visually |
Tht was also good but use littel highlighted points and also nclex imp topics and mamory tricks
~/nclex-warfare/demo_v2.py
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph,
Spacer, HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
OUTPUT = "/home/daytona/workspace/nclex-warfare/DEMO_NewFormat_v2.pdf"
# ── Palette ───────────────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1B3A6B")
TEAL = colors.HexColor("#1A7F8E")
RED_DARK = colors.HexColor("#922B21")
RED_MED = colors.HexColor("#C0392B")
GREEN_DK = colors.HexColor("#145A32")
GREEN_MD = colors.HexColor("#1E8449")
ORANGE = colors.HexColor("#E67E22")
PURPLE = colors.HexColor("#6C3483")
GOLD = colors.HexColor("#B7950B")
PINK = colors.HexColor("#C0185A")
BROWN = colors.HexColor("#5D4037")
GREY_LINE = colors.HexColor("#BDC3C7")
GREY_TXT = colors.HexColor("#666666")
WHITE = colors.white
BLACK = colors.black
# Light fills
L_RED = colors.HexColor("#FADBD8")
L_ORG = colors.HexColor("#FDEBD0")
L_YEL = colors.HexColor("#FEF9E7")
L_GRN = colors.HexColor("#D5F5E3")
L_TEAL = colors.HexColor("#D1F2EB")
L_BLUE = colors.HexColor("#D6EAF8")
L_PUR = colors.HexColor("#E8DAEF")
L_PINK = colors.HexColor("#FDEDEC")
L_GREY = colors.HexColor("#F4F6F7")
L_GOLD = colors.HexColor("#FEF5E7")
# ── Styles ────────────────────────────────────────────────────────────────────
def S(name, size=9, color=BLACK, bold=False, italic=False,
align=TA_LEFT, leading=None, left=0, right=0, sb=0, sa=0):
fn = ("Helvetica-BoldOblique" if bold and italic else
"Helvetica-Bold" if bold else
"Helvetica-Oblique" if italic else "Helvetica")
return ParagraphStyle(name, fontSize=size, fontName=fn, textColor=color,
alignment=align, leading=leading or size*1.55,
leftIndent=left, rightIndent=right,
spaceBefore=sb, spaceAfter=sa)
title_s = S("T", 22, WHITE, bold=True, align=TA_CENTER)
sub_s = S("Su", 10, WHITE, italic=True, align=TA_CENTER)
sec_s = S("Se", 13, WHITE, bold=True, left=8)
agent_s = S("Ag", 11, WHITE, bold=True, left=10)
tag_s = S("Tg", 8, WHITE, bold=True, align=TA_CENTER)
h3_s = S("H3", 10, NAVY, bold=True, sb=2)
body_s = S("Bo", 9, BLACK, leading=14, align=TA_JUSTIFY)
bullet_s = S("Bu", 9, BLACK, leading=14, left=14)
label_s = S("La", 8.5, GREY_TXT, bold=True)
# Highlighted text styles
hl_red = S("HR", 9, RED_DARK, bold=True, left=6)
hl_green = S("HG", 9, GREEN_DK, bold=True, left=6)
hl_navy = S("HN", 9, NAVY, bold=True, left=6)
hl_gold = S("HGo", 9, GOLD, bold=True, left=6)
hl_tip = S("HT", 8.5, NAVY, italic=True, left=6)
hl_trick = S("HTr", 9, PURPLE, bold=True, left=6)
foot_s = S("Fo", 6.8, GREY_TXT, align=TA_CENTER)
def sp(n=6): return Spacer(1, n)
# ══════════════════════════════════════════════════════════════════════════════
# COMPONENT BUILDERS
# ══════════════════════════════════════════════════════════════════════════════
def title_block(line1, line2, bg=NAVY):
t = Table([[Paragraph(line1, title_s)],
[Paragraph(line2, sub_s)]],
colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 14),
("BOTTOMPADDING", (0,0), (-1,-1), 14),
]))
return t
def sec_banner(text, bg=TEAL):
t = Table([[Paragraph(text, sec_s)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
]))
return t
def agent_bar(num, name, cat, bg=RED_DARK):
"""Agent header: coloured bar with number, name and category badge."""
badge_bg = colors.HexColor(
"%06x" % max(0, int(bg.hexval(), 16) - 0x181818))
t = Table([[Paragraph(f"{num}. {name}", agent_s),
Paragraph(cat, tag_s)]],
colWidths=[5.9*inch, 1.5*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), bg),
("BACKGROUND", (1,0), (1,0), badge_bg),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("LEFTPADDING", (0,0), (0,0), 10),
("ALIGN", (1,0), (1,0), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
return t
def lp(label, text, label_w=1.4):
"""Bold label + body paragraph in a tight two-column row."""
t = Table([[Paragraph(label, label_s),
Paragraph(text, body_s)]],
colWidths=[label_w*inch, (7.4 - label_w)*inch])
t.setStyle(TableStyle([
("TOPPADDING", (0,0), (-1,-1), 2),
("BOTTOMPADDING", (0,0), (-1,-1), 2),
("LEFTPADDING", (0,0), (-1,-1), 0),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
return t
def hbox(para, bg=L_BLUE, border=TEAL):
"""Single coloured paragraph box."""
t = Table([[para]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 0.9, border),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
return t
def highlight_row(icon, text, style, bg, border):
"""Single inline highlight strip — icon + text on one line."""
t = Table([[Paragraph(f"{icon} {text}", style)]],
colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 0.7, border),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def nclex_imp(*points):
"""Yellow starred NCLEX-important points box."""
rows = [[Paragraph("⭐ NCLEX IMPORTANT", S("ni", 9, GOLD, bold=True))]]
for p in points:
rows.append([Paragraph(f"★ {p}", S("np", 8.5, colors.HexColor("#7D6608")))])
t = Table(rows, colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), L_GOLD),
("BACKGROUND", (0,1), (-1,-1), colors.HexColor("#FFFDE7")),
("BOX", (0,0), (-1,-1), 1.0, GOLD),
("LINEBELOW", (0,0), (-1,0), 0.5, GOLD),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def memory_trick(trick_text, extra=None):
"""Purple memory trick / mnemonic box."""
rows = [[Paragraph("🧠 MEMORY TRICK", S("mt", 9, PURPLE, bold=True))],
[Paragraph(trick_text, S("mb", 9, PURPLE, bold=False))]]
if extra:
rows.append([Paragraph(extra, S("me", 8.5, colors.HexColor("#4A235A"), italic=True))])
t = Table(rows, colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), L_PUR),
("BACKGROUND", (0,1), (-1,-1), colors.HexColor("#F5EEF8")),
("BOX", (0,0), (-1,-1), 1.0, PURPLE),
("LINEBELOW", (0,0), (-1,0), 0.5, PURPLE),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def warn_box(text):
"""Red warning / critical alert box."""
t = Table([[Paragraph(f"⚠ {text}", hl_red)]], colWidths=[7.4*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), L_RED),
("BOX", (0,0), (-1,-1), 1.0, RED_MED),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return t
def two_col_bullets(left_title, left_bullets, left_bg, left_border,
right_title, right_bullets, right_bg, right_border):
"""Two side-by-side bullet boxes."""
def box(title, bullets, bg, border):
rows = [[Paragraph(title, S("bh", 9, border, bold=True))]]
for b in bullets:
rows.append([Paragraph(f"• {b}", bullet_s)])
t = Table(rows, colWidths=[3.55*inch])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), bg),
("BACKGROUND", (0,1), (-1,-1), colors.HexColor(
"FFFEF0" if bg == L_YEL else "F8FFFE" if bg == L_TEAL else "FFF8F8"))),
("BOX", (0,0), (-1,-1), 0.8, border),
("LINEBELOW", (0,0), (0,0), 0.5, border),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
outer = Table([[box(left_title, left_bullets, left_bg, left_border),
box(right_title, right_bullets, right_bg, right_border)]],
colWidths=[3.65*inch, 3.65*inch])
outer.setStyle(TableStyle([
("LEFTPADDING", (0,0), (-1,-1), 0),
("RIGHTPADDING", (0,0), (-1,-1), 0),
("TOPPADDING", (0,0), (-1,-1), 0),
("VALIGN", (0,0), (-1,-1), "TOP"),
("INNERGRID", (0,0), (-1,-1), 0, WHITE),
]))
return outer
def mini_table(headers, rows, col_widths, hdr_bg=NAVY):
data = [headers] + rows
t = Table(data, colWidths=col_widths, repeatRows=1)
cmds = [
("BACKGROUND", (0,0), (-1,0), hdr_bg),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 8),
("ALIGN", (0,0), (-1,0), "CENTER"),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("GRID", (0,0), (-1,-1), 0.4, GREY_LINE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]
for i in range(2, len(rows)+1, 2):
cmds.append(("BACKGROUND", (0,i), (-1,i), L_GREY))
t.setStyle(TableStyle(cmds))
return t
def divider(): return HRFlowable(width="100%", thickness=0.6, color=GREY_LINE)
# ══════════════════════════════════════════════════════════════════════════════
# STORY
# ══════════════════════════════════════════════════════════════════════════════
story = []
doc = SimpleDocTemplate(OUTPUT, pagesize=letter,
leftMargin=0.6*inch, rightMargin=0.6*inch,
topMargin=0.6*inch, bottomMargin=0.6*inch,
title="NCLEX Demo v2 – Biological Warfare (Mixed Format)",
author="Orris Study Aid")
# ── TITLE ──────────────────────────────────────────────────────────────────────
story += [
title_block("☣ Biological Warfare Agents — NCLEX Study Guide",
"Mixed Format Demo · Highlights · Memory Tricks · NCLEX Important Points"),
sp(8),
hbox(Paragraph(
"📌 This guide uses paragraphs for explanations, bullet boxes for signs & symptoms, "
"highlighted strips for key facts, ⭐ NCLEX Important boxes for exam-critical points, "
"and 🧠 Memory Trick boxes for mnemonics. Tables are used only for true comparisons.",
hl_tip), bg=L_BLUE, border=TEAL),
sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# AGENT 1 — ANTHRAX
# ══════════════════════════════════════════════════════════════════════════════
story += [
agent_bar("1", "ANTHRAX (Bacillus anthracis)", "Category A ★ HIGHEST RISK", RED_DARK),
sp(6),
Paragraph("Overview", h3_s), sp(3),
Paragraph(
"Anthrax is caused by <i>Bacillus anthracis</i>, a spore-forming gram-positive rod. "
"It is the #1 bioterrorism concern because spores are incredibly stable, survive for decades "
"in soil, can be aerosolised, and inhalation anthrax kills over 80% of untreated patients. "
"The 2001 U.S. anthrax mail attacks demonstrated how even small quantities of spores "
"can produce mass casualties and overwhelm public health systems.",
body_s), sp(8),
Paragraph("Three Clinical Forms", h3_s), sp(4),
two_col_bullets(
"Cutaneous (95% of natural cases)",
["Painless papule at site of spore contact",
"Becomes a ring of vesicles, then ulcerates",
"Forms a BLACK, PAINLESS ESCHAR (key sign!)",
"Surrounding gelatinous oedema",
"Lymphadenopathy, low-grade fever",
"Incubation: < 1 week (rarely up to 2 weeks)"],
L_ORG, ORANGE,
"Inhalation ★ Bioweapon Form",
["Flu-like prodrome: fever, malaise, myalgia",
"Brief apparent improvement (1–3 days)",
"Then SUDDEN COLLAPSE & rapid deterioration",
"WIDENED MEDIASTINUM on chest X-ray",
"Haemorrhagic mediastinitis, meningitis",
"Incubation: 2 days – 6 WEEKS (spore dormancy!)"],
L_RED, RED_MED,
), sp(4),
Paragraph(
"The gastrointestinal form is rare and occurs after ingesting contaminated meat. "
"It produces oral/oropharyngeal ulcers, nausea, bloody diarrhoea, and ascites. "
"All forms can progress to septicaemia and meningitis if treatment is delayed.",
body_s), sp(6),
# highlighted strip
highlight_row("🔴", "WIDENED MEDIASTINUM on chest X-ray = Inhalation Anthrax until proven otherwise",
hl_red, L_RED, RED_MED), sp(3),
highlight_row("🟠", "BLACK PAINLESS ESCHAR = Cutaneous Anthrax (painless = key differentiator)",
S("hs2", 9, ORANGE, bold=True), L_ORG, ORANGE), sp(6),
Paragraph("Precautions & Treatment", h3_s), sp(3),
lp("Precautions:", "Standard precautions for all forms. Person-to-person transmission is extremely rare. Wear gloves when handling cutaneous lesions — discharge is potentially infectious."), sp(3),
lp("Treatment:", "Ciprofloxacin or Doxycycline are first-line. Inhalation anthrax requires IV therapy initially, then oral step-down. Total course = 60 days to cover prolonged spore germination."), sp(3),
lp("Prophylaxis:", "Post-exposure: Ciprofloxacin or Doxycycline × 60 days. Anthrax vaccine (AVA) for military and lab workers."), sp(6),
nclex_imp(
"Inhalation anthrax incubation = up to 6 WEEKS (spores can remain dormant in lungs)",
"Painless eschar — the word PAINLESS is what the NCLEX will test",
"Widened mediastinum on CXR = classic imaging finding of inhalation anthrax",
"Standard precautions only — no airborne, no droplet required",
"Ciprofloxacin is the drug most associated with anthrax on NCLEX",
), sp(4),
memory_trick(
"'ANTH-RAX has a BLACK TACK in its name' — black eschar, painless like a thumbtack",
"Inhalation anthrax: Think '6-WEEK SLEEPER' — spores sleep in lungs up to 6 weeks before waking up deadly"
), sp(12),
]
# ══════════════════════════════════════════════════════════════════════════════
# AGENT 2 — SMALLPOX
# ══════════════════════════════════════════════════════════════════════════════
story += [
agent_bar("2", "SMALLPOX (Variola virus)", "Category A — Eradicated 1980", PURPLE),
sp(6),
Paragraph("Overview", h3_s), sp(3),
Paragraph(
"Smallpox was eradicated globally in 1980. Because routine vaccination stopped at that time, "
"most people born after ~1972 have NO immunity, making it one of the most feared "
"potential bioweapons. Only two authorised repositories remain: CDC (Atlanta) and "
"VECTOR Institute (Russia). Smallpox spreads via the airborne route and direct contact "
"with lesions — both routes require simultaneous precautions.",
body_s), sp(8),
Paragraph("Clinical Features", h3_s), sp(3),
Paragraph(
"The prodrome begins with HIGH FEVER, severe headache, and backache "
"<b>2–4 days BEFORE the rash appears</b>. This pre-rash fever is the most tested "
"distinguishing feature from chickenpox. The rash is <b>centrifugal</b> — starting on "
"the face and spreading outward to the palms and soles (the opposite of chickenpox). "
"Critically, ALL lesions are in the <b>same stage of development simultaneously</b> — "
"all papules, then all vesicles, then all pustules, then all crusts. "
"The pustules are deep, firm, and umbilicated (belly-button dimple in centre).",
body_s), sp(6),
highlight_row("🟣", "ALL lesions SAME STAGE simultaneously = Smallpox (chickenpox has multiple stages at once)",
S("hsp", 9, PURPLE, bold=True), L_PUR, PURPLE), sp(3),
highlight_row("🟣", "Centrifugal rash: Face → Arms → Legs → Palms & Soles (outward from the centre)",
S("hsp2", 9, PURPLE, bold=True), L_PUR, PURPLE), sp(3),
highlight_row("🟣", "Prodrome FEVER 2–4 days BEFORE rash appears (chickenpox: fever WITH rash)",
S("hsp3", 9, PURPLE, bold=True), L_PUR, PURPLE), sp(6),
Paragraph("Smallpox vs. Chickenpox — Quick Comparison", h3_s), sp(4),
mini_table(
headers=["Feature", "SMALLPOX", "CHICKENPOX"],
col_widths=[2.0*inch, 2.7*inch, 2.7*inch],
rows=[
["Lesion stages", "ALL same stage", "Multiple stages at once"],
["Rash direction", "Centrifugal (face first)", "Centripetal (trunk first)"],
["Lesion feel", "Deep, firm, umbilicated", "Superficial, soft vesicles"],
["Fever timing", "2–4 days BEFORE rash", "WITH rash (or mild)"],
["Precautions", "Airborne + Contact", "Airborne only"],
], hdr_bg=PURPLE,
), sp(6),
lp("Precautions:", "AIRBORNE + CONTACT simultaneously. N-95 respirator (fit-tested), negative-pressure room, gown, gloves. Door must remain closed. Patient wears surgical mask during any transport."), sp(3),
lp("Treatment:", "No proven antiviral cure. Vaccinia vaccine (ACAM2000) given within 4 days of exposure can prevent or reduce disease severity. Tecovirimat (TPOXX) is FDA-approved for treatment."), sp(6),
nclex_imp(
"The #1 tested fact: ALL lesions are in the SAME stage — memorise this above all else",
"Precautions = BOTH Airborne AND Contact (two types at the same time)",
"Vaccinate contacts within 4 DAYS of exposure — window for prevention",
"Centrifugal = outward (face, palms, soles) — opposite of chickenpox",
"Negative-pressure room with door CLOSED at all times",
), sp(4),
memory_trick(
'"SMALL-pox = SMALL differences that are BIG on exams"',
"S = Same stage · M = More on face/palms (centrifugal) · A = Airborne+Contact · L = Lesions deep/firm · L = Long prodrome (fever first)"
), sp(12),
]
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# AGENT 3 — BOTULISM
# ══════════════════════════════════════════════════════════════════════════════
story += [
agent_bar("3", "BOTULISM (Clostridium botulinum toxin)", "Category A", NAVY),
sp(6),
Paragraph("Overview", h3_s), sp(3),
Paragraph(
"Botulinum toxin is the most acutely lethal toxin known. It blocks the release of "
"acetylcholine (ACh) at the neuromuscular junction, causing a progressive "
"<b>descending flaccid paralysis</b>. As a bioweapon it could be aerosolised or introduced "
"into food/water supplies. There is NO person-to-person transmission, so only standard "
"precautions are needed.",
body_s), sp(6),
Paragraph("Presentation — The 3 Ds then Down", h3_s), sp(3),
Paragraph(
"Symptoms begin with the cranial nerves and descend. The classic triad is <b>Diplopia</b> "
"(double vision), <b>Dysarthria</b> (slurred speech), and <b>Dysphagia</b> (difficulty "
"swallowing). These then progress downward to the trunk and limbs, and ultimately to "
"respiratory muscle failure. The patient is <b>afebrile, fully alert, with no sensory "
"loss</b> — they can hear and understand everything said in the room.",
body_s), sp(4),
highlight_row("🔵", "DESCENDING paralysis + AFEBRILE + ALERT + NO sensory loss = Botulism",
S("hbot", 9, NAVY, bold=True), L_BLUE, NAVY), sp(3),
highlight_row("🔵", "Patient is CONSCIOUS even when completely paralysed — always explain procedures aloud",
S("hbot2", 9, NAVY, bold=True), L_BLUE, NAVY), sp(3),
highlight_row("🔴", "RESPIRATORY FAILURE is the #1 priority — monitor rate, O2 sat, vital capacity",
hl_red, L_RED, RED_MED), sp(6),
Paragraph("Nursing Priorities", h3_s), sp(3),
*[Paragraph(f"• {b}", bullet_s) for b in [
"Monitor respiratory status continuously — frequent vital capacity checks, early intubation if needed.",
"Administer Botulinum Antitoxin (BAT) ASAP — it stops progression but does NOT reverse existing paralysis.",
"Paralysis can last weeks to months — prepare patient and family for prolonged ICU stay.",
"Post bedside signage: 'Patient is conscious — communicate with them, explain all procedures.'",
"Infant form: strict honey restriction under 12 months; treat with BabyBIG (human immunoglobulin).",
"Standard precautions only — no person-to-person transmission of botulism.",
]], sp(6),
warn_box(
"ANTITOXIN TRAP: BAT stops progression — it does NOT reverse paralysis already present. "
"The earlier it is given, the better the outcome. Call state health dept to access BAT from federal stockpile."
), sp(6),
nclex_imp(
"Descending paralysis = always think Botulism (ascending = Guillain-Barré — opposite direction!)",
"Patient is ALERT and CONSCIOUS despite being paralysed — NCLEX loves this fact",
"Antitoxin STOPS progression — does NOT REVERSE existing paralysis",
"Honey is CONTRAINDICATED in infants under 1 year (infant botulism risk)",
"Respiratory failure = priority nursing concern — monitor every assessment",
), sp(4),
memory_trick(
'"BOTU-lism goes DOWN like a BOT-tle tipped over" — descending paralysis',
"3 Ds before it goes DOWN: Diplopia → Dysarthria → Dysphagia → Descending paralysis → Diaphragm (respiratory failure)"
), sp(12),
]
# ══════════════════════════════════════════════════════════════════════════════
# MASTER QUICK REFERENCE
# ══════════════════════════════════════════════════════════════════════════════
story += [
sec_banner("Master Quick-Reference", GREEN_DK), sp(6),
mini_table(
headers=["Agent", "One-Liner Key Sign", "Precaution", "Treatment / Antidote"],
col_widths=[1.3*inch, 2.5*inch, 1.4*inch, 2.2*inch],
rows=[
["Anthrax (skin)", "Painless BLACK eschar", "Standard", "Cipro / Doxy × 60 days"],
["Anthrax (lung)", "Widened mediastinum on CXR", "Standard", "Cipro IV → oral × 60 days"],
["Smallpox", "ALL lesions same stage; centrifugal","Airborne+Contact", "Vaccinia vaccine ≤ 4 days"],
["Plague (pneumonic)","Bloody frothy sputum", "Droplet", "Streptomycin / Doxy"],
["Botulism", "Descending paralysis; alert; afebrile","Standard", "BAT antitoxin (stops progression)"],
["Tularemia", "Ulcer + lymphadenopathy", "Standard", "Streptomycin / Gentamicin"],
], hdr_bg=GREEN_DK,
), sp(10),
]
# ══════════════════════════════════════════════════════════════════════════════
# PRACTICE QUESTION
# ══════════════════════════════════════════════════════════════════════════════
story += [
sec_banner("NCLEX-Style Practice Question", TEAL), sp(6),
]
q = Table([
[Paragraph(
"A nurse receives four patients during a mass casualty event. "
"Patient A has a painless black lesion on the hand after opening a suspicious envelope. "
"Patient B has descending limb weakness, double vision, and is afebrile. "
"Patient C has a rash with ALL lesions appearing as firm pustules concentrated on the face and palms. "
"Patient D has bloody frothy sputum and severe pneumonia after a possible bioterrorism release.\n\n"
"Match each patient with the correct priority nursing action:",
body_s)],
[sp(3)],
[Paragraph(
"Patient A — Cutaneous Anthrax: Standard precautions; Ciprofloxacin; notify public health.\n"
"Patient B — Botulism: Standard precautions; monitor respirations; prepare for BAT antitoxin.\n"
"Patient C — Smallpox: Airborne + Contact precautions; N-95; negative-pressure room; notify CDC.\n"
"Patient D — Pneumonic Plague: Droplet precautions; Streptomycin or Doxycycline.",
S("qa", 9, GREEN_DK, bold=False, left=8))],
], colWidths=[7.4*inch])
q.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), L_BLUE),
("BACKGROUND", (0,2), (0,2), L_GRN),
("BOX", (0,0), (-1,-1), 0.8, TEAL),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING", (0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
]))
story += [q, sp(10)]
# ── FOOTER ─────────────────────────────────────────────────────────────────────
story += [
divider(), sp(4),
Paragraph(
"Sources: Harrison's Principles of Internal Medicine 22E · Red Book 2021 · "
"Goldman-Cecil Medicine · CDC Bioterrorism Agent List · NCSBN NCLEX-RN Test Plan",
foot_s),
]
doc.build(story)
print(f"Written: {OUTPUT}")
Generate the demo v2 PDF and download it
Create a full NCLEX study guide using this improved format