Airway management for anaesthsia resident and definition of difficult mask ventilation and DSA protocol explained in simple terms and steps with diagrams
| Letter | What to Check |
|---|---|
| L - Look externally | Gestalt: facial trauma, large tongue, beard, obesity |
| E - Evaluate 3-3-2 rule | Mouth opening = 3 fingers; Chin-to-hyoid = 3 fingers; Hyoid-to-thyroid notch = 2 fingers |
| M - Mallampati | Class I/II = easy; Class III = moderate; Class IV = likely difficult |
| O - Obstruction/Obesity | Supraglottic mass, Ludwig's angina, severe obesity |
| N - Neck mobility | Can they flex/extend? Fixed cervical spine = difficult |
The 3-3-2 rule: if a patient has a receding jaw and high larynx, direct laryngoscopy will be very difficult because you cannot displace the tongue adequately to see the cords.
| Class | What you see | Meaning |
|---|---|---|
| I | Soft palate, uvula, anterior and posterior pillars | Easy |
| II | Soft palate, uvula | Usually easy |
| III | Soft palate, base of uvula only | Likely difficult |
| IV | Hard palate only | Very difficult |
| Letter | Risk Factor | Why it matters |
|---|---|---|
| R - Radiation/Resistance | History of neck radiation; severe asthma, COPD, ARDS | Stiff lungs need high pressures |
| O - Obstruction/Obesity/OSA | Supraglottic mass, BMI >35, obstructive sleep apnoea | Redundant pharyngeal tissue collapses |
| M - Mallampati/Mask seal/Male | Class III-IV; beard, facial trauma (poor seal); male sex | Poor seal = air leak; males have larger tongues |
| A - Age >55 | Physiological aging, loss of pharyngeal tone | Harder to ventilate |
| N - No teeth (edentulous) | Teeth support the mask seal | "Teeth out to intubate, teeth IN to ventilate" |
Practical tip: If a patient is edentulous, leave their dentures in for mask ventilation and only remove them for laryngoscopy.




| Rule | Explanation |
|---|---|
| Oxygen first, always | Give supplemental oxygen between every attempt |
| Do not repeat failure | Never do the same thing three times if it's failing - change your approach |
| Call for help early | Before you've used up all your attempts, not after |
| Video laryngoscopy first | ASA and DAS now recommend VL as the primary approach for anticipated difficulty |
| Maximum 3+1 intubation attempts | After 3 failed attempts by the same operator, one more by a more senior person |
| CICO is not a failure | Declaring CICO early and going to Plan D saves lives. Delay kills. |
| Capnography confirms intubation | Waveform ETCO2 is the gold standard. Do not rely on chest rise or "feeling" alone |
| Awake intubation for predicted impossible mask | If you predict you cannot mask ventilate AND cannot intubate, do NOT induce GA |
| Document and follow up | After any difficult airway, fill an airway alert form, inform the patient in writing, notify their GP |
PREOP ASSESSMENT:
LEMON (difficult intubation) + ROMAN (difficult mask ventilation)
INTRAOP - If intubation fails:
PLAN A (DAS): Laryngoscopy - max 3+1 attempts, optimized technique
↓ FAIL → Declare failed intubation
PLAN B (DAS): Second-generation SAD - max 3 attempts
↓ SUCCEED → STOP AND THINK (wake up / intubate via SAD / proceed)
↓ FAIL → Declare failed SAD
PLAN C (DAS): Final facemask ventilation (2-person technique, NMB)
↓ SUCCEED → Wake patient up
↓ FAIL → DECLARE CICO
PLAN D (DAS): Scalpel cricothyroidotomy - NOW, no further delay
Create a visual pocket card PDF of the DAS 4-plan algorithm with equipment checklists
mkdir -p /home/daytona/workspace/das-pocket-card && ls /home/daytona/workspace/d…
~/das-pocket-card/generate_das_card.py
"""
DAS 4-Plan Difficult Airway Algorithm - Visual Pocket Card PDF
A3 landscape, double-sided pocket card design using ReportLab
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.platypus import SimpleDocTemplate
from reportlab.pdfgen import canvas
from reportlab.lib.colors import HexColor, white, black
import os
OUTPUT = "/home/daytona/workspace/das-pocket-card/DAS_Airway_Pocket_Card.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
NAVY = HexColor("#1B3A6B") # DAS dark blue
PLAN_A_BG = HexColor("#1B3A6B") # Plan A header
PLAN_B_BG = HexColor("#1B6B3A") # Plan B header - green
PLAN_C_BG = HexColor("#6B4E1B") # Plan C header - amber/brown
PLAN_D_BG = HexColor("#8B0000") # Plan D header - dark red (emergency)
CICO_RED = HexColor("#CC0000")
SUCCEED_GREEN = HexColor("#2E7D32")
ARROW_RED = HexColor("#D32F2F")
LIGHT_BLUE = HexColor("#E8F0FE")
LIGHT_GREEN= HexColor("#E8F5E9")
LIGHT_AMBER= HexColor("#FFF8E1")
LIGHT_RED = HexColor("#FFEBEE")
BOX_GREY = HexColor("#F5F5F5")
MID_GREY = HexColor("#9E9E9E")
DARK_GREY = HexColor("#424242")
STOP_BG = HexColor("#FFF3E0")
STOP_BORDER= HexColor("#FF8F00")
WHITE = white
BLACK = black
PAGE_W, PAGE_H = A4 # 595.27 x 841.89 points (portrait A4)
# We'll create 2 pages: Page 1 = main algorithm, Page 2 = equipment checklists
def draw_rounded_rect(c, x, y, w, h, r, fill_color=None, stroke_color=None, line_width=1):
"""Draw a rounded rectangle."""
c.saveState()
if fill_color:
c.setFillColor(fill_color)
if stroke_color:
c.setStrokeColor(stroke_color)
c.setLineWidth(line_width)
else:
c.setStrokeColor(colors.transparent)
p = c.beginPath()
p.roundRect(x, y, w, h, r)
if fill_color and stroke_color:
c.drawPath(p, fill=1, stroke=1)
elif fill_color:
c.drawPath(p, fill=1, stroke=0)
elif stroke_color:
c.drawPath(p, fill=0, stroke=1)
c.restoreState()
def draw_arrow_down(c, x, y, length=14, color=ARROW_RED, width=2):
"""Draw a downward arrow from (x, y)."""
c.saveState()
c.setStrokeColor(color)
c.setFillColor(color)
c.setLineWidth(width)
# shaft
c.line(x, y, x, y - length + 4)
# arrowhead
p = c.beginPath()
p.moveTo(x - 4, y - length + 5)
p.lineTo(x + 4, y - length + 5)
p.lineTo(x, y - length)
p.close()
c.drawPath(p, fill=1, stroke=0)
c.restoreState()
def draw_arrow_right(c, x, y, length=20, color=SUCCEED_GREEN, width=2):
"""Draw a rightward arrow from (x, y)."""
c.saveState()
c.setStrokeColor(color)
c.setFillColor(color)
c.setLineWidth(width)
c.line(x, y, x + length - 4, y)
p = c.beginPath()
p.moveTo(x + length - 5, y - 4)
p.lineTo(x + length - 5, y + 4)
p.lineTo(x + length, y)
p.close()
c.drawPath(p, fill=1, stroke=0)
c.restoreState()
def wrap_text_in_box(c, text_lines, x, y, w, h, font_name, font_size, text_color, line_height=None):
"""Draw wrapped text lines centred vertically in a box."""
if line_height is None:
line_height = font_size + 2
total_h = len(text_lines) * line_height
start_y = y + h/2 + total_h/2 - font_size
c.setFont(font_name, font_size)
c.setFillColor(text_color)
for i, line in enumerate(text_lines):
c.drawCentredString(x + w/2, start_y - i * line_height, line)
def draw_plan_block(c, plan_label, plan_title, steps, outcome_text,
bx, by, bw, bh,
header_color, body_bg, outcome_color,
fail_label=None, succeed_label=None,
stop_think=None):
"""Draw one plan block with header, steps, and outcome."""
header_h = 22
margin = 6
# Header
draw_rounded_rect(c, bx, by + bh - header_h, bw, header_h, 4,
fill_color=header_color, stroke_color=None)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 9)
c.drawCentredString(bx + bw/2, by + bh - header_h + 7, f"{plan_label}: {plan_title}")
# Body background
draw_rounded_rect(c, bx, by, bw, bh - header_h, 4,
fill_color=body_bg, stroke_color=header_color, line_width=1)
# Steps
c.setFont("Helvetica", 7.5)
c.setFillColor(DARK_GREY)
ty = by + bh - header_h - margin - 8
for step in steps:
if step.startswith("**") and step.endswith("**"):
c.setFont("Helvetica-Bold", 7.5)
txt = step[2:-2]
else:
c.setFont("Helvetica", 7.5)
txt = step
# word-wrap simple
max_chars = int(bw / 4.2)
if len(txt) > max_chars:
# split at space near midpoint
mid = max_chars
while mid > 0 and txt[mid] != ' ':
mid -= 1
line1 = txt[:mid]
line2 = txt[mid+1:]
c.drawString(bx + margin, ty, "• " + line1)
ty -= 9
c.drawString(bx + margin + 6, ty, line2)
else:
c.drawString(bx + margin, ty, "• " + txt)
ty -= 10
# Outcome arrow label (succeed →)
if succeed_label:
c.setFont("Helvetica-BoldOblique", 7)
c.setFillColor(SUCCEED_GREEN)
c.drawCentredString(bx + bw/2, by + 4, succeed_label)
def draw_page1(c):
"""Draw Page 1: DAS 4-Plan Algorithm."""
W, H = PAGE_W, PAGE_H
margin = 10 * mm
# ── Background ──
c.setFillColor(HexColor("#FAFAFA"))
c.rect(0, 0, W, H, fill=1, stroke=0)
# ── Top header banner ──
c.setFillColor(NAVY)
c.rect(0, H - 28*mm, W, 28*mm, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 16)
c.drawCentredString(W/2, H - 14*mm, "DAS DIFFICULT AIRWAY ALGORITHM")
c.setFont("Helvetica", 9)
c.drawCentredString(W/2, H - 22*mm, "Management of Unanticipated Difficult Tracheal Intubation in Adults | DAS Guidelines 2015")
# ── Sub-header: key rule ──
draw_rounded_rect(c, margin, H - 35*mm, W - 2*margin, 6*mm, 3,
fill_color=HexColor("#FFF9C4"), stroke_color=HexColor("#F9A825"), line_width=1.5)
c.setFont("Helvetica-Bold", 8)
c.setFillColor(HexColor("#E65100"))
c.drawCentredString(W/2, H - 32*mm, "⚠ If in difficulty at ANY point — CALL FOR HELP immediately ⚠")
# ── Layout constants for the 4 plan boxes ──
col_w = (W - 2*margin - 3*4*mm) / 4 # 4 equal columns with 4mm gaps
box_h = 95*mm
box_y = H - 35*mm - 4*mm - box_h
gap = 4*mm
plans = [
{
"label": "PLAN A",
"title": "Facemask + Intubation",
"header": PLAN_A_BG,
"body": LIGHT_BLUE,
"steps": [
"**Optimise head/neck position**",
"Pre-oxygenate (EtO₂ >80%)",
"Adequate neuromuscular blockade",
"Direct OR video laryngoscopy",
"Max 3+1 attempts total",
"Use bougie as primary adjunct",
"External laryngeal manipulation",
"Remove cricoid pressure if view poor",
"Maintain oxygenation between attempts",
"**Confirm with waveform capnography**",
],
"fail": "▼ Declare FAILED INTUBATION",
"succeed": "✓ Confirmed intubation → PIM",
},
{
"label": "PLAN B",
"title": "SAD Insertion",
"header": PLAN_B_BG,
"body": LIGHT_GREEN,
"steps": [
"**2nd-generation SAD recommended**",
"(i-gel, ProSeal LMA, LMA Supreme)",
"Max 3 attempts",
"Change device or size if fails",
"Confirm ventilation with capnography",
"Oxygenate and ventilate",
],
"fail": "▼ Declare FAILED SAD ventilation",
"succeed": "✓ Succeed → STOP & THINK (see box)",
},
{
"label": "PLAN C",
"title": "Facemask Ventilation",
"header": PLAN_C_BG,
"body": LIGHT_AMBER,
"steps": [
"**Final attempt — oxygenate**",
"Ensure full NMB (paralysis opens airway)",
"2-person technique:",
" Person 1: Both hands on mask",
" Two-thumb jaw thrust grip",
" Person 2: Squeeze bag",
"Oropharyngeal + nasopharyngeal airway",
"Increase fresh gas flow",
],
"fail": "▼ DECLARE CICO",
"succeed": "✓ Succeed → Wake the patient",
},
{
"label": "PLAN D",
"title": "Emergency FONA",
"header": PLAN_D_BG,
"body": LIGHT_RED,
"steps": [
"**CICO = ACT NOW, no delay**",
"Continue O₂ via upper airway",
"Ensure full NMB",
"Extend the neck",
"**Laryngeal handshake:**",
"Stabilise larynx, feel CTM",
"**Scalpel cricothyroidotomy:**",
"Transverse stab incision CTM",
"Turn blade 90° (sharp edge down)",
"Bougie into trachea → 6mm tube",
"Inflate cuff, confirm capnography",
],
"fail": None,
"succeed": None,
},
]
for i, plan in enumerate(plans):
bx = margin + i * (col_w + gap)
by = box_y
# Header bar
draw_rounded_rect(c, bx, by + box_h - 20, col_w, 20, 4,
fill_color=plan["header"], stroke_color=None)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 8.5)
c.drawCentredString(bx + col_w/2, by + box_h - 13, plan["label"])
c.setFont("Helvetica", 7)
c.drawCentredString(bx + col_w/2, by + box_h - 22, plan["title"])
# Body
draw_rounded_rect(c, bx, by + 18, col_w, box_h - 20, 4,
fill_color=plan["body"],
stroke_color=plan["header"], line_width=1.2)
# Steps text
c.setFont("Helvetica", 7.2)
c.setFillColor(DARK_GREY)
ty = by + box_h - 30
for step in plan["steps"]:
if step.startswith("**") and step.endswith("**"):
c.setFont("Helvetica-Bold", 7.2)
txt = "• " + step[2:-2]
c.setFillColor(BLACK)
else:
c.setFont("Helvetica", 7.2)
txt = " " + step if step.startswith(" ") else "• " + step
c.setFillColor(DARK_GREY)
# simple wrap
max_w = col_w - 8
# Estimate char width ~4pt per char at 7.2
max_chars = int(max_w / 3.9)
if len(txt) > max_chars:
mid = max_chars
while mid > 0 and txt[mid] != ' ':
mid -= 1
if mid == 0:
mid = max_chars
c.drawString(bx + 5, ty, txt[:mid])
ty -= 8.5
c.drawString(bx + 10, ty, txt[mid:].lstrip())
else:
c.drawString(bx + 5, ty, txt)
ty -= 9.5
if ty < by + 22:
break
# Succeed label (green, bottom right area)
if plan["succeed"]:
c.setFont("Helvetica-Bold", 6.5)
c.setFillColor(SUCCEED_GREEN)
c.drawCentredString(bx + col_w/2, by + 22, plan["succeed"])
# Fail label below box
if plan["fail"]:
c.setFont("Helvetica-Bold", 7)
c.setFillColor(CICO_RED)
c.drawCentredString(bx + col_w/2, by + 10, plan["fail"])
# ── Downward arrows between plans ──
for i in range(3):
ax = margin + (i+1) * (col_w + gap) - gap/2
ay = box_y + box_h/2 + 8
draw_arrow_right(c, ax - 3, ay, length=gap + 4, color=ARROW_RED, width=1.5)
# ── STOP AND THINK box ──
stop_x = margin
stop_y = box_y - 52*mm
stop_w = (W - 2*margin) * 0.48
stop_h = 46*mm
draw_rounded_rect(c, stop_x, stop_y, stop_w, stop_h, 5,
fill_color=STOP_BG, stroke_color=STOP_BORDER, line_width=2)
# Header
c.setFillColor(STOP_BORDER)
c.setFont("Helvetica-Bold", 9)
c.drawCentredString(stop_x + stop_w/2, stop_y + stop_h - 10, "🛑 STOP AND THINK (After successful Plan B)")
c.setFont("Helvetica", 7.5)
c.setFillColor(DARK_GREY)
options = [
"Consider risks & benefits carefully before next step:",
"1. Wake the patient up (safest if elective surgery)",
"2. Intubate trachea via SAD (with fiberoptic scope)",
"3. Proceed with surgery under SAD anaesthesia",
"4. Planned tracheostomy or cricothyroidotomy",
"",
"Do NOT rush to intubate. Oxygenation is secured.",
]
oy = stop_y + stop_h - 22
for opt in options:
c.setFont("Helvetica-Bold" if opt.startswith("Consider") else "Helvetica", 7.5)
c.setFillColor(HexColor("#BF360C") if opt.startswith("Do NOT") else DARK_GREY)
c.drawString(stop_x + 8, oy, opt)
oy -= 9.5
# ── CICO box ──
cico_x = stop_x + stop_w + 4*mm
cico_y = stop_y
cico_w = W - 2*margin - stop_w - 4*mm
cico_h = stop_h
draw_rounded_rect(c, cico_x, cico_y, cico_w, cico_h, 5,
fill_color=HexColor("#FFCDD2"), stroke_color=CICO_RED, line_width=2.5)
c.setFillColor(CICO_RED)
c.setFont("Helvetica-Bold", 11)
c.drawCentredString(cico_x + cico_w/2, cico_y + cico_h - 13, "⚡ CICO DECLARED")
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(cico_x + cico_w/2, cico_y + cico_h - 24, "Can't Intubate, Can't Oxygenate")
c.setFont("Helvetica-Bold", 8)
c.setFillColor(DARK_GREY)
cico_steps = [
"→ CALL FOR HELP (shout loud)",
"→ Continue O₂ via upper airway",
"→ Declare to team: 'This is CICO'",
"→ Proceed IMMEDIATELY to Plan D",
"→ Scalpel cricothyroidotomy NOW",
"→ No further intubation attempts",
]
cy = cico_y + cico_h - 36
for s in cico_steps:
c.setFont("Helvetica-Bold" if "NOW" in s or "IMMEDIATELY" in s else "Helvetica", 7.5)
c.setFillColor(CICO_RED if "NOW" in s or "IMMEDIATELY" in s else DARK_GREY)
c.drawCentredString(cico_x + cico_w/2, cy, s)
cy -= 9.5
# ── Key Principles footer ──
fp_y = stop_y - 28*mm
draw_rounded_rect(c, margin, fp_y, W - 2*margin, 24*mm, 4,
fill_color=HexColor("#E3F2FD"), stroke_color=NAVY, line_width=1)
c.setFont("Helvetica-Bold", 8)
c.setFillColor(NAVY)
c.drawCentredString(W/2, fp_y + 18*mm, "KEY PRINCIPLES")
principles = [
("Oxygen always", "Supplement O₂ throughout — never stop trying to oxygenate"),
("Never repeat failure", "Change technique, device, or provider — not the same thing again"),
("Confirm with ETCO₂", "Waveform capnography is the gold standard for tube confirmation"),
("Max 3+1 attempts", "3 by same operator + 1 by senior; no more laryngoscopy after that"),
("Awake if CICO predicted", "If mask ventilation + intubation both predicted impossible → awake fibreoptic"),
("Post-event follow-up", "Airway alert form + written info to patient + notify GP"),
]
px = margin + 5
py = fp_y + 14*mm
col_width = (W - 2*margin - 10) / 3
for idx, (title, desc) in enumerate(principles):
col = idx % 3
row = idx // 3
tx = px + col * col_width
ty2 = py - row * 10*mm
c.setFont("Helvetica-Bold", 7.5)
c.setFillColor(NAVY)
c.drawString(tx, ty2, f"▸ {title}:")
c.setFont("Helvetica", 7)
c.setFillColor(DARK_GREY)
c.drawString(tx + 2, ty2 - 8, desc)
# ── Footer ──
c.setFont("Helvetica", 6.5)
c.setFillColor(MID_GREY)
c.drawCentredString(W/2, 8*mm, "Based on DAS 2015 Guidelines (Frerk C et al. Br J Anaesth 2015;115:827-848) | For educational use only | Always refer to current institutional protocols")
c.drawCentredString(W/2, 5*mm, "Page 1 of 2 — DAS Algorithm")
def draw_checklist_box(c, x, y, w, h, title, items, header_color, body_color, col_count=1):
"""Draw an equipment checklist box."""
hh = 16
draw_rounded_rect(c, x, y, w, h, 4, fill_color=header_color, stroke_color=None)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(x + w/2, y + h - 11, title)
draw_rounded_rect(c, x, y, w, h - hh, 4,
fill_color=body_color, stroke_color=header_color, line_width=1.2)
# Items in columns
item_count = len(items)
per_col = -(-item_count // col_count) # ceil divide
col_w = (w - 8) / col_count
start_y = y + h - hh - 5
for idx, item in enumerate(items):
col = idx // per_col
row = idx % per_col
ix = x + 4 + col * col_w
iy = start_y - row * 9.5
# checkbox
c.setStrokeColor(header_color)
c.setLineWidth(0.8)
c.rect(ix, iy - 1, 6, 6, fill=0, stroke=1)
c.setFont("Helvetica", 7)
c.setFillColor(DARK_GREY)
c.drawString(ix + 8, iy, item)
def draw_page2(c):
"""Draw Page 2: Equipment checklists + assessment tools."""
W, H = PAGE_W, PAGE_H
margin = 10 * mm
# Background
c.setFillColor(HexColor("#FAFAFA"))
c.rect(0, 0, W, H, fill=1, stroke=0)
# Header
c.setFillColor(NAVY)
c.rect(0, H - 22*mm, W, 22*mm, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 14)
c.drawCentredString(W/2, H - 12*mm, "DAS AIRWAY POCKET CARD — EQUIPMENT & ASSESSMENT")
c.setFont("Helvetica", 8)
c.drawCentredString(W/2, H - 19*mm, "Checklists for Plans A–D | LEMON | ROMAN | Cricothyroid Membrane Landmark")
# Layout: two columns
col_w = (W - 2*margin - 4*mm) / 2
left_x = margin
right_x = margin + col_w + 4*mm
top_y = H - 26*mm
# ── PLAN A Equipment ──
plan_a_items = [
"Laryngoscope (Mac 3 & 4, Miller)",
"Video laryngoscope (e.g. C-MAC, McGrath)",
"ETT sizes 6.0, 7.0, 8.0 (cuffed)",
"Gum elastic bougie",
"10mL syringe (cuff inflation)",
"Magill's forceps",
"Stylet/introducer",
"Tape/tube tie for securing ETT",
"CO₂ detector / waveform capnograph",
"Suction (Yankauer) — working",
"Pre-oxygenation mask + circuit",
"NMB agent (suxamethonium/rocuronium)",
"Stethoscope",
"Monitoring: SpO₂, ETCO₂, ECG, NIBP",
]
a_h = 52*mm
draw_checklist_box(c, left_x, top_y - a_h, col_w, a_h,
"PLAN A — Intubation Equipment", plan_a_items,
PLAN_A_BG, LIGHT_BLUE, col_count=2)
# ── PLAN B Equipment ──
plan_b_items = [
"i-gel (sizes 3, 4, 5)",
"ProSeal LMA or LMA Supreme",
"Classic LMA (backup)",
"Lubricant (water-based)",
"Syringe for cuff inflation",
"Gastric drainage tube (60mL syringe)",
"Tape to secure SAD",
"Capnograph connection",
]
b_h = 33*mm
draw_checklist_box(c, left_x, top_y - a_h - 4*mm - b_h, col_w, b_h,
"PLAN B — SAD / Supraglottic Airway Equipment", plan_b_items,
PLAN_B_BG, LIGHT_GREEN, col_count=2)
# ── PLAN C Equipment ──
plan_c_items = [
"Face mask (correct size)",
"Oropharyngeal (Guedel) airways: sizes 3, 4",
"Nasopharyngeal airway + lubricant",
"Self-inflating bag (Ambu)",
"2nd operator for 2-person technique",
"Oxygen source (100%)",
]
c_h = 28*mm
draw_checklist_box(c, left_x, top_y - a_h - 4*mm - b_h - 4*mm - c_h, col_w, c_h,
"PLAN C — Facemask Ventilation Equipment", plan_c_items,
PLAN_C_BG, LIGHT_AMBER, col_count=2)
# ── PLAN D Equipment ──
plan_d_items = [
"Scalpel — No. 10 blade",
"Bougie (gum elastic, 60cm)",
"Cuffed ETT 6.0mm ID",
"10mL syringe (cuff inflation)",
"Lubricant for tube",
"Tape/tie for securing tube",
"Capnograph (confirm position)",
"Suction available",
"Skin prep / swabs",
"Assistant + good lighting",
]
d_h = 40*mm
draw_checklist_box(c, left_x, top_y - a_h - 4*mm - b_h - 4*mm - c_h - 4*mm - d_h, col_w, d_h,
"PLAN D — Emergency FONA / Scalpel Cricothyroidotomy", plan_d_items,
PLAN_D_BG, LIGHT_RED, col_count=2)
# RIGHT COLUMN ──────────────────────────────────────────────────────────
# ── LEMON ──
lemon_items_text = [
("L", "Look externally",
"Gestalt: facial trauma, beard, large tongue, obesity, small mouth"),
("E", "Evaluate 3-3-2",
"3 fingers between incisors | 3 fingers floor of mouth | 2 fingers hyoid-to-notch"),
("M", "Mallampati",
"Class I/II = easy | Class III = moderate | Class IV = predicted difficult"),
("O", "Obstruction/Obesity",
"Supraglottic mass, Ludwig's, tonsil, obese (BMI >35), OSA"),
("N", "Neck mobility",
"Can they flex/extend? Fixed C-spine, halo, collar = very difficult"),
]
lemon_h = 48*mm
draw_rounded_rect(c, right_x, top_y - lemon_h, col_w, lemon_h, 4,
fill_color=NAVY, stroke_color=None)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 8.5)
c.drawCentredString(right_x + col_w/2, top_y - 12, "LEMON — Predict Difficult Intubation")
draw_rounded_rect(c, right_x, top_y - lemon_h, col_w, lemon_h - 16, 4,
fill_color=HexColor("#E8EAF6"), stroke_color=NAVY, line_width=1)
ly = top_y - 26
for letter, title, desc in lemon_items_text:
# Letter badge
draw_rounded_rect(c, right_x + 5, ly - 4, 12, 12, 2,
fill_color=NAVY, stroke_color=None)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(right_x + 11, ly + 1, letter)
c.setFont("Helvetica-Bold", 7.5)
c.setFillColor(NAVY)
c.drawString(right_x + 20, ly + 4, title)
c.setFont("Helvetica", 6.8)
c.setFillColor(DARK_GREY)
c.drawString(right_x + 20, ly - 4, desc)
ly -= 14
# ── ROMAN ──
roman_items = [
("R", "Radiation/Resistance",
"Neck radiation hx | Asthma/COPD/ARDS (high pressures needed)"),
("O", "Obstruction/Obesity/OSA",
"Supraglottic mass | BMI >35 | OSA (redundant pharyngeal tissue)"),
("M", "Mallampati/Mask seal/Male",
"Class III-IV | Beard/facial trauma (seal failure) | Male sex"),
("A", "Age >55",
"Physiological ageing, decreased pharyngeal tone"),
("N", "No teeth (edentulous)",
"'Teeth IN to ventilate, teeth OUT to intubate'"),
]
roman_h = 48*mm
ry = top_y - lemon_h - 4*mm
draw_rounded_rect(c, right_x, ry - roman_h, col_w, roman_h, 4,
fill_color=PLAN_B_BG, stroke_color=None)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 8.5)
c.drawCentredString(right_x + col_w/2, ry - 12, "ROMAN — Predict Difficult Mask Ventilation")
draw_rounded_rect(c, right_x, ry - roman_h, col_w, roman_h - 16, 4,
fill_color=HexColor("#E8F5E9"), stroke_color=PLAN_B_BG, line_width=1)
ry2 = ry - 26
for letter, title, desc in roman_items:
draw_rounded_rect(c, right_x + 5, ry2 - 4, 12, 12, 2,
fill_color=PLAN_B_BG, stroke_color=None)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(right_x + 11, ry2 + 1, letter)
c.setFont("Helvetica-Bold", 7.5)
c.setFillColor=PLAN_B_BG
c.setFillColor(HexColor("#1B5E20"))
c.drawString(right_x + 20, ry2 + 4, title)
c.setFont("Helvetica", 6.8)
c.setFillColor(DARK_GREY)
c.drawString(right_x + 20, ry2 - 4, desc)
ry2 -= 14
# ── Cricothyroid Membrane Landmark Diagram ──
ctm_y = ry - roman_h - 4*mm
ctm_h = 62*mm
draw_rounded_rect(c, right_x, ctm_y - ctm_h, col_w, ctm_h, 4,
fill_color=HexColor("#FCE4EC"), stroke_color=PLAN_D_BG, line_width=1.5)
c.setFillColor(PLAN_D_BG)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(right_x + col_w/2, ctm_y - 11,
"CTM LANDMARK — Laryngeal Handshake")
# Simple neck diagram
cx = right_x + col_w/2
cy_base = ctm_y - ctm_h + 10
# Neck outline (simple rectangle)
c.setStrokeColor(HexColor("#795548"))
c.setLineWidth(1.5)
c.roundRect(cx - 22, cy_base + 2, 44, 40, 5, fill=0, stroke=1)
c.setFillColor(HexColor("#FFCCBC"))
c.roundRect(cx - 22, cy_base + 2, 44, 40, 5, fill=1, stroke=1)
# Thyroid cartilage label
c.setFillColor(HexColor("#6D4C41"))
c.setFont("Helvetica-Bold", 7)
c.drawCentredString(cx, cy_base + 37, "Thyroid Cartilage")
# CTM zone (coloured)
c.setFillColor(HexColor("#FF5722"))
c.rect(cx - 12, cy_base + 22, 24, 8, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 6.5)
c.drawCentredString(cx, cy_base + 27, "CTM")
# Cricoid label
c.setFillColor(HexColor("#6D4C41"))
c.setFont("Helvetica-Bold", 7)
c.drawCentredString(cx, cy_base + 17, "Cricoid Cartilage")
# Tracheal rings
for i in range(3):
c.setStrokeColor(HexColor("#795548"))
c.setLineWidth(0.8)
c.rect(cx - 10, cy_base + 5 + i*3, 20, 3, fill=0, stroke=1)
# Arrow to CTM
c.setStrokeColor(CICO_RED)
c.setFillColor(CICO_RED)
c.setLineWidth(1.5)
c.line(cx + 30, cy_base + 26, cx + 14, cy_base + 26)
# arrowhead
p = c.beginPath()
p.moveTo(cx + 14, cy_base + 23)
p.lineTo(cx + 14, cy_base + 29)
p.lineTo(cx + 10, cy_base + 26)
p.close()
c.drawPath(p, fill=1, stroke=0)
c.setFont("Helvetica-Bold", 7)
c.drawString(cx + 31, cy_base + 24, "← Incise here")
# Handshake steps
c.setFont("Helvetica-Bold", 7.5)
c.setFillColor(PLAN_D_BG)
c.drawString(right_x + 5, ctm_y - 18, "Laryngeal Handshake Technique:")
steps_ctm = [
"1. Thumb + middle finger grip thyroid cartilage",
"2. Index finger slides down to feel CTM dip",
"3. CTM = soft tissue between thyroid & cricoid",
"4. Horizontal stab incision through CTM",
"5. Bougie → 6mm tube → confirm with ETCO₂",
]
c.setFont("Helvetica", 7)
c.setFillColor(DARK_GREY)
hy = ctm_y - 27
for s in steps_ctm:
c.drawString(right_x + 5, hy, s)
hy -= 9
# ── Mallampati guide ──
mall_y = ctm_y - ctm_h - 4*mm
mall_h = 36*mm
draw_rounded_rect(c, right_x, mall_y - mall_h, col_w, mall_h, 4,
fill_color=HexColor("#F3E5F5"), stroke_color=HexColor("#7B1FA2"), line_width=1.2)
c.setFillColor(HexColor("#7B1FA2"))
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(right_x + col_w/2, mall_y - 11, "MALLAMPATI CLASSIFICATION")
classes = [
("I", "Soft palate, uvula, pillars all visible", "✓ Easy", HexColor("#2E7D32")),
("II", "Soft palate + uvula visible", "✓ Usually easy", HexColor("#558B2F")),
("III", "Soft palate, base of uvula only", "⚠ Likely difficult", HexColor("#E65100")),
("IV", "Hard palate only — tongue fills mouth", "✗ Very difficult", CICO_RED),
]
my = mall_y - 24
for cls, vis, pred, col in classes:
draw_rounded_rect(c, right_x + 5, my - 3, 12, 10, 2,
fill_color=col, stroke_color=None)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 7)
c.drawCentredString(right_x + 11, my + 2, cls)
c.setFont("Helvetica", 6.8)
c.setFillColor(DARK_GREY)
c.drawString(right_x + 20, my + 3, vis)
c.setFont("Helvetica-Bold", 6.8)
c.setFillColor(col)
c.drawString(right_x + 20, my - 4, pred)
my -= 14
# Footer
c.setFont("Helvetica", 6.5)
c.setFillColor(MID_GREY)
c.drawCentredString(W/2, 8*mm, "Based on DAS 2015 Guidelines (Frerk C et al. Br J Anaesth 2015;115:827-848) | For educational use only | Always refer to current institutional protocols")
c.drawCentredString(W/2, 5*mm, "Page 2 of 2 — Equipment Checklists & Assessment Tools")
# ── Generate PDF ─────────────────────────────────────────────────────────────
c = canvas.Canvas(OUTPUT, pagesize=A4)
c.setTitle("DAS Difficult Airway Pocket Card")
c.setAuthor("Orris Medical Education")
c.setSubject("DAS 2015 Difficult Airway Algorithm – Anaesthesia Resident Reference")
draw_page1(c)
c.showPage()
draw_page2(c)
c.showPage()
c.save()
print(f"PDF generated: {OUTPUT}")
import os
size = os.path.getsize(OUTPUT)
print(f"File size: {size:,} bytes ({size/1024:.1f} KB)")
cd /home/daytona/workspace/das-pocket-card && python generate_das_card.py 2>&1
~/das-pocket-card/generate_das_card.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/das-pocket-card/generate_das_card.py'
cd /home/daytona/workspace/das-pocket-card && python generate_das_card.py 2>&1
cd /home/daytona/workspace/das-pocket-card && python -c " from pypdf import PdfR…
DAS Airway Pocket Card
PDF Document · PDF