Gum elastic bougie References - millers, morgan, baheti, barash, all anesthesia standard textbooks
| Feature | Details |
|---|---|
| Material | Originally woven polyester (Dacron) coated with polyurethane resin ("gum elastic"); modern versions may be polyethylene (single-use) |
| Adult size (curved tip) | 60 cm long, 15 Fr (5 mm) with a 40-degree coudé (angled) tip 3.5 cm from the distal end |
| Adult size (straight) | 70 cm long |
| Pediatric version | 70 cm long, 10 Fr (straight); accommodates a 4.0-mm ETT |
| ET tube compatibility | Adult version accommodates ETT ≥ 5.5 mm ID |
| Variants | FROVA Introducer (Cook Critical Care) - hollow lumen allowing CO₂ detection and, in principle, temporary ventilation (though oxygen insufflation is discouraged due to barotrauma risk) |
"The presence of blood and vomitus rarely prevents placement of the bougie into the trachea." - Roberts & Hedges, p. 127
| Problem | Cause | Solution |
|---|---|---|
| Bougie won't advance past 40 cm | Tip lodged on anterior tracheal wall | Withdraw slightly, rotate 90° clockwise to move tip to patient's right |
| ETT won't railroad over bougie | Tip caught on right arytenoid cartilage (most common) | Withdraw tube 2 cm, rotate 90° counterclockwise, re-advance |
| Bougie passes >40 cm freely | Esophageal placement | Withdraw, reshape to 60°, reattempt |
| Bougie seems "too floppy" | Introducer entering at an angle above line of vision (operator too close to patient) | Adjust operator position so introducer aligns with line of sight |
| Difficulty railroading ETT | Laryngoscope removed prematurely | Keep laryngoscope in place while railroading; soft tissue weight deflects ETT posteriorly |
| Full-length lubrication | Slippery, hard to handle | Lubricate only distal end of bougie; always lubricate the ETT |
"It is recommended that all anesthesiologists learn this technique and receive regular training to avoid fading of skill." - Miller's Anesthesia 10e, p. 5960
Add diagram from standard anaesthesia textbooks



| Type | Length | Fr | Tip | Use |
|---|---|---|---|---|
| GEB curved tip (Eschmann) | 60 cm | 15 Fr | 40° coudé | Adult - difficult airway |
| GEB straight | 70 cm | 15 Fr | Straight | Adult - standard |
| Pediatric (Eschmann) | 70 cm | 10 Fr | Straight | Accommodates ≥4.0 mm ETT |
| Flectrach (single-use) | 60 cm | 15 Fr | Coudé | Adult - disposable |
| FROVA (hollow lumen) | 60 cm | — | Coudé | CO₂ detection, optional stiffening stylet |
Give the above content regarding gum elastic bougie in handwrtten form for 10 marks question
ls /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace/geb-answer
mkdir -p /tmp/workspace/geb-answer && python3 -c " from PIL import Image, ImageDraw, ImageFont import os print('PIL available') # Check for fonts import subprocess result = subprocess.run(['fc-list', ':family=DejaVu'], capture_output=True, text=True) print(result.stdout[:300]) "
python3 -c " import os, glob # find handwriting-like fonts fonts = glob.glob('/usr/share/fonts/**/*.ttf', recursive=True) + glob.glob('/usr/share/fonts/**/*.otf', recursive=True) for f in fonts[:40]: print(f) "
pip install reportlab --quiet --user 2>/dev/null; python3 -c "from reportlab.platypus import SimpleDocTemplate; print('reportlab OK')"
~/geb-answer/generate_geb.py
#!/usr/bin/env python3
"""
Gum Elastic Bougie - Handwritten-style 10-mark exam answer PDF
Uses reportlab canvas for full control over ruled lines, blue ink, handwriting font feel
"""
import os, math, urllib.request, io
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import mm, cm
from reportlab.lib.colors import HexColor, black, white, Color
from reportlab.pdfgen import canvas
from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, Table,
TableStyle, KeepTogether, HRFlowable)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.graphics.shapes import Drawing, Rect, Circle, Line, String, Polygon
from reportlab.graphics import renderPDF
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from PIL import Image as PILImage
# ── Colours ────────────────────────────────────────────────────────────────────
INK = HexColor('#1a237e') # deep blue ink
INK_LIGHT = HexColor('#1565C0') # medium blue for body text
INK_SUB = HexColor('#0d47a1') # for subheadings
RED_INK = HexColor('#b71c1c') # red for emphasis
RULE_CLR = HexColor('#bbdefb') # ruled-line light blue
MARGIN_CLR = HexColor('#ef9a9a') # red margin line
BG_CLR = HexColor('#fffde7') # cream/off-white paper
HEADER_CLR = HexColor('#e3f2fd') # header band
W, H = A4 # 595 x 842 pt
LMARGIN = 22*mm
RMARGIN = 15*mm
TMARGIN = 25*mm
BMARGIN = 20*mm
LINE_H = 8*mm # ruled line spacing
FONT_BODY = 'Helvetica'
FONT_BOLD = 'Helvetica-Bold'
FONT_OBL = 'Helvetica-Oblique'
OUT = '/tmp/workspace/geb-answer/GumElasticBougie_10marks.pdf'
# ── Page background painter ────────────────────────────────────────────────────
def draw_paper(c, page_no, total_pages):
"""Draw ruled notebook paper background on each page."""
c.saveState()
# cream background
c.setFillColor(BG_CLR)
c.rect(0, 0, W, H, fill=1, stroke=0)
# ruled lines
c.setStrokeColor(RULE_CLR)
c.setLineWidth(0.4)
y = H - TMARGIN
while y > BMARGIN:
c.line(0, y, W, y)
y -= LINE_H
# red margin line
c.setStrokeColor(MARGIN_CLR)
c.setLineWidth(0.8)
c.line(LMARGIN - 3*mm, 0, LMARGIN - 3*mm, H)
# header band
c.setFillColor(HEADER_CLR)
c.rect(0, H - TMARGIN + 2, W, TMARGIN - 2, fill=1, stroke=0)
# header text
c.setFillColor(INK)
c.setFont(FONT_BOLD, 9)
c.drawString(LMARGIN - 2*mm, H - TMARGIN + 8, 'ANAESTHESIA | AIRWAY MANAGEMENT')
c.setFont(FONT_BODY, 9)
c.drawRightString(W - RMARGIN, H - TMARGIN + 8, f'Page {page_no} of {total_pages}')
# bottom footer
c.setFillColor(HexColor('#555555'))
c.setFont(FONT_BODY, 7)
c.drawCentredString(W/2, BMARGIN - 8, 'Ref: Miller\'s Anesthesia 10e | Barash 9e | Morgan & Mikhail 7e | Roberts & Hedges')
c.restoreState()
# ── Text helper ────────────────────────────────────────────────────────────────
class Writer:
"""Stateful line-writer for handwriting-style layout."""
def __init__(self, c_obj, pages_ref):
self.c = c_obj
self.pages = pages_ref
self.page_no = 1
self.x = LMARGIN
self.y = H - TMARGIN - LINE_H
def _check_newpage(self, extra=0):
if self.y - extra < BMARGIN + LINE_H:
self.c.showPage()
self.page_no += 1
self.pages.append(self.page_no)
draw_paper(self.c, self.page_no, '?')
self.y = H - TMARGIN - LINE_H
def blank(self, n=1):
for _ in range(n):
self._check_newpage()
self.y -= LINE_H
def heading1(self, txt):
"""Big underlined heading — main title."""
self._check_newpage(LINE_H * 2)
self.c.saveState()
self.c.setFont(FONT_BOLD, 15)
self.c.setFillColor(INK)
self.c.drawString(self.x, self.y, txt)
tw = self.c.stringWidth(txt, FONT_BOLD, 15)
self.c.setStrokeColor(INK)
self.c.setLineWidth(1.2)
self.c.line(self.x, self.y - 2, self.x + tw, self.y - 2)
self.c.restoreState()
self.y -= LINE_H * 1.6
def heading2(self, txt):
"""Section heading - bold blue, underlined."""
self._check_newpage(LINE_H * 1.5)
self.c.saveState()
self.c.setFont(FONT_BOLD, 12)
self.c.setFillColor(INK_SUB)
tw = self.c.stringWidth(txt, FONT_BOLD, 12)
# small filled rect behind heading
self.c.setFillColor(HexColor('#e8eaf6'))
self.c.rect(self.x - 2, self.y - 3, tw + 8, LINE_H - 1, fill=1, stroke=0)
self.c.setFillColor(INK_SUB)
self.c.drawString(self.x + 2, self.y, txt)
self.c.restoreState()
self.y -= LINE_H * 1.3
def heading3(self, txt):
"""Sub-section heading."""
self._check_newpage(LINE_H)
self.c.saveState()
self.c.setFont(FONT_BOLD, 11)
self.c.setFillColor(RED_INK)
self.c.drawString(self.x, self.y, txt)
self.c.restoreState()
self.y -= LINE_H * 1.1
def body(self, txt, indent=0, bold=False, color=None):
"""Wrap and print body text."""
font = FONT_BOLD if bold else FONT_BODY
fsize = 11
col = color or INK_LIGHT
avail = W - self.x - RMARGIN - indent
words = txt.split()
line = ''
for word in words:
test = (line + ' ' + word).strip()
if self.c.stringWidth(test, font, fsize) < avail:
line = test
else:
self._check_newpage()
self.c.setFont(font, fsize)
self.c.setFillColor(col)
self.c.drawString(self.x + indent, self.y, line)
self.y -= LINE_H
line = word
if line:
self._check_newpage()
self.c.setFont(font, fsize)
self.c.setFillColor(col)
self.c.drawString(self.x + indent, self.y, line)
self.y -= LINE_H
def bullet(self, txt, sym='\u2022', indent=5*mm):
"""Bullet point."""
self._check_newpage()
self.c.saveState()
self.c.setFont(FONT_BOLD, 11)
self.c.setFillColor(INK)
self.c.drawString(self.x + indent, self.y, sym)
self.c.restoreState()
self.body(txt, indent=indent + 5*mm)
def sub_bullet(self, txt, indent=10*mm):
self._check_newpage()
self.c.saveState()
self.c.setFont(FONT_BODY, 10)
self.c.setFillColor(HexColor('#555555'))
self.c.drawString(self.x + indent, self.y, '\u25e6')
self.c.restoreState()
self.body(txt, indent=indent + 5*mm)
def keyvalue(self, key, val):
"""Key: value line."""
self._check_newpage()
self.c.saveState()
self.c.setFont(FONT_BOLD, 11)
self.c.setFillColor(INK)
kw = self.c.stringWidth(key + ': ', FONT_BOLD, 11)
self.c.drawString(self.x + 5*mm, self.y, key + ':')
self.c.setFont(FONT_BODY, 11)
self.c.setFillColor(INK_LIGHT)
self.c.drawString(self.x + 5*mm + kw, self.y, val)
self.c.restoreState()
self.y -= LINE_H
def hline(self):
self._check_newpage()
self.c.saveState()
self.c.setStrokeColor(HexColor('#9fa8da'))
self.c.setLineWidth(0.6)
self.c.line(self.x, self.y + 4, W - RMARGIN, self.y + 4)
self.c.restoreState()
self.y -= 2
def reserve_space(self, h_mm):
"""Reserve vertical space (for a diagram)."""
pts = h_mm * mm
self._check_newpage(pts)
top = self.y
self.y -= pts
return top # top-left y for drawing
def draw_image_from_url(self, url, h_mm=60, caption=''):
"""Download and embed an image."""
pts = h_mm * mm
self._check_newpage(pts + (LINE_H if caption else 0))
try:
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
data = urllib.request.urlopen(req, timeout=10).read()
img_io = io.BytesIO(data)
pil = PILImage.open(img_io)
pil = pil.convert('RGB')
iw, ih = pil.size
aspect = iw / ih
draw_w = min((W - LMARGIN - RMARGIN), aspect * pts)
draw_h = draw_w / aspect
# centre horizontally
x_img = self.x + (W - LMARGIN - RMARGIN - draw_w) / 2
img_io.seek(0)
self.c.drawImage(
urllib.request.urlopen(url),
x_img, self.y - draw_h, draw_w, draw_h,
preserveAspectRatio=True
)
self.y -= draw_h + 2
if caption:
self.c.setFont(FONT_OBL, 8.5)
self.c.setFillColor(HexColor('#424242'))
self.c.drawCentredString(W/2, self.y, caption)
self.y -= LINE_H
except Exception as e:
# fallback: draw a placeholder box with label
box_h = pts
self.c.setStrokeColor(HexColor('#90a4ae'))
self.c.setFillColor(HexColor('#eceff1'))
self.c.rect(self.x, self.y - box_h, W - LMARGIN - RMARGIN, box_h, fill=1, stroke=1)
self.c.setFont(FONT_OBL, 9)
self.c.setFillColor(HexColor('#546e7a'))
self.c.drawCentredString(W/2, self.y - box_h/2, f'[Diagram: {caption}]')
self.y -= box_h + 2
if caption:
self.c.setFont(FONT_OBL, 8.5)
self.c.setFillColor(HexColor('#424242'))
self.c.drawCentredString(W/2, self.y, caption)
self.y -= LINE_H
def draw_local_image(self, path, h_mm=60, caption=''):
"""Embed a local image file."""
pts = h_mm * mm
self._check_newpage(pts + (LINE_H * 1.5 if caption else 0))
try:
pil = PILImage.open(path).convert('RGB')
iw, ih = pil.size
aspect = iw / ih
avail_w = W - LMARGIN - RMARGIN
draw_w = min(avail_w, aspect * pts)
draw_h = draw_w / aspect
x_img = self.x + (avail_w - draw_w) / 2
self.c.drawImage(path, x_img, self.y - draw_h,
draw_w, draw_h, preserveAspectRatio=True)
self.y -= draw_h + 3
if caption:
self.c.setFont(FONT_OBL, 8.5)
self.c.setFillColor(HexColor('#424242'))
self.c.drawCentredString(W/2, self.y, caption)
self.y -= LINE_H
except Exception as e:
box_h = pts
self.c.setStrokeColor(HexColor('#90a4ae'))
self.c.setFillColor(HexColor('#eceff1'))
self.c.rect(self.x, self.y - box_h,
W - LMARGIN - RMARGIN, box_h, fill=1, stroke=1)
self.c.setFont(FONT_OBL, 9)
self.c.setFillColor(HexColor('#546e7a'))
self.c.drawCentredString(W/2, self.y - box_h/2,
f'[Diagram: {caption}] ({e})')
self.y -= box_h + 3
if caption:
self.c.setFont(FONT_OBL, 8.5)
self.c.setFillColor(HexColor('#424242'))
self.c.drawCentredString(W/2, self.y, caption)
self.y -= LINE_H
# ── Draw inline table ──────────────────────────────────────────────────────────
def draw_table(c, w_obj, rows, col_widths, header_row=True):
"""Simple manual table drawn on canvas."""
fsize = 9.5
row_h = LINE_H * 1.1
total_w = sum(col_widths)
table_h = len(rows) * row_h
w_obj._check_newpage(table_h + LINE_H)
y_top = w_obj.y
x0 = w_obj.x
for ri, row in enumerate(rows):
y_row = y_top - ri * row_h
is_hdr = (ri == 0 and header_row)
# background
c.setFillColor(HexColor('#e8eaf6') if is_hdr else (HexColor('#f5f5f5') if ri % 2 == 0 else white))
c.rect(x0, y_row - row_h + 3, total_w, row_h, fill=1, stroke=0)
# text
x_col = x0
for ci, cell in enumerate(row):
font = FONT_BOLD if is_hdr else FONT_BODY
c.setFont(font, fsize)
c.setFillColor(INK if is_hdr else INK_LIGHT)
c.drawString(x_col + 2, y_row - row_h/2 - fsize/3 + 4, str(cell))
x_col += col_widths[ci]
# grid lines
c.setStrokeColor(HexColor('#9fa8da'))
c.setLineWidth(0.4)
c.rect(x0, y_row - row_h + 3, total_w, row_h, fill=0, stroke=1)
w_obj.y -= table_h + LINE_H * 0.5
# ── Download diagram images ────────────────────────────────────────────────────
IMG_DIR = '/tmp/workspace/geb-answer/imgs'
os.makedirs(IMG_DIR, exist_ok=True)
IMGS = {
'scalpel_bougie': 'https://cdn.orris.care/cdss_images/a19959bddb0bf08b96fd8057e597a6c55696aef08d2d7b23b02f3eb163e04bcb.png',
'ctm_anatomy': 'https://cdn.orris.care/cdss_images/ea0344161d411c6b17c65e63077fff13be396ffe0e3c19acea6ad27ac394d39d.png',
'arytenoid': 'https://cdn.orris.care/cdss_images/9a4e43dce9125a2ded39c1f7fd585e32d90b374b3f75934efb2912bc42eac996.png',
}
downloaded = {}
for name, url in IMGS.items():
fpath = f'{IMG_DIR}/{name}.png'
try:
if not os.path.exists(fpath):
req = urllib.request.Request(url, headers={'User-Agent':'Mozilla/5.0'})
data = urllib.request.urlopen(req, timeout=15).read()
with open(fpath, 'wb') as f:
f.write(data)
downloaded[name] = fpath
print(f' Downloaded: {name}')
except Exception as e:
print(f' FAILED {name}: {e}')
print('Image downloads done:', list(downloaded.keys()))
~/geb-answer/build_geb_pdf.py
#!/usr/bin/env python3
"""
Gum Elastic Bougie - Handwritten-style 10-mark exam answer PDF
"""
import os, io, urllib.request
from PIL import Image as PILImage
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import mm
from reportlab.lib.colors import HexColor, white
from reportlab.pdfgen import canvas as rl_canvas
W, H = A4
LMARGIN = 25*mm
RMARGIN = 15*mm
TMARGIN = 28*mm
BMARGIN = 22*mm
LINE_H = 8.2*mm
TXT_W = W - LMARGIN - RMARGIN
INK = HexColor('#1a237e')
INK_B = HexColor('#0d47a1')
INK_BODY = HexColor('#1565c0')
RED = HexColor('#b71c1c')
RULE_CLR = HexColor('#bbdefb')
MARGIN_CLR = HexColor('#ef9a9a')
BG = HexColor('#fffde7')
HDR_BG = HexColor('#e3f2fd')
TBL_HDR = HexColor('#e8eaf6')
TBL_ALT = HexColor('#f5f5f5')
GREY_TXT = HexColor('#424242')
FB = 'Helvetica-Bold'
FN = 'Helvetica'
FI = 'Helvetica-Oblique'
IMG_URLS = {
'scalpel': 'https://cdn.orris.care/cdss_images/a19959bddb0bf08b96fd8057e597a6c55696aef08d2d7b23b02f3eb163e04bcb.png',
'anatomy': 'https://cdn.orris.care/cdss_images/ea0344161d411c6b17c65e63077fff13be396ffe0e3c19acea6ad27ac394d39d.png',
'arytenoid': 'https://cdn.orris.care/cdss_images/9a4e43dce9125a2ded39c1f7fd585e32d90b374b3f75934efb2912bc42eac996.png',
}
IMG_DIR = '/tmp/workspace/geb-answer/imgs'
os.makedirs(IMG_DIR, exist_ok=True)
local_imgs = {}
for k, url in IMG_URLS.items():
p = f'{IMG_DIR}/{k}.png'
if not os.path.exists(p):
try:
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
data = urllib.request.urlopen(req, timeout=15).read()
with open(p,'wb') as f: f.write(data)
except Exception as e:
print(f' img fail {k}: {e}'); continue
local_imgs[k] = p
print(f' ready: {k}')
# ── Canvas wrapper ─────────────────────────────────────────────────────────────
class Page:
def __init__(self, c):
self.c = c
self.page_no = 0
self.y = 0
self.new_page()
def new_page(self):
if self.page_no > 0:
self.c.showPage()
self.page_no += 1
self.y = H - TMARGIN - LINE_H
self._draw_bg()
def _draw_bg(self):
c = self.c
c.setFillColor(BG); c.rect(0,0,W,H,fill=1,stroke=0)
# ruled lines
c.setStrokeColor(RULE_CLR); c.setLineWidth(0.4)
y = H - TMARGIN
while y > BMARGIN - 5:
c.line(0, y, W, y); y -= LINE_H
# red margin
c.setStrokeColor(MARGIN_CLR); c.setLineWidth(0.9)
c.line(LMARGIN-4*mm, 0, LMARGIN-4*mm, H)
# header band
c.setFillColor(HDR_BG)
c.rect(0, H-TMARGIN+1, W, TMARGIN-1, fill=1, stroke=0)
c.setFillColor(INK); c.setFont(FB, 9.5)
c.drawString(LMARGIN, H-TMARGIN+9, 'ANAESTHESIA | AIRWAY MANAGEMENT | 10 MARKS')
c.setFont(FN, 8.5); c.setFillColor(HexColor('#555555'))
c.drawRightString(W-RMARGIN, H-TMARGIN+9, f'Page {self.page_no}')
# footer
c.setFont(FI, 7); c.setFillColor(HexColor('#757575'))
c.drawCentredString(W/2, BMARGIN-10,
"Ref: Miller's Anesthesia 10e | Barash 9e | Morgan & Mikhail 7e | Roberts & Hedges")
def check(self, need=LINE_H):
if self.y - need < BMARGIN + LINE_H:
self.new_page()
# ── text primitives ────────────────────────────────────────────────────────
def h1(self, txt):
self.check(LINE_H*2)
c = self.c
c.setFont(FB, 15); c.setFillColor(INK)
c.drawString(LMARGIN, self.y, txt)
tw = c.stringWidth(txt, FB, 15)
c.setStrokeColor(INK); c.setLineWidth(1.3)
c.line(LMARGIN, self.y-2, LMARGIN+tw, self.y-2)
self.y -= LINE_H*1.8
def h2(self, txt):
self.check(LINE_H*1.6)
c = self.c; tw = c.stringWidth(txt, FB, 12)
c.setFillColor(TBL_HDR)
c.rect(LMARGIN-2, self.y-3, tw+10, LINE_H-1, fill=1, stroke=0)
c.setFont(FB, 12); c.setFillColor(INK_B)
c.drawString(LMARGIN+2, self.y, txt)
self.y -= LINE_H*1.4
def h3(self, txt):
self.check(LINE_H*1.3)
c = self.c
c.setFont(FB, 11); c.setFillColor(RED)
c.drawString(LMARGIN+2*mm, self.y, txt)
self.y -= LINE_H*1.1
def text(self, txt, indent=0, bold=False, color=None, size=11):
font = FB if bold else FN
col = color or INK_BODY
avail = TXT_W - indent
words = txt.split(); line = ''
for word in words:
test = (line+' '+word).strip()
if self.c.stringWidth(test, font, size) < avail:
line = test
else:
self.check()
self.c.setFont(font, size); self.c.setFillColor(col)
self.c.drawString(LMARGIN+indent, self.y, line)
self.y -= LINE_H; line = word
if line:
self.check()
self.c.setFont(font, size); self.c.setFillColor(col)
self.c.drawString(LMARGIN+indent, self.y, line)
self.y -= LINE_H
def bullet(self, txt, indent=4*mm, sym='\u2022'):
self.check()
self.c.setFont(FB,11); self.c.setFillColor(INK)
self.c.drawString(LMARGIN+indent, self.y, sym)
self.text(txt, indent=indent+5*mm)
def sub_bullet(self, txt, indent=9*mm):
self.check()
self.c.setFont(FN,10); self.c.setFillColor(HexColor('#555'))
self.c.drawString(LMARGIN+indent, self.y, '\u25e6')
self.text(txt, indent=indent+5*mm, size=10, color=HexColor('#333'))
def kv(self, key, val, indent=4*mm):
self.check()
c = self.c
c.setFont(FB,11); c.setFillColor(INK)
kw = c.stringWidth(key+': ', FB, 11)
c.drawString(LMARGIN+indent, self.y, key+':')
c.setFont(FN,11); c.setFillColor(INK_BODY)
c.drawString(LMARGIN+indent+kw, self.y, val)
self.y -= LINE_H
def blank(self, n=1):
for _ in range(n): self.check(); self.y -= LINE_H*0.5
def hline(self):
self.check()
self.c.setStrokeColor(HexColor('#9fa8da')); self.c.setLineWidth(0.6)
self.c.line(LMARGIN, self.y+4, W-RMARGIN, self.y+4)
self.y -= 3
def table(self, rows, col_w, hdr=True):
fsize=9.5; row_h=LINE_H*1.05; total=sum(col_w)
self.check(len(rows)*row_h + LINE_H)
x0 = LMARGIN
for ri, row in enumerate(rows):
yr = self.y - ri*row_h
is_h = ri==0 and hdr
self.c.setFillColor(TBL_HDR if is_h else (TBL_ALT if ri%2==0 else white))
self.c.rect(x0, yr-row_h+4, total, row_h, fill=1, stroke=0)
xc = x0
for ci, cell in enumerate(row):
self.c.setFont(FB if is_h else FN, fsize)
self.c.setFillColor(INK if is_h else INK_BODY)
self.c.drawString(xc+2, yr-row_h/2-fsize/3+5, str(cell))
xc += col_w[ci]
self.c.setStrokeColor(HexColor('#9fa8da')); self.c.setLineWidth(0.4)
self.c.rect(x0, yr-row_h+4, total, row_h, fill=0, stroke=1)
self.y -= len(rows)*row_h + LINE_H*0.8
def image(self, path, h_mm=65, caption=''):
pts = h_mm*mm
self.check(pts + (LINE_H*1.5 if caption else 0))
try:
pil = PILImage.open(path).convert('RGB')
iw,ih = pil.size; aspect = iw/ih
dw = min(TXT_W, aspect*pts); dh = dw/aspect
xi = LMARGIN + (TXT_W-dw)/2
self.c.drawImage(path, xi, self.y-dh, dw, dh, preserveAspectRatio=True)
self.y -= dh+3
if caption:
self.c.setFont(FI, 8.5); self.c.setFillColor(GREY_TXT)
self.c.drawCentredString(W/2, self.y, caption)
self.y -= LINE_H
except Exception as e:
dh = pts
self.c.setFillColor(HexColor('#eceff1'))
self.c.rect(LMARGIN, self.y-dh, TXT_W, dh, fill=1, stroke=1)
self.c.setFont(FI,9); self.c.setFillColor(HexColor('#546e7a'))
self.c.drawCentredString(W/2, self.y-dh/2, f'[{caption}]')
self.y -= dh+3
def marks_box(self, n=10):
"""Draw a marks box in top-right corner of current area."""
bw,bh = 22*mm, 10*mm
bx = W-RMARGIN-bw; by = self.y+3
self.c.setFillColor(HexColor('#ffeb3b'))
self.c.setStrokeColor(INK); self.c.setLineWidth(0.8)
self.c.rect(bx,by,bw,bh,fill=1,stroke=1)
self.c.setFont(FB,11); self.c.setFillColor(INK)
self.c.drawCentredString(bx+bw/2, by+bh/2-4, f'{n} Marks')
# ── BUILD PDF ──────────────────────────────────────────────────────────────────
out = '/tmp/workspace/geb-answer/GumElasticBougie_10marks.pdf'
c = rl_canvas.Canvas(out, pagesize=A4)
p = Page(c)
# ── TITLE ──────────────────────────────────────────────────────────────────────
p.marks_box(10)
p.h1('GUM ELASTIC BOUGIE (TRACHEAL TUBE INTRODUCER)')
p.blank()
# ── 1. Introduction ────────────────────────────────────────────────────────────
p.h2('1. Introduction and History')
p.text('The gum elastic bougie (GEB), also called the Eschmann tracheal tube introducer,'
' is one of the most important adjuncts for managing the difficult airway.')
p.bullet('Originally described by Macintosh (>60 years ago) for difficult cord visualisation')
p.bullet('Modern device developed by Venn in 1973 for Eschmann Healthcare, Kent, England')
p.bullet('Most common airway adjunct used in British emergency departments for complicated intubations')
p.blank()
# ── 2. Design ──────────────────────────────────────────────────────────────────
p.h2('2. Design and Physical Characteristics')
p.table(
[
['Feature', 'Specification'],
['Adult curved tip', '60 cm, 15 Fr (5 mm), 40-degree coude tip, 3.5 cm from distal end'],
['Adult straight', '70 cm, 15 Fr'],
['Pediatric', '70 cm, 10 Fr, straight; accommodates >= 4.0 mm ETT'],
['Min. ETT size (adult)','5.5 mm ID'],
['Material', 'Woven polyester (Dacron) + polyurethane resin coating'],
['Variants', 'FROVA Introducer (hollow lumen, CO2 detection); Flectrach (single-use)'],
],
col_w=[55*mm, 105*mm]
)
p.text('The coude (angled) tip is the defining feature - it allows the bougie to be directed'
' anteriorly toward the larynx even when the glottis is NOT directly visible.')
p.blank()
# ── 3. Indications ─────────────────────────────────────────────────────────────
p.h2('3. Indications')
p.bullet('Difficult or failed direct laryngoscopy - Cormack-Lehane grade III or IV')
p.bullet('Anticipated difficult airway (cervical spine injury, trauma, limited mouth opening)')
p.bullet('Cords not visible but epiglottis seen')
p.bullet('Soiled airway - blood, secretions, vomitus (bougie navigates past soiling)')
p.bullet('Scalpel-bougie cricothyrotomy (CICO scenario - cannot intubate, cannot oxygenate)')
p.bullet('Supraglottic airway (SGA) to ETT exchange - via King LT or i-gel')
p.blank()
# ── 4. Signs of Correct Tracheal Placement ────────────────────────────────────
p.h2('4. Signs of Correct Tracheal Placement (3 key signs)')
p.h3('A. Tracheal Clicks (Most Classic - up to 90% of cases)')
p.text('The coude tip strikes the cartilaginous tracheal rings as the bougie is advanced,'
' producing a palpable "click-click" sensation. Felt by operator and by'
' assistant palpating the anterior neck.', indent=4*mm)
p.blank()
p.h3('B. Hold-Up / Distal Stop (at ~40 cm)')
p.text('Bougie stops when it enters a main bronchus at ~40 cm depth. If the bougie'
' passes beyond 40 cm freely without stop, it is likely in the ESOPHAGUS'
' (no bifurcation).', indent=4*mm)
p.blank()
p.h3('C. Visual Confirmation')
p.text('If arytenoids are visible and introducer passed anterior to them without'
' resistance = confirmed tracheal placement. The small calibre does NOT'
' obscure the laryngeal view.', indent=4*mm)
p.blank()
# ── 5. Technique ──────────────────────────────────────────────────────────────
p.h2('5. Technique - Two-Person Method (Preferred)')
for n, step in enumerate([
'Prepare: have styleted ETT and bougie ready before beginning laryngoscopy',
'Laryngoscopy: obtain best possible view. If full cord view - use styleted ETT directly',
'Grade III/IV view: shape bougie with 60-degree bend in distal portion (factory curve alone is insufficient)',
'Pass bougie anterior to arytenoids into larynx. If only epiglottis visible, direct tip under epiglottis anteriorly',
'Confirm: feel tracheal clicks or hold-up at ~40 cm',
'Railroad ETT: assistant threads ETT over bougie with LARYNGOSCOPE STILL IN PLACE',
'Rotate ETT 90 degrees counterclockwise as it approaches glottis (prevents right arytenoid hang-up)',
'Remove bougie while advancing ETT; confirm with capnography',
], 1):
p.bullet(f'Step {n}: {step}')
p.blank()
# ── 6. Common Errors ──────────────────────────────────────────────────────────
p.h2('6. Common Errors and Troubleshooting')
p.table(
[
['Problem', 'Cause', 'Solution'],
['ETT does not railroad', 'Tip on right arytenoid', 'Withdraw 2 cm + rotate 90 deg CCW'],
['Bougie stuck at 20-30 cm', 'Tip on anterior tracheal wall', 'Withdraw slightly + rotate 90 deg CW'],
['No hold-up at >40 cm', 'Esophageal placement', 'Withdraw, reshape to 60-deg, retry'],
['Bougie "too floppy"', 'Operator too close, bad angle', 'Align bougie with line of vision'],
['ETT deflects posteriorly', 'Laryngoscope removed too early','Reinsert laryngoscope first'],
['Slippery introducer', 'Full-length lubrication', 'Lubricate only distal end + ETT'],
],
col_w=[52*mm, 56*mm, 52*mm]
)
# ── 7. Scalpel-Bougie Cricothyrotomy ──────────────────────────────────────────
p.h2('7. Scalpel-Bougie Cricothyrotomy (DAS 2015 - Preferred CICO Technique)')
p.text('Mnemonic: "STAB - TWIST - BOUGIE - TUBE"', bold=True, color=RED)
p.blank()
for step in [
'1. Identify cricothyroid membrane (CTM) with left hand; stabilise larynx',
'2. Transverse STAB incision through skin and CTM with No.10 scalpel',
'3. TWIST: rotate scalpel 90 degrees - sharp edge points caudally',
'4. Swap hands; pull scalpel laterally (left hand) to keep CTM open',
'5. BOUGIE: slide coude tip of bougie down far side of scalpel blade into trachea',
'6. Rotate and advance bougie 10-15 cm; remove scalpel',
'7. TUBE: railroad a 6.0-mm cuffed ETT over bougie with rotation',
'8. Remove bougie; inflate cuff; confirm with capnography',
]:
p.bullet(step)
p.blank()
# ── DIAGRAMS ──────────────────────────────────────────────────────────────────
p.h2('8. Diagrams')
p.h3('Diagram 1: Scalpel-Bougie Technique (Steps A-E) [Miller\'s Anesthesia 10e, Fig. 40.32]')
if 'scalpel' in local_imgs:
p.image(local_imgs['scalpel'], h_mm=70,
caption='FIG. 40.32 - Stab, Twist, Bougie, Tube (A) Identify CTM (B) Stab incision (C) Rotate scalpel (D) Bougie down blade (E) Railroad ETT [Miller\'s Anesthesia 10e]')
p.blank()
p.h3('Diagram 2: CTM Anatomy - Access Site [Miller\'s Anesthesia 10e, Fig. 40.33]')
if 'anatomy' in local_imgs:
p.image(local_imgs['anatomy'], h_mm=60,
caption='FIG. 40.33 - Midsagittal anatomy: access point = lower third of cricothyroid membrane [Miller\'s Anesthesia 10e]')
p.blank()
p.h3('Diagram 3: Arytenoid Hang-Up + Railroading Correction [Roberts & Hedges, Fig. 4.20]')
if 'arytenoid' in local_imgs:
p.image(local_imgs['arytenoid'], h_mm=50,
caption='Fig. 4.20 - (A) ETT tip catches right arytenoid (B-C) Withdraw 2 cm + rotate 90 deg CCW = smooth passage [Roberts & Hedges]')
p.blank()
# ── 9. Evidence ───────────────────────────────────────────────────────────────
p.h2('9. Evidence Base')
p.bullet('Bougie vs stylet - first attempt ED intubation success: 98% vs 87% (Jabre et al., JAMA 2018)')
p.bullet('RCT of 1,102 critically ill patients (JAMA 2021): no significant difference bougie vs stylet for first attempt success,'
' hypoxemia, esophageal intubation, pneumothorax, or oropharyngeal injury')
p.bullet('Bougie + video laryngoscopy (McGrath MAC, Pentax-AWS): improved success + reduced time in simulated vomitus airway')
p.bullet('DAS 2015: scalpel-bougie is the preferred technique for CICO emergency')
p.blank()
# ── 10. Advantages / Complications ───────────────────────────────────────────
p.h2('10. Advantages and Complications')
p.h3('Advantages:')
for a in ['Low cost, highly portable, widely available',
'Works in soiled airways (blood, vomitus) - fiberoptic scope fails here',
'Does not obscure glottic view unlike full ETT',
'Useful when only epiglottis is visible (grade III)',
'Tactile feedback - clicks and hold-up confirm tracheal position',
'Adaptable: works with DL, VL, cricothyrotomy, SGA exchange']:
p.sub_bullet(a)
p.blank()
p.h3('Complications (rare):')
for a in ['Tracheal/bronchial trauma with forceful advancement',
'Barotrauma if hollow-lumen versions used for jet ventilation',
'Endobronchial intubation if ETT advanced too far over bougie',
'Esophageal intubation if placement signs misinterpreted']:
p.sub_bullet(a)
p.blank()
# ── References ────────────────────────────────────────────────────────────────
p.hline()
p.text("References:", bold=True, size=9, color=INK)
for ref in [
"Miller's Anesthesia 10e, Chapter 40 (Airway Management)",
"Barash, Cullen & Stoelting's Clinical Anesthesia 9e, Chapter 28",
"Morgan & Mikhail's Clinical Anesthesiology 7e, Chapter 19",
"Roberts & Hedges' Clinical Procedures in Emergency Medicine, Chapter 4",
]:
p.text(f'\u2022 {ref}', size=8.5, color=GREY_TXT)
# finalize
c.save()
print(f'\nDONE: {out}')
cd /tmp/workspace/geb-answer && python3 build_geb_pdf.py
ls -lh /tmp/workspace/geb-answer/GumElasticBougie_10marks.pdf && python3 -c " from reportlab.lib.pagesizes import A4 # quick page-count check import subprocess result = subprocess.run(['python3', '-c', ''' import pikepdf pdf = pikepdf.open(\"/tmp/workspace/geb-answer/GumElasticBougie_10marks.pdf\") print(f\"Pages: {len(pdf.pages)}\") '''], capture_output=True, text=True) print(result.stdout, result.stderr[:200] if result.stderr else '') "
GumElasticBougie 10marks
PDF Document · PDF