cd /home/daytona/workspace/attachments/dfdd2139-c8c3-40e3-be1c-cf3ebccbcf61 && python3 -c " import pdfplumber files = [ 'DocScanner 04-Jun-2026 12-28 PM.pdf', 'M. S. (BRANCH I) EXAMINATION MARCH _ APRIL - 2022 GENERAL SURGERY _ PAPER-III.pdf' ] for f in files: print(f'=== FILE: {f} ===') with pdfplumber.open(f) as pdf: print(f'Pages: {len(pdf.pages)}') for i, page in enumerate(pdf.pages): print(f'--- Page {i+1} ---') text = page.extract_text() if text: print(text) else: print('[No text extracted]') print() "
cd /home/daytona/workspace/attachments/dfdd2139-c8c3-40e3-be1c-cf3ebccbcf61 && python3 -c " from pypdf import PdfReader, PdfWriter import os # Extract each page of the scanned doc as individual PDFs for analysis reader = PdfReader('DocScanner 04-Jun-2026 12-28 PM.pdf') print(f'DocScanner pages: {len(reader.pages)}') reader2 = PdfReader('M. S. (BRANCH I) EXAMINATION MARCH _ APRIL - 2022 GENERAL SURGERY _ PAPER-III.pdf') print(f'Question paper pages: {len(reader2.pages)}') "
cd /home/daytona/workspace/attachments/dfdd2139-c8c3-40e3-be1c-cf3ebccbcf61 && python3 -c " import subprocess, os # Convert both PDFs to images using pdftoppm os.makedirs('/home/daytona/workspace/pdf_images', exist_ok=True) # Question paper (1 page) subprocess.run(['pdftoppm', '-r', '200', '-png', 'M. S. (BRANCH I) EXAMINATION MARCH _ APRIL - 2022 GENERAL SURGERY _ PAPER-III.pdf', '/home/daytona/workspace/pdf_images/qpaper'], check=True) # DocScanner (15 pages) subprocess.run(['pdftoppm', '-r', '150', '-png', 'DocScanner 04-Jun-2026 12-28 PM.pdf', '/home/daytona/workspace/pdf_images/docscanner'], check=True) import glob files = sorted(glob.glob('/home/daytona/workspace/pdf_images/*.png')) print('Generated images:') for f in files: print(f) "
python3 -c " import subprocess result = subprocess.run(['tesseract', '--version'], capture_output=True, text=True) print(result.stdout) print(result.stderr) "
cd /home/daytona/workspace/pdf_images && for f in *.png; do echo "=== $f ==="; tesseract "$f" stdout 2>/dev/null; echo; done
ls /home/daytona/workspace/ && ls /home/daytona/skills/docx/
mkdir -p /home/daytona/workspace/ms-surgery-answers && node -e "const {Document, Packer} = require('docx'); console.log('docx OK');"
Continue
Answer in exam format generate file paper by paper Please give diagram whenever necessary also flow charts and images
cd /home/daytona/workspace/attachments/dfdd2139-c8c3-40e3-be1c-cf3ebccbcf61 && python3 -c " import subprocess, os os.makedirs('/home/daytona/workspace/pdf_images2', exist_ok=True) subprocess.run(['pdftoppm', '-r', '150', '-png', 'DocScanner 04-Jun-2026 12-28 PM (1).pdf', '/home/daytona/workspace/pdf_images2/doc2'], check=True) import glob files = sorted(glob.glob('/home/daytona/workspace/pdf_images2/*.png')) print(f'Pages: {len(files)}') for f in files: print(f) "
cd /home/daytona/workspace/pdf_images2 && for f in *.png; do echo "=== $f ==="; tesseract "$f" stdout 2>/dev/null; echo; done
cd /home/daytona/workspace/attachments/dfdd2139-c8c3-40e3-be1c-cf3ebccbcf61 && python3 -c " import subprocess, os os.makedirs('/home/daytona/workspace/pdf_images3', exist_ok=True) subprocess.run(['pdftoppm', '-r', '200', '-png', 'M. S. (BRANCH - I) EXAMINATION JULY - 2020 GENERAL SURGERY _ PAPER - I .pdf', '/home/daytona/workspace/pdf_images3/paper'], check=True) import glob files = sorted(glob.glob('/home/daytona/workspace/pdf_images3/*.png')) print(f'Pages: {len(files)}') for f in files: print(f) "
tesseract /home/daytona/workspace/pdf_images3/paper-1.png stdout 2>/dev/null
~/ms-surgery-answers/paper_july2020_paper1.js
const {
Document, Packer, Paragraph, TextRun, HeadingLevel, AlignmentType,
BorderStyle, Table, TableRow, TableCell, WidthType, ShadingType,
PageBreak, UnderlineType
} = require('docx');
const fs = require('fs');
// ─── helpers ──────────────────────────────────────────────────────────────────
const H1 = (text) => new Paragraph({
text, heading: HeadingLevel.HEADING_1,
spacing: { before: 320, after: 120 },
border: { bottom: { style: BorderStyle.SINGLE, size: 6, color: '1F4E79' } }
});
const H2 = (text) => new Paragraph({
text, heading: HeadingLevel.HEADING_2,
spacing: { before: 240, after: 80 }
});
const H3 = (text) => new Paragraph({
text, heading: HeadingLevel.HEADING_3,
spacing: { before: 180, after: 60 }
});
const P = (text) => new Paragraph({
children: [new TextRun({ text, size: 22 })],
spacing: { after: 100 },
indent: { left: 0 }
});
const BOLD = (text) => new Paragraph({
children: [new TextRun({ text, bold: true, size: 22 })],
spacing: { after: 80 }
});
const Bullet = (text, indent = 360) => new Paragraph({
children: [new TextRun({ text, size: 22 })],
bullet: { level: 0 },
indent: { left: indent },
spacing: { after: 60 }
});
const SubBullet = (text) => new Paragraph({
children: [new TextRun({ text, size: 22 })],
bullet: { level: 1 },
indent: { left: 720 },
spacing: { after: 40 }
});
const BoxedNote = (text) => new Paragraph({
children: [new TextRun({ text, bold: true, color: '1F4E79', size: 22 })],
spacing: { before: 80, after: 80 },
border: {
top: { style: BorderStyle.SINGLE, size: 4, color: '1F4E79' },
bottom: { style: BorderStyle.SINGLE, size: 4, color: '1F4E79' },
left: { style: BorderStyle.SINGLE, size: 4, color: '1F4E79' },
right: { style: BorderStyle.SINGLE, size: 4, color: '1F4E79' }
},
indent: { left: 200, right: 200 }
});
const Divider = () => new Paragraph({
border: { bottom: { style: BorderStyle.SINGLE, size: 4, color: 'AAAAAA' } },
spacing: { before: 160, after: 160 }
});
const Space = () => new Paragraph({ text: '', spacing: { after: 100 } });
// ASCII-art style diagram using monospace text in a table cell
const DiagramBox = (lines) => {
const rows = lines.map(line =>
new TableRow({
children: [new TableCell({
children: [new Paragraph({
children: [new TextRun({ text: line, font: 'Courier New', size: 18, color: '1F4E79' })],
spacing: { after: 0 }
})],
margins: { top: 40, bottom: 40, left: 200, right: 200 }
})]
})
);
return new Table({
rows,
width: { size: 9000, type: WidthType.DXA },
borders: {
top: { style: BorderStyle.SINGLE, size: 8, color: '1F4E79' },
bottom: { style: BorderStyle.SINGLE, size: 8, color: '1F4E79' },
left: { style: BorderStyle.SINGLE, size: 8, color: '1F4E79' },
right: { style: BorderStyle.SINGLE, size: 8, color: '1F4E79' },
insideH: { style: BorderStyle.NONE },
insideV: { style: BorderStyle.NONE }
}
});
};
// Two-column table
const TwoColTable = (rows, header) => {
const tableRows = [];
if (header) {
tableRows.push(new TableRow({
children: header.map(h => new TableCell({
children: [new Paragraph({ children: [new TextRun({ text: h, bold: true, color: 'FFFFFF', size: 22 })] })],
shading: { type: ShadingType.SOLID, color: '1F4E79' },
margins: { top: 80, bottom: 80, left: 160, right: 160 }
})),
tableHeader: true
}));
}
rows.forEach(([c1, c2]) => {
tableRows.push(new TableRow({
children: [
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text: c1, bold: true, size: 20 })] })],
width: { size: 3600, type: WidthType.DXA },
margins: { top: 80, bottom: 80, left: 160, right: 160 }
}),
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text: c2, size: 20 })] })],
width: { size: 5400, type: WidthType.DXA },
margins: { top: 80, bottom: 80, left: 160, right: 160 }
})
]
}));
});
return new Table({
rows: tableRows,
width: { size: 9000, type: WidthType.DXA },
borders: {
top: { style: BorderStyle.SINGLE, size: 4, color: '4472C4' },
bottom: { style: BorderStyle.SINGLE, size: 4, color: '4472C4' },
left: { style: BorderStyle.SINGLE, size: 4, color: '4472C4' },
right: { style: BorderStyle.SINGLE, size: 4, color: '4472C4' },
insideH: { style: BorderStyle.SINGLE, size: 2, color: 'AAAAAA' },
insideV: { style: BorderStyle.SINGLE, size: 2, color: 'AAAAAA' }
}
});
};
// ─── COVER PAGE ───────────────────────────────────────────────────────────────
const coverPage = [
Space(), Space(), Space(),
new Paragraph({
children: [new TextRun({ text: 'M.S. (Branch – I) Examination', bold: true, size: 52, color: '1F4E79' })],
alignment: AlignmentType.CENTER, spacing: { after: 160 }
}),
new Paragraph({
children: [new TextRun({ text: 'July 2020 — General Surgery : Paper I', bold: true, size: 36, color: '2E74B5' })],
alignment: AlignmentType.CENTER, spacing: { after: 160 }
}),
new Paragraph({
children: [new TextRun({ text: 'MODEL ANSWERS WITH DIAGRAMS & FLOWCHARTS', bold: true, size: 28, color: '1F4E79' })],
alignment: AlignmentType.CENTER, spacing: { after: 200 }
}),
new Paragraph({
border: { bottom: { style: BorderStyle.DOUBLE, size: 6, color: '1F4E79' } },
spacing: { before: 100, after: 400 }
}),
new Paragraph({
children: [new TextRun({ text: 'Time: 3 Hours | Total Marks: 100', size: 24, italics: true })],
alignment: AlignmentType.CENTER, spacing: { after: 200 }
}),
TwoColTable([
['Q.1', 'Spleen – Anatomy, Physiology, Splenectomy (30 marks)'],
['Q.2', 'Lymphoedema – Pathophysiology, Classification, Management (20 marks)'],
['Q.3', 'Shock – Pathophysiology, Classification, Management (20 marks)'],
['Q.4(a)', 'Total Parenteral Nutrition (TPN)'],
['Q.4(b)', 'Blast Injuries'],
['Q.4(c)', 'Assessment of Area of Burns'],
], ['Question', 'Topic']),
Space(), Space(),
new Paragraph({ children: [new PageBreak()] })
];
// ═══════════════════════════════════════════════════════════════════════════════
// QUESTION 1 — SPLEEN (30 marks)
// ═══════════════════════════════════════════════════════════════════════════════
const q1 = [
H1('QUESTION 1 (30 Marks)'),
P('Write surgical anatomy, physiology and functions of spleen. Describe indications and technique of Splenectomy and post-splenectomy complications.'),
Divider(),
H2('A. SURGICAL ANATOMY OF THE SPLEEN'),
H3('1. Gross Anatomy'),
Bullet('Location: Left hypochondrium, 9th–11th rib level, under the diaphragm'),
Bullet('Weight: 100–150 g (adult); Size: 12 × 7 × 4 cm (Rule of 1, 3, 5, 7, 9, 11)'),
Bullet('Peritoneal covering: Intraperitoneal organ'),
Bullet('Surfaces: Diaphragmatic (convex, smooth), Visceral (concave, hilum, renal, gastric, colic impressions)'),
Bullet('Poles: Superior (notched), Inferior'),
H3('2. Ligaments'),
TwoColTable([
['Gastrosplenic ligament', 'Contains short gastric arteries and left gastroepiploic vessels'],
['Splenorenal (lienorenal) ligament', 'Contains splenic vessels and tail of pancreas'],
['Phrenocolic ligament', 'Supports inferior pole — "suspensory ligament"'],
['Splenocolic ligament', 'Between splenic flexure of colon and spleen'],
], ['Ligament', 'Contents / Significance']),
Space(),
H3('3. Blood Supply'),
DiagramBox([
' CELIAC AXIS',
' |',
' Splenic Artery (tortuous)',
' |',
' Branches before hilum: Superior, Inferior poles',
' |',
' Trabecular Arteries → Central Arteries',
' |',
' ┌─────────────┴──────────────┐',
' Open (fast) Closed (slow)',
' circulation circulation',
' └─────────────┬──────────────┘',
' Venous Sinuses',
' |',
' Splenic Vein',
' |',
' (Joins Superior Mesenteric Vein)',
' |',
' Portal Vein',
]),
Space(),
H3('4. Microscopic Anatomy'),
Bullet('White pulp: Lymphoid tissue; periarteriolar lymphatic sheaths (PALS) and lymphoid follicles (B-cells)'),
Bullet('Red pulp: Venous sinuses + splenic cords (cords of Billroth); filters RBCs'),
Bullet('Marginal zone: Between red and white pulp; first contact point for blood-borne antigens'),
H2('B. PHYSIOLOGY AND FUNCTIONS'),
TwoColTable([
['Filtration', 'Removes senescent/abnormal RBCs, platelets, bacteria (especially encapsulated)'],
['Immunological', 'Produces IgM antibodies; opsonins (tuftsin, properdin); T and B lymphocytes; NK cells'],
['Haematopoiesis', 'In fetal life (up to 5th month); extramedullary haematopoiesis in adults when marrow fails'],
['Storage', 'Stores ~30% of total platelets; small reserve of RBCs'],
['Iron recycling', 'Macrophages phagocytose effete RBCs → haemoglobin → haem → iron recycled'],
['Blood volume regulation', 'Acts as reservoir; contracts under sympathetic stimulation releasing stored blood'],
], ['Function', 'Detail']),
Space(),
H2('C. INDICATIONS FOR SPLENECTOMY'),
H3('Haematological'),
Bullet('Hereditary spherocytosis — definitive treatment'),
Bullet('Immune thrombocytopenic purpura (ITP) — refractory to steroids'),
Bullet('Haemolytic anaemias — thalassaemia, sickle cell'),
Bullet('Thrombotic thrombocytopenic purpura (TTP)'),
H3('Traumatic'),
Bullet('Grade III–V splenic lacerations (AAST grading)'),
Bullet('Failed non-operative management / hemodynamic instability'),
H3('Incidental / Other'),
Bullet('Staging laparotomy for Hodgkin\'s lymphoma (historic)'),
Bullet('Hypersplenism secondary to portal hypertension'),
Bullet('Splenic artery aneurysm, splenic abscess, splenic cysts (large)'),
Bullet('En-bloc resection for adjacent malignancy (stomach, pancreatic tail)'),
H2('D. PRE-OPERATIVE PREPARATION'),
Bullet('Vaccinate against encapsulated organisms ≥2 weeks before: Pneumococcus (PCV13/PPSV23), Meningococcus, Haemophilus influenzae type b'),
Bullet('Correct thrombocytopenia / anaemia with transfusions / steroids'),
Bullet('Group and crossmatch; consent for open conversion if laparoscopic'),
Bullet('Antibiotic prophylaxis (cefuroxime)'),
Bullet('DVT prophylaxis'),
H2('E. TECHNIQUE OF SPLENECTOMY'),
H3('Open Splenectomy'),
DiagramBox([
' STEPS OF OPEN SPLENECTOMY',
'',
' 1. Position: Supine / right lateral decubitus',
' 2. Incision: Left subcostal (Kocher) / Midline / Roof-top',
' 3. Mobilization: Divide splenocolic ligament (inferior)',
' 4. Ligate short gastric vessels (gastrosplenic ligament)',
' 5. Divide splenorenal ligament → displace spleen medially',
' 6. Expose splenic hilum',
' 7. LIGATE SPLENIC ARTERY FIRST (controls bleeding,',
' allows autotransfusion of stored blood ~250 mL)',
' 8. Ligate splenic vein',
' 9. Divide ligaments → remove spleen',
' 10. Check pancreatic tail for injury',
' 11. Drain (optional — left sub-phrenic)',
' 12. Close in layers',
]),
Space(),
H3('Laparoscopic Splenectomy'),
Bullet('Patient: Supine or right lateral decubitus'),
Bullet('Ports: 4 ports — camera (umbilical), working ports in left upper quadrant'),
Bullet('Hand-assisted or total laparoscopic'),
Bullet('Advantages: Less pain, faster recovery, lower wound complications'),
Bullet('Contraindications (relative): Splenomegaly >20 cm, haemodynamic instability, severe portal hypertension'),
H2('F. POST-SPLENECTOMY COMPLICATIONS'),
H3('Immediate'),
Bullet('Haemorrhage (from splenic hilum, short gastric vessels)'),
Bullet('Injury to pancreatic tail → fistula, pseudocyst'),
Bullet('Injury to stomach (short gastric ligation)'),
Bullet('Injury to colon, left kidney, diaphragm'),
H3('Early'),
Bullet('Reactive thrombocytosis (platelet count >1000 × 10⁹/L) — DVT/PE risk'),
Bullet('Left sub-phrenic abscess'),
Bullet('Pleural effusion / atelectasis (left lower lobe)'),
Bullet('Gastric fistula'),
H3('Late — OPSI (Most Feared)'),
BoxedNote('OVERWHELMING POST-SPLENECTOMY INFECTION (OPSI)'),
Bullet('Incidence: 0.5–2% lifetime; Mortality: up to 50%'),
Bullet('Causative organisms: S. pneumoniae (50%), N. meningitidis, H. influenzae'),
Bullet('Mechanism: Loss of filtration, opsonisation (tuftsin, properdin), IgM'),
Bullet('Presentation: Sudden fever → sepsis → DIC → death within 12–24 hours'),
DiagramBox([
' OPSI MANAGEMENT FLOWCHART',
'',
' Asplenic patient + fever/rigors',
' |',
' ┌──────▼───────┐',
' │ DO NOT WAIT │ → Blood cultures THEN',
' └──────┬───────┘ IV Ceftriaxone 2g STAT',
' |',
' Hospital admission',
' |',
' Sepsis bundle (SOFA)',
' |',
' ICU if deteriorating',
]),
Space(),
Bullet('Prevention: Vaccination + lifelong prophylactic penicillin V 250 mg BD (esp. children <5 yr, first 2 yr post-splenectomy)'),
Bullet('Patient education: Medic-alert bracelet, emergency antibiotic card, travel precautions (malaria)'),
H3('Other Late Complications'),
Bullet('Splenosis — autotransplantation of splenic tissue (may restore partial function)'),
Bullet('Portal / mesenteric vein thrombosis (reactive thrombocytosis)'),
Bullet('Increased susceptibility to malaria, babesiosis, capnocytophaga'),
Bullet('Iron-deficiency anaemia (loss of iron recycling)'),
new Paragraph({ children: [new PageBreak()] })
];
// ═══════════════════════════════════════════════════════════════════════════════
// QUESTION 2 — LYMPHOEDEMA (20 marks)
// ═══════════════════════════════════════════════════════════════════════════════
const q2 = [
H1('QUESTION 2 (20 Marks)'),
P('Describe Pathophysiology, Classification and Management of Lymphoedema.'),
Divider(),
H2('A. DEFINITION'),
P('Lymphoedema is the accumulation of protein-rich interstitial fluid due to inadequate lymphatic transport, resulting in chronic soft-tissue swelling, inflammation, and fibrosis.'),
H2('B. PATHOPHYSIOLOGY'),
DiagramBox([
' PATHOPHYSIOLOGY OF LYMPHOEDEMA',
'',
' Lymphatic obstruction / aplasia / damage',
' |',
' ┌───────────▼────────────────────────┐',
' │ Reduced lymphatic transport │',
' │ capacity (normal 2–4 L/day) │',
' └───────────┬────────────────────────┘',
' |',
' Protein-rich fluid accumulates in interstitium',
' |',
' Oncotic pressure gradient maintained',
' → Water retention worsens oedema',
' |',
' Macrophage accumulation → TGF-β, VEGF',
' |',
' Fibrosis of subcutaneous tissue',
' (collagen deposition)',
' |',
' Chronic lymphostasis → adipose deposition',
' |',
' IRREVERSIBLE CHANGES: Elephantiasis',
]),
Space(),
Bullet('Protein accumulation stimulates fibroblast activity → progressive fibrosis'),
Bullet('Fat hypertrophy (lipoedema component develops late)'),
Bullet('Immune dysfunction → recurrent bacterial (erysipelas) and fungal infections'),
Bullet('Repeated infections worsen lymphatic destruction (vicious cycle)'),
H2('C. CLASSIFICATION'),
H3('I. Primary Lymphoedema (Congenital/Idiopathic)'),
TwoColTable([
['Milroy\'s disease', 'Congenital; autosomal dominant; VEGFR3 mutation; present at birth; lower limbs'],
['Lymphoedema praecox (Meige\'s disease)', 'Onset at puberty (most common primary type); female predominance; unilateral leg'],
['Lymphoedema tarda', 'Onset after age 35; bilateral lower limbs'],
['Lymphangiectasia', 'Dilated, incompetent lymphatics; may be associated with chylous ascites'],
], ['Type', 'Features']),
Space(),
H3('II. Secondary Lymphoedema (Acquired)'),
Bullet('Filariasis (Wuchereria bancrofti) — most common cause worldwide'),
Bullet('Post-malignancy lymph node dissection (axillary, inguinal, pelvic)'),
Bullet('Radiation therapy — radiation-induced fibrosis of lymphatics'),
Bullet('Chronic venous insufficiency'),
Bullet('Infection — TB, lymphogranuloma venereum, pyogenic lymphadenitis'),
Bullet('Trauma, burns'),
Bullet('Tumour infiltration of lymphatics (lymphoma, metastases)'),
H3('III. Staging (International Society of Lymphology — ISL)'),
TwoColTable([
['Stage 0 (Latent)', 'Lymphatic damage present but no clinical oedema; subclinical'],
['Stage I', 'Early pitting oedema that reduces with limb elevation; reversible'],
['Stage II', 'Non-pitting oedema; does not reduce with elevation; fibrosis begins'],
['Stage III (Elephantiasis)', 'Massive non-pitting oedema; skin changes (papillomatosis, hyperkeratosis, warty growths)'],
], ['Stage', 'Description']),
Space(),
H2('D. CLINICAL FEATURES'),
Bullet('Unilateral (usually) painless swelling of limb (lower > upper)'),
Bullet('Pitting initially → non-pitting later (fibrosis)'),
Bullet('Stemmer\'s sign: Inability to pinch skin at base of 2nd toe (pathognomonic of lymphoedema)'),
Bullet('Skin changes: Thickening, hyperkeratosis, papillomatosis, "cobblestone" appearance, lymphorrhea'),
Bullet('Recurrent episodes of cellulitis / erysipelas → worsening lymphoedema'),
Bullet('Psychological impact — disfigurement, mobility issues'),
H2('E. INVESTIGATIONS'),
Bullet('Lymphoscintigraphy (radionucleide): Gold standard — shows lymphatic anatomy, transport time'),
Bullet('Duplex ultrasound: Exclude DVT; assess venous insufficiency'),
Bullet('MRI / CT: Evaluate tissue composition, malignant obstruction, "honeycomb" pattern in subcutaneous tissue'),
Bullet('Bioimpedance spectroscopy: Early detection of fluid accumulation'),
Bullet('Lymphangiography (historic): Direct contrast injection — rarely used now'),
H2('F. MANAGEMENT'),
H3('1. Conservative (Mainstay — CDT)'),
BoxedNote('CDT = Complete Decongestive Therapy (Gold Standard Non-Surgical Treatment)'),
DiagramBox([
' COMPLETE DECONGESTIVE THERAPY (CDT)',
'',
' Phase 1: Intensive (2–4 weeks)',
' ┌──────────────────────────────────────┐',
' │ MLD (Manual Lymphatic Drainage) │',
' │ Multilayer compression bandaging │',
' │ Skin care (moisturizers, antifungals) │',
' │ Prescribed exercises │',
' └──────────────────────────────────────┘',
' ↓',
' Phase 2: Maintenance (lifelong)',
' ┌──────────────────────────────────────┐',
' │ Custom compression garments (Class 2) │',
' │ Self-MLD │',
' │ Ongoing exercises │',
' │ Skin care + infection prophylaxis │',
' └──────────────────────────────────────┘',
]),
Space(),
Bullet('Compression garments: Reduce fluid reaccumulation'),
Bullet('Pneumatic compression devices: Sequential intermittent pneumatic compression'),
Bullet('Treat infections promptly: Penicillin/amoxicillin for cellulitis; antifungals for tinea'),
Bullet('Diethylcarbamazine (DEC) for filarial lymphoedema'),
Bullet('Weight reduction in obese patients'),
H3('2. Surgical Management'),
TwoColTable([
['Lymphatico-venous anastomosis (LVA)', 'Microsurgical; bypasses obstruction; best for early stage II; reduces volume by 30–40%'],
['Vascularized lymph node transfer (VLNT)', 'Transfers lymph nodes to affected region; promotes lymphangiogenesis'],
['Charles procedure', 'Radical excision of subcutaneous tissue + skin grafting; for severe elephantiasis (Stage III)'],
['Homans\' procedure', 'Staged subcutaneous excision; less disfiguring than Charles'],
['Liposuction', 'For fat-dominated chronic lymphoedema; requires lifelong compression post-op'],
], ['Procedure', 'Description']),
Space(),
new Paragraph({ children: [new PageBreak()] })
];
// ═══════════════════════════════════════════════════════════════════════════════
// QUESTION 3 — SHOCK (20 marks)
// ═══════════════════════════════════════════════════════════════════════════════
const q3 = [
H1('QUESTION 3 (20 Marks)'),
P('Pathophysiology and classification of Shock. Discuss resuscitation and management of shock.'),
Divider(),
H2('A. DEFINITION'),
P('Shock is a life-threatening, generalised form of acute circulatory failure associated with inadequate oxygen utilisation by the cells (cellular hypoxia), leading to cellular dysfunction and ultimately death.'),
BoxedNote('DO₂ < VO₂ (Oxygen delivery < Oxygen consumption) → Anaerobic metabolism → Lactic acidosis'),
H2('B. PATHOPHYSIOLOGY'),
DiagramBox([
' PATHOPHYSIOLOGY OF SHOCK',
'',
' Trigger (blood loss/sepsis/anaphylaxis/cardiac failure)',
' |',
' ↓ Cardiac Output and/or ↓ SVR',
' |',
' ↓ Mean Arterial Pressure (MAP < 65 mmHg)',
' |',
' COMPENSATORY MECHANISMS (Reversible Phase)',
' ┌─────────────────────────────────────────┐',
' │ Baroreceptor activation → SNS stimulation│',
' │ ↑ HR, ↑ Contractility, vasoconstriction │',
' │ Renin-Angiotensin-Aldosterone activation │',
' │ ADH (vasopressin) release │',
' └────────────────────┬────────────────────┘',
' |',
' If untreated → Prolonged hypoperfusion',
' |',
' DECOMPENSATION (Progressive Phase)',
' ┌─────────────────────────────────────────┐',
' │ Anaerobic glycolysis → Lactic acidosis │',
' │ Capillary leak (histamine, cytokines) │',
' │ Microvascular sludging, microthrombi │',
' │ Cell membrane pump failure (Na⁺/K⁺ ATPase)│',
' │ Lysosomal enzyme release │',
' └────────────────────┬────────────────────┘',
' |',
' IRREVERSIBLE SHOCK',
' → MODS → DEATH',
]),
Space(),
H2('C. CLASSIFICATION OF SHOCK'),
TwoColTable([
['Type', 'Mechanism / Examples'],
['HYPOVOLAEMIC', 'Loss of circulating volume: Haemorrhage, dehydration (burns, diarrhoea, vomiting), plasma loss'],
['DISTRIBUTIVE\n(a) Septic\n(b) Anaphylactic\n(c) Neurogenic', 'Vasodilation → maldistribution\n(a) Endotoxins/cytokines → warm shock → cold shock\n(b) IgE-mediated → histamine, bradykinin\n(c) Spinal cord injury → loss of sympathetic tone'],
['CARDIOGENIC', 'Pump failure: MI, arrhythmia, valve rupture, cardiac tamponade, tension pneumothorax'],
['OBSTRUCTIVE', 'Mechanical obstruction: Massive PE, tension pneumothorax, cardiac tamponade, aortic dissection'],
], null),
Space(),
H3('ATLS Classification of Haemorrhagic Shock (based on 70 kg adult)'),
TwoColTable([
['Class I', '< 750 mL (<15%)\nHR <100, BP normal, RR 14–20'],
['Class II', '750–1500 mL (15–30%)\nHR 100–120, ↓pulse pressure, RR 20–30, anxious'],
['Class III', '1500–2000 mL (30–40%)\nHR >120, ↓BP, RR 30–40, confused'],
['Class IV', '>2000 mL (>40%)\nHR >140, ↓↓BP, negligible urine, unconscious'],
], ['Class', 'Blood Loss / Parameters']),
Space(),
H2('D. RESUSCITATION AND MANAGEMENT'),
H3('Universal Approach: ABCDE + Early Goal-Directed Therapy'),
DiagramBox([
' SHOCK RESUSCITATION FLOWCHART',
'',
' RECOGNITION: MAP<65, HR>100, ↓UO, altered consciousness',
' |',
' ┌───────────────▼───────────────┐',
' │ IMMEDIATE ACTIONS │',
' │ • 2 large-bore IV lines │',
' │ • O₂ (15L/min, non-rebreathe) │',
' │ • ECG, SpO₂, ETCO₂ │',
' │ • Bloods: FBC,U&E,LFT,Lactate│',
' │ Coag, X-match, ABG │',
' │ • Urinary catheter (UO >0.5 │',
' │ mL/kg/hr target) │',
' │ • CXR/FAST/CT │',
' └───────────────┬───────────────┘',
' |',
' ┌───────────────▼───────────────┐',
' │ IDENTIFY TYPE & TREAT │',
' └───────────────┬───────────────┘',
' ___________________│___________________',
' | | | |',
' Haemorrhagic Septic Cardiogenic Anaphylactic',
' ↓ ↓ ↓ ↓',
' Haemostasis Antibiotics Inotropes Adrenaline',
' Fluids/Blood Fluids/Nora ± IABP/ECMO Fluids/Steroids',
]),
Space(),
H3('1. Haemorrhagic Shock'),
BOLD('Damage Control Resuscitation (DCR):'),
Bullet('Permissive hypotension: Target SBP 80–90 mmHg until haemostasis (NOT in TBI)'),
Bullet('Massive Transfusion Protocol (MTP): pRBC : FFP : Platelets = 1:1:1'),
Bullet('Tranexamic acid: 1 g IV within 3 hours of injury (CRASH-2 trial)'),
Bullet('Avoid hypothermia, acidosis, coagulopathy (Lethal Triad)'),
Bullet('Surgical haemostasis — damage control surgery if needed'),
H3('2. Septic Shock (Surviving Sepsis Campaign "Hour-1 Bundle")'),
Bullet('Blood cultures × 2 BEFORE antibiotics'),
Bullet('Broad-spectrum IV antibiotics within 1 hour'),
Bullet('IV crystalloid 30 mL/kg for hypotension / lactate ≥4 mmol/L'),
Bullet('Vasopressors: Noradrenaline (first line) if MAP <65 despite fluids'),
Bullet('Reassess fluid responsiveness (passive leg raise, SVV)'),
Bullet('Hydrocortisone 200 mg/day if refractory to vasopressors'),
H3('3. Anaphylactic Shock'),
Bullet('Adrenaline (epinephrine) 0.5 mg IM (1:1000) FIRST'),
Bullet('Remove trigger, O₂, IV fluid bolus'),
Bullet('Chlorphenamine 10 mg IV, Hydrocortisone 200 mg IV'),
Bullet('Salbutamol nebuliser for bronchospasm'),
H3('4. Cardiogenic Shock'),
Bullet('Treat underlying cause (PCI for STEMI, pericardiocentesis for tamponade, needle decompression for tension pneumothorax)'),
Bullet('Dobutamine / dopamine (inotropic support)'),
Bullet('Consider IABP or ECMO in refractory cases'),
H3('Monitoring Endpoints of Resuscitation'),
Bullet('MAP ≥65 mmHg'),
Bullet('Urine output ≥0.5 mL/kg/hour'),
Bullet('Lactate clearance (>10% per 2 hours; target <2 mmol/L)'),
Bullet('ScvO₂ >70%'),
Bullet('Base excess normalisation'),
new Paragraph({ children: [new PageBreak()] })
];
// ═══════════════════════════════════════════════════════════════════════════════
// QUESTION 4 (a) — TPN (10 marks shared)
// ═══════════════════════════════════════════════════════════════════════════════
const q4a = [
H1('QUESTION 4(a) — Total Parenteral Nutrition (TPN)'),
Divider(),
H2('Definition'),
P('TPN is the intravenous provision of all nutritional requirements (carbohydrates, proteins, lipids, vitamins, minerals, trace elements, and fluids) when enteral nutrition is impossible, insufficient, or contraindicated.'),
H2('Indications'),
Bullet('GI failure (paralytic ileus, short bowel syndrome, high-output fistulae)'),
Bullet('Severe malnutrition with non-functioning gut'),
Bullet('Bowel obstruction, intestinal pseudo-obstruction'),
Bullet('Severe acute pancreatitis (when enteral feed intolerance occurs)'),
Bullet('Post-major GI surgery (brief period)'),
Bullet('Inflammatory bowel disease with toxic megacolon / fistula'),
Bullet('Bone marrow transplant patients'),
H2('Composition of TPN'),
TwoColTable([
['Carbohydrates', 'Dextrose 50–60% of calories; 3.4 kcal/g; glucose infusion rate <5 mg/kg/min'],
['Amino acids', '1.2–2 g/kg/day; essential + non-essential; 4 kcal/g; nitrogen source'],
['Lipids', '20–30% of calories; 10% or 20% Intralipid; 9 kcal/g; essential fatty acids'],
['Total calories', '25–35 kcal/kg/day (non-protein calories: 150 kcal per 1 g nitrogen)'],
['Electrolytes', 'Na⁺, K⁺, Mg²⁺, Ca²⁺, Phosphate — adjusted daily'],
['Vitamins', 'Water-soluble (B, C) + fat-soluble (A, D, E, K) added'],
['Trace elements', 'Zinc, Copper, Selenium, Chromium, Manganese'],
], ['Component', 'Detail']),
Space(),
H2('Access'),
Bullet('Central venous catheter (CVC): Subclavian > internal jugular > femoral'),
Bullet('PICC line (peripherally inserted central catheter): For prolonged TPN'),
Bullet('Peripheral TPN: Osmolarity <800 mOsm/L; short-term only (phlebitis risk)'),
H2('Complications of TPN'),
H3('Catheter-related'),
Bullet('Pneumothorax, haemothorax, arterial injury (during insertion)'),
Bullet('CLABSI (Central Line-Associated Blood Stream Infection) — Staphylococcus epidermidis most common'),
Bullet('Catheter thrombosis, air embolism'),
H3('Metabolic'),
DiagramBox([
' TPN METABOLIC COMPLICATIONS',
'',
' Hyperglycaemia → insulin protocol required',
' Hypoglycaemia → on abrupt stopping',
' Refeeding syndrome → ↓PO₄, ↓K⁺, ↓Mg²⁺',
' (phosphate drops as cells take up glucose)',
' Hyperlipidaemia → if lipids infused too rapidly',
' Hepatic steatosis → fatty liver (esp. in neonates)',
' Electrolyte imbalances',
' Metabolic acidosis (hyperchloraemic)',
]),
Space(),
H3('Monitoring TPN'),
Bullet('Daily: Blood glucose (4-hourly initially), electrolytes, fluid balance'),
Bullet('Twice weekly: LFTs, urea, triglycerides'),
Bullet('Weekly: FBC, coagulation, trace elements, vitamins'),
Bullet('Transition to enteral nutrition as soon as possible'),
new Paragraph({ children: [new PageBreak()] })
];
// ═══════════════════════════════════════════════════════════════════════════════
// QUESTION 4 (b) — BLAST INJURIES
// ═══════════════════════════════════════════════════════════════════════════════
const q4b = [
H1('QUESTION 4(b) — Blast Injuries'),
Divider(),
H2('Definition'),
P('Blast injuries result from the release of a large amount of energy in a very short time following an explosion, causing blast wave, blast wind, penetrating fragments, burns, and blunt trauma.'),
H2('Mechanisms — Classification of Blast Injuries'),
TwoColTable([
['PRIMARY', 'Blast wave (pressure wave) — solid-gas interfaces most vulnerable: Ear (rupture of TM), Lung (blast lung), Bowel (hollow viscus rupture), Brain (PTBI)'],
['SECONDARY', 'Fragmentation — bomb casing, glass, debris — penetrating injuries'],
['TERTIARY', 'Blast wind — victim thrown against structures — blunt trauma, fractures, traumatic amputations'],
['QUATERNARY', 'Burns, crush injuries, inhalation injury, toxic chemicals, radiation (dirty bomb)'],
['QUINARY', 'Hyperinflammatory state from additives (bacteria, radioactive material)'],
], ['Mechanism', 'Injury']),
Space(),
H2('Target Organ Injuries'),
H3('Blast Lung (most serious primary blast injury)'),
Bullet('Pulmonary contusion, alveolar haemorrhage, pneumothorax, haemothorax'),
Bullet('"Butterfly" pattern opacification on CXR'),
Bullet('Delayed presentation (up to 48 hours)'),
Bullet('Management: O₂, supportive; AVOID positive pressure ventilation if possible (tension pneumothorax risk)'),
H3('Abdominal Blast Injury'),
Bullet('Air-filled bowel (colon > small bowel) most vulnerable'),
Bullet('Delayed perforation (up to 72 hours after blast)'),
Bullet('Solid organs may rupture from transmitted pressure'),
H3('Ear / Head'),
Bullet('Tympanic membrane rupture (most common primary blast injury)'),
Bullet('Sensorineural hearing loss, tinnitus'),
Bullet('Primary Traumatic Brain Injury — diffuse axonal injury'),
H2('Management'),
DiagramBox([
' BLAST INJURY MANAGEMENT',
'',
' Scene safety → decontamination',
' ↓',
' ABCDE (ATLS protocol)',
' ↓',
' All blast survivors → observe ≥12–24 h',
' (delayed perforation, blast lung)',
' ↓',
' Imaging: CXR, AXR, CT abdomen if concern',
' ↓',
' Surgical exploration if peritonism / haemodynamic instability',
' ↓',
' Pain management, tetanus prophylaxis',
' Wound debridement (delay primary closure)',
' Antibiotics for penetrating injuries',
]),
Space(),
new Paragraph({ children: [new PageBreak()] })
];
// ═══════════════════════════════════════════════════════════════════════════════
// QUESTION 4 (c) — BURNS ASSESSMENT
// ═══════════════════════════════════════════════════════════════════════════════
const q4c = [
H1('QUESTION 4(c) — Assessment of Area of Burns'),
Divider(),
H2('Importance'),
P('Accurate assessment of Total Body Surface Area (TBSA) burned is essential for fluid resuscitation calculation, prognosis, and triage decisions.'),
H2('Methods for Assessment'),
H3('1. Rule of Nines (Wallace Rule of Nines)'),
DiagramBox([
' RULE OF NINES (Adult)',
'',
' Head & Neck = 9%',
' ┌──────────────────────────┐',
' │ Each arm = 9% │',
' │ Anterior trunk = 18% │',
' │ Posterior trunk= 18% │',
' │ Each leg = 18% │',
' │ Perineum = 1% │',
' └──────────────────────────┘',
' TOTAL = 100%',
'',
' NOTE: In children, HEAD = 18%, each LEG = 13.5%',
' (Lund & Browder more accurate for children)',
]),
Space(),
Bullet('Quick, practical at bedside and pre-hospital'),
Bullet('Overestimates in obese patients, inaccurate for children'),
H3('2. Lund and Browder Chart'),
Bullet('Most accurate method — accounts for age-related differences in body proportions'),
Bullet('Divides body into 19 segments with precise percentages'),
Bullet('Head decreases with age (9% at 10 yr → 7% adult); lower limbs increase'),
Bullet('Used in all hospitals for accurate assessment'),
TwoColTable([
['Region', 'Percentage (adult)'],
['Head (A)', '7% (varies with age — Lund & Browder table)'],
['Neck', '2%'],
['Anterior trunk', '13%'],
['Posterior trunk', '13%'],
['Upper arm (each)', '4%'],
['Lower arm (each)', '3%'],
['Hand (each)', '2.5%'],
['Thigh (each, B)', '4.75% (varies with age)'],
['Lower leg (each, C)', '3.5% (varies with age)'],
['Foot (each)', '3.5%'],
['Genitalia', '1%'],
], ['Region', 'TBSA']),
Space(),
H3('3. Palmar Method (Rule of Palm)'),
Bullet('Patient\'s palm (including fingers) = 1% TBSA'),
Bullet('Useful for small (<15%) or scattered, irregular burns'),
Bullet('Quick and easy for pre-hospital assessment'),
H3('4. Berkow Chart / Modified Berkow Chart'),
Bullet('Detailed chart similar to Lund & Browder; used in specialist burns centres'),
H3('5. Digital Planimetry / Software tools'),
Bullet('Mobile apps (e.g. Mersey Burns) for digital TBSA calculation'),
Bullet('Increasingly used in burns centres'),
H2('What to Include/Exclude in Assessment'),
Bullet('Include: 2nd degree (partial thickness) and 3rd degree (full thickness) burns only'),
Bullet('EXCLUDE: 1st degree (superficial/sunburn/epidermal) burns from TBSA calculation for fluid resuscitation'),
Bullet('Also assess: Depth (1st/2nd/3rd/4th), Circumferential burns, Airway involvement, Chemical/electrical/inhalation burns'),
H2('Clinical Application — Parkland Formula'),
BoxedNote('Fluid Resuscitation (Parkland): 4 mL × TBSA (%) × Body weight (kg) = Total crystalloid in 24 hrs'),
Bullet('Half in first 8 hours from TIME OF BURN (not hospital arrival)'),
Bullet('Remaining half over next 16 hours'),
Bullet('Fluid: Ringer\'s Lactate (Hartmann\'s solution)'),
Bullet('Monitor: Urine output 0.5 mL/kg/hr adult; 1 mL/kg/hr child'),
Space(),
Divider(),
new Paragraph({
children: [new TextRun({ text: '— END OF MODEL ANSWERS: July 2020 General Surgery Paper I —', bold: true, italics: true, size: 20, color: '666666' })],
alignment: AlignmentType.CENTER, spacing: { before: 200, after: 200 }
})
];
// ═══════════════════════════════════════════════════════════════════════════════
// BUILD DOCUMENT
// ═══════════════════════════════════════════════════════════════════════════════
const doc = new Document({
styles: {
default: {
document: { run: { font: 'Calibri', size: 22 } }
},
paragraphStyles: [
{
id: 'Heading1', name: 'Heading 1', basedOn: 'Normal',
run: { bold: true, size: 32, color: '1F4E79', font: 'Calibri' },
paragraph: { spacing: { before: 320, after: 120 } }
},
{
id: 'Heading2', name: 'Heading 2', basedOn: 'Normal',
run: { bold: true, size: 26, color: '2E74B5', font: 'Calibri' },
paragraph: { spacing: { before: 240, after: 80 } }
},
{
id: 'Heading3', name: 'Heading 3', basedOn: 'Normal',
run: { bold: true, size: 24, color: '2E74B5', font: 'Calibri' },
paragraph: { spacing: { before: 180, after: 60 } }
}
]
},
sections: [{
properties: {
page: {
margin: { top: 1080, bottom: 1080, left: 1080, right: 1080 }
}
},
children: [
...coverPage,
...q1,
...q2,
...q3,
...q4a,
...q4b,
...q4c
]
}]
});
Packer.toBuffer(doc).then(buf => {
fs.writeFileSync('/home/daytona/workspace/ms-surgery-answers/MS_Surgery_July2020_Paper1_ModelAnswers.docx', buf);
console.log('SUCCESS: file written');
}).catch(e => { console.error('ERROR:', e.message); process.exit(1); });
cd /home/daytona/workspace/ms-surgery-answers && node paper_july2020_paper1.js 2>&1
python3 /home/daytona/skills/docx/scripts/office/validate.py /home/daytona/workspace/ms-surgery-answers/MS_Surgery_July2020_Paper1_ModelAnswers.docx 2>&1 && ls -lh /home/daytona/workspace/ms-surgery-answers/
ls -lh /home/daytona/workspace/ms-surgery-answers/ && python3 -c " from pypdf import PdfReader # quick check the docx is a valid zip (docx format) import zipfile z = zipfile.ZipFile('/home/daytona/workspace/ms-surgery-answers/MS_Surgery_July2020_Paper1_ModelAnswers.docx') print('Valid DOCX (ZIP) - files inside:') for n in z.namelist()[:8]: print(' ', n) print(f' ... ({len(z.namelist())} total files)') "
MS Surgery July2020 Paper1 ModelAnswers
Word Document · DOCX
| Q | Topic | Marks | Coverage |
|---|---|---|---|
| Q.1 | Spleen — Surgical Anatomy, Physiology, Splenectomy | 30 | Ligaments table, blood supply diagram (ASCII), microscopic anatomy, functions table, indications, open + lap technique step-by-step, all complications including OPSI flowchart |
| Q.2 | Lymphoedema — Pathophysiology, Classification, Management | 20 | Pathophysiology flowchart, ISL staging table, Milroy/Meige/Tarda comparison, CDT 2-phase diagram, surgical options table (LVA, VLNT, Charles, Homans) |
| Q.3 | Shock — Pathophysiology, Classification, Resuscitation | 20 | ATLS Class I-IV table, shock pathophysiology flowchart, resuscitation flowchart by type (haemorrhagic DCR, Surviving Sepsis Hour-1 Bundle, anaphylaxis, cardiogenic) |
| Q.4(a) | Total Parenteral Nutrition (TPN) | 10 | Composition table, access routes, metabolic complications diagram (refeeding syndrome), monitoring schedule |
| Q.4(b) | Blast Injuries | 10 | PRIMARY–QUINARY classification table, blast lung, blast injury management flowchart |
| Q.4(c) | Assessment of Burns Area | 10 | Rule of Nines diagram, Lund & Browder chart table, palmar method, Parkland formula boxed |
Create a PDF version with professional diagrams and flowcharts
python3 -c "import reportlab; print(reportlab.Version)" 2>&1
Create a PDF version with professional diagrams and flowcharts
~/ms-surgery-answers/gen_pdf.py
#!/usr/bin/env python3
"""
MS General Surgery – July 2020 Paper I
Professional PDF with diagrams, flowcharts, tables
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
PageBreak, HRFlowable, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.graphics.shapes import (
Drawing, Rect, String, Line, Polygon, Arrow,
Group, Path, Circle, Ellipse
)
from reportlab.graphics.charts.barcharts import VerticalBarChart
from reportlab.graphics import renderPDF
import math
# ── Colour palette ─────────────────────────────────────────────────────────────
NAVY = colors.HexColor('#1F3864')
BLUE = colors.HexColor('#2E75B6')
LTBLUE = colors.HexColor('#BDD7EE')
VLTBLUE = colors.HexColor('#DEEAF1')
TEAL = colors.HexColor('#00B0A0')
LTTEAL = colors.HexColor('#C7F5F0')
RED = colors.HexColor('#C00000')
ORANGE = colors.HexColor('#ED7D31')
LTORANGE = colors.HexColor('#FCE4D6')
GREEN = colors.HexColor('#375623')
LTGREEN = colors.HexColor('#E2EFDA')
GOLD = colors.HexColor('#FFC000')
LTGOLD = colors.HexColor('#FFF2CC')
GREY = colors.HexColor('#595959')
LTGREY = colors.HexColor('#F2F2F2')
WHITE = colors.white
BLACK = colors.black
W, H = A4 # 595 x 842 pt
# ── Styles ────────────────────────────────────────────────────────────────────
ss = getSampleStyleSheet()
def make_style(name, parent='Normal', **kw):
return ParagraphStyle(name, parent=ss[parent], **kw)
sTitle = make_style('sTitle', fontSize=26, textColor=NAVY, alignment=TA_CENTER,
fontName='Helvetica-Bold', spaceAfter=6)
sSubTitle = make_style('sSubTitle', fontSize=14, textColor=BLUE, alignment=TA_CENTER,
fontName='Helvetica-Bold', spaceAfter=4)
sMeta = make_style('sMeta', fontSize=11, textColor=GREY, alignment=TA_CENTER,
fontName='Helvetica', spaceAfter=12)
sH1 = make_style('sH1', fontSize=15, textColor=WHITE, fontName='Helvetica-Bold',
spaceAfter=4, spaceBefore=12,
backColor=NAVY, leftIndent=-6, rightIndent=-6,
borderPadding=(5,8,5,8))
sH2 = make_style('sH2', fontSize=13, textColor=NAVY, fontName='Helvetica-Bold',
spaceAfter=3, spaceBefore=9,
borderPadding=(2,0,2,0))
sH3 = make_style('sH3', fontSize=11, textColor=BLUE, fontName='Helvetica-Bold',
spaceAfter=2, spaceBefore=6)
sBody = make_style('sBody', fontSize=10, textColor=BLACK, fontName='Helvetica',
spaceAfter=4, leading=14, alignment=TA_JUSTIFY)
sBullet = make_style('sBullet', fontSize=10, textColor=BLACK, fontName='Helvetica',
spaceAfter=3, leading=13, leftIndent=16, firstLineIndent=-10)
sNote = make_style('sNote', fontSize=10, textColor=NAVY, fontName='Helvetica-Bold',
spaceAfter=4, backColor=LTGOLD, borderPadding=(5,8,5,8),
leftIndent=4, rightIndent=4)
sCaption = make_style('sCaption', fontSize=9, textColor=GREY, fontName='Helvetica-Oblique',
alignment=TA_CENTER, spaceAfter=6)
def H1(txt):
return Paragraph(f' {txt}', sH1)
def H2(txt):
return Paragraph(f'<font color="#2E75B6">◆</font> {txt}', sH2)
def H3(txt):
return Paragraph(f'<font color="#2E75B6">▸</font> {txt}', sH3)
def Body(txt):
return Paragraph(txt, sBody)
def Bul(txt):
return Paragraph(f'• {txt}', sBullet)
def Note(txt):
return Paragraph(f'★ {txt}', sNote)
def Sp(h=4):
return Spacer(1, h*mm)
def HR(color=LTBLUE, thickness=1):
return HRFlowable(width='100%', thickness=thickness, color=color, spaceAfter=4, spaceBefore=4)
# ── Generic table builder ──────────────────────────────────────────────────────
def make_table(data, col_widths=None, header=True, stripe=True):
if col_widths is None:
ncol = len(data[0])
col_widths = [(W - 90) / ncol] * ncol
t = Table(data, colWidths=col_widths, repeatRows=1 if header else 0)
style = [
('FONTNAME', (0,0), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 9),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING',(0,0),(-1,-1), 4),
('LEFTPADDING',(0,0), (-1,-1), 6),
('RIGHTPADDING',(0,0),(-1,-1), 6),
('GRID', (0,0), (-1,-1), 0.5, colors.HexColor('#BFBFBF')),
('ROWBACKGROUNDS',(0,0),(-1,-1),[WHITE, VLTBLUE] if stripe else [WHITE]),
]
if header:
style += [
('BACKGROUND', (0,0), (-1,0), NAVY),
('TEXTCOLOR', (0,0), (-1,0), WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 10),
('ALIGN', (0,0), (-1,0), 'CENTER'),
]
t.setStyle(TableStyle(style))
return t
# ══════════════════════════════════════════════════════════════════════════════
# FLOWCHART ENGINE (pure vector via reportlab.graphics)
# ══════════════════════════════════════════════════════════════════════════════
def box(d, x, y, w, h, text, fill=LTBLUE, text_color=NAVY, font='Helvetica', fsize=9, bold=False):
fn = 'Helvetica-Bold' if bold else font
d.add(Rect(x, y, w, h, rx=4, ry=4, fillColor=fill, strokeColor=NAVY, strokeWidth=1))
# wrap text
lines = text.split('\n')
line_h = fsize * 1.3
ty = y + h/2 + (len(lines)-1) * line_h / 2
for line in lines:
d.add(String(x + w/2, ty - fsize*0.3, line,
textAnchor='middle', fillColor=text_color,
fontName=fn, fontSize=fsize))
ty -= line_h
def diamond(d, x, y, w, h, text, fill=LTGOLD, text_color=NAVY, fsize=9):
cx, cy = x + w/2, y + h/2
pts = [cx, y+h, x+w, cy, cx, y, x, cy]
d.add(Polygon(pts, fillColor=fill, strokeColor=ORANGE, strokeWidth=1.2))
d.add(String(cx, cy - fsize*0.35, text,
textAnchor='middle', fillColor=text_color,
fontName='Helvetica-Bold', fontSize=fsize))
def arrow_down(d, x, y, length=18, color=NAVY):
d.add(Line(x, y, x, y - length, strokeColor=color, strokeWidth=1.5))
d.add(Polygon([x-4, y-length+6, x+4, y-length+6, x, y-length],
fillColor=color, strokeColor=color))
def arrow_right(d, x, y, length=18, color=NAVY):
d.add(Line(x, y, x+length, y, strokeColor=color, strokeWidth=1.5))
d.add(Polygon([x+length-6, y-4, x+length-6, y+4, x+length, y],
fillColor=color, strokeColor=color))
def label(d, x, y, text, color=GREY, fsize=8):
d.add(String(x, y, text, textAnchor='middle', fillColor=color,
fontName='Helvetica-Oblique', fontSize=fsize))
# ─────────────────────────────────────────────────────────────────────────────
# DIAGRAM 1: Splenic Blood Supply
# ─────────────────────────────────────────────────────────────────────────────
def diag_splenic_blood_supply():
dw, dh = 480, 260
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=LTBLUE, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, 'SPLENIC BLOOD SUPPLY',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=11))
# Nodes top→bottom
bw, bh = 160, 28
cx = dw/2 - bw/2
nodes = [
(cx, dh-52, bw, bh, 'Coeliac Axis', NAVY, WHITE, True),
(cx, dh-100, bw, bh, 'Splenic Artery (tortuous)', BLUE, WHITE, True),
(cx, dh-148, bw, bh, 'Trabecular Arteries', LTBLUE, NAVY, False),
(cx, dh-196, bw, bh, 'Central Arteries', LTBLUE, NAVY, False),
]
for (bx,by,bww,bhh,txt,fill,tc,bold) in nodes:
box(d, bx, by, bww, bhh, txt, fill, tc, bold=bold)
for i in range(len(nodes)-1):
_, y1, _, bh1, _, _, _, _ = nodes[i]
_, y2, _, _, _, _, _, _ = nodes[i+1]
arrow_down(d, dw/2, y1, length=y1-y2-bh1+2)
# Split into open/closed
split_y = dh - 222
box(d, 30, split_y-26, 150, 28, 'Open Circulation\n(Fast – Sinuses)', LTTEAL, NAVY)
box(d, dw-180, split_y-26, 150, 28, 'Closed Circulation\n(Slow – Cords)', LTORANGE, NAVY)
# lines from Central Arteries
d.add(Line(dw/2, dh-196, dw/2, split_y, strokeColor=NAVY, strokeWidth=1.2))
d.add(Line(dw/2, split_y, 105, split_y, strokeColor=NAVY, strokeWidth=1.2))
d.add(Line(dw/2, split_y, dw-105, split_y, strokeColor=NAVY, strokeWidth=1.2))
arrow_down(d, 105, split_y, length=split_y-(split_y-26), color=TEAL)
arrow_down(d, dw-105, split_y, length=split_y-(split_y-26), color=ORANGE)
# Merge → splenic vein
merge_y = split_y - 70
d.add(Line(105, split_y-26, 105, merge_y+14, strokeColor=NAVY, strokeWidth=1.2))
d.add(Line(dw-105, split_y-26, dw-105, merge_y+14, strokeColor=NAVY, strokeWidth=1.2))
d.add(Line(105, merge_y+14, dw-105, merge_y+14, strokeColor=NAVY, strokeWidth=1.2))
arrow_down(d, dw/2, merge_y+14, length=14)
box(d, cx, merge_y-28, bw, 28, 'Splenic Vein → Portal Vein', BLUE, WHITE, bold=True)
return d
# ─────────────────────────────────────────────────────────────────────────────
# DIAGRAM 2: OPSI Flowchart
# ─────────────────────────────────────────────────────────────────────────────
def diag_opsi():
dw, dh = 480, 320
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=colors.HexColor('#C00000'), strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, 'MANAGEMENT OF OPSI',
textAnchor='middle', fillColor=RED, fontName='Helvetica-Bold', fontSize=11))
cx = dw/2
bw = 310
bx = cx - bw/2
steps = [
(dh-50, 'Asplenic patient presents with fever / rigors / lethargy', LTORANGE, NAVY),
(dh-105, 'DO NOT WAIT for results\n→ Blood cultures × 2 THEN IV Ceftriaxone 2g STAT', RED, WHITE),
(dh-165, 'Immediate hospital admission\nFull sepsis workup (FBC, CRP, Lactate, Blood Cultures)', LTBLUE, NAVY),
(dh-225, 'Sepsis-6 bundle\nO₂ • IV fluids • Repeat cultures • Urine output monitor', LTBLUE, NAVY),
(dh-280, 'ICU if SOFA score ≥2 or deteriorating\nConsider vasopressors (Noradrenaline)', colors.HexColor('#C00000'), WHITE),
]
for (y, txt, fill, tc) in steps:
box(d, bx, y-22, bw, 38, txt, fill, tc, fsize=9)
for i in range(len(steps)-1):
y1 = steps[i][0] - 22
y2 = steps[i+1][0] + 16
arrow_down(d, cx, y1, length=y1-y2)
return d
# ─────────────────────────────────────────────────────────────────────────────
# DIAGRAM 3: Lymphoedema Pathophysiology
# ─────────────────────────────────────────────────────────────────────────────
def diag_lymph_path():
dw, dh = 480, 300
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=LTBLUE, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, 'PATHOPHYSIOLOGY OF LYMPHOEDEMA',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=11))
cx = dw/2
bw = 340; bx = cx - bw/2
steps = [
(dh-52, 'Lymphatic Obstruction / Aplasia / Damage', NAVY, WHITE),
(dh-100, 'Reduced lymphatic transport capacity\n(Normal: 2–4 L interstitial fluid/day)', BLUE, WHITE),
(dh-155, 'Protein-rich fluid accumulates in interstitium\n→ ↑ Oncotic pressure → more water retention', LTBLUE, NAVY),
(dh-210, 'Macrophage infiltration → TGF-β, IL-6, VEGF-C\n→ Fibroblast activation → Collagen deposition', LTORANGE, NAVY),
(dh-258, 'Adipose hypertrophy + irreversible fibrosis\n→ ELEPHANTIASIS (Stage III)', RED, WHITE),
]
for (y, txt, fill, tc) in steps:
box(d, bx, y-22, bw, 36, txt, fill, tc, fsize=9)
for i in range(len(steps)-1):
y1 = steps[i][0] - 22
y2 = steps[i+1][0] + 14
arrow_down(d, cx, y1, length=y1-y2)
# side annotation
d.add(String(dw-10, dh-155, 'Recurrent\nCellulitis\nworsens↓',
textAnchor='end', fillColor=RED, fontName='Helvetica-Oblique', fontSize=8))
return d
# ─────────────────────────────────────────────────────────────────────────────
# DIAGRAM 4: CDT Flowchart
# ─────────────────────────────────────────────────────────────────────────────
def diag_cdt():
dw, dh = 480, 280
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=TEAL, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, 'COMPLETE DECONGESTIVE THERAPY (CDT)',
textAnchor='middle', fillColor=TEAL, fontName='Helvetica-Bold', fontSize=11))
# Phase 1 box
box(d, 20, dh-80, 200, 55, 'PHASE 1 — Intensive (2–4 weeks)', TEAL, WHITE, bold=True, fsize=9)
items1 = ['• Manual Lymphatic Drainage (MLD)', '• Multilayer compression bandaging',
'• Skin care (antifungals, moisturisers)', '• Prescribed exercises']
for i, item in enumerate(items1):
d.add(String(30, dh-100-i*13, item, fillColor=NAVY, fontName='Helvetica', fontSize=8))
# Phase 2 box
box(d, 20, dh-210, 200, 55, 'PHASE 2 — Maintenance (lifelong)', LTGREEN, GREEN, bold=True, fsize=9)
items2 = ['• Compression garments (Class 2–3)', '• Self-MLD technique',
'• Ongoing prescribed exercises', '• Skin care + infection prophylaxis']
for i, item in enumerate(items2):
d.add(String(30, dh-230-i*13, item, fillColor=GREEN, fontName='Helvetica', fontSize=8))
# Arrow between phases
arrow_down(d, 120, dh-80, length=75)
# Right side surgical options
box(d, 260, dh-80, 200, 55, 'SURGICAL OPTIONS', NAVY, WHITE, bold=True, fsize=9)
surgs = ['• LVA (Lymphatico-venous anastomosis)', '• VLNT (Vascularised LN transfer)',
'• Liposuction (fat-dominated)', '• Charles procedure (Stage III)']
for i, s in enumerate(surgs):
d.add(String(268, dh-100-i*13, s, fillColor=NAVY, fontName='Helvetica', fontSize=8))
# connect
d.add(Line(240, dh-52, 260, dh-52, strokeColor=NAVY, strokeWidth=1))
d.add(String(250, dh-44, 'If\nfailed', textAnchor='middle', fillColor=GREY,
fontName='Helvetica-Oblique', fontSize=7))
return d
# ─────────────────────────────────────────────────────────────────────────────
# DIAGRAM 5: Shock Pathophysiology
# ─────────────────────────────────────────────────────────────────────────────
def diag_shock_path():
dw, dh = 480, 340
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=RED, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, 'PATHOPHYSIOLOGY OF SHOCK',
textAnchor='middle', fillColor=RED, fontName='Helvetica-Bold', fontSize=11))
cx = dw/2; bw = 320; bx = cx-bw/2
steps = [
(dh-52, 'Precipitating Trigger\n(haemorrhage / sepsis / cardiac failure / anaphylaxis)', NAVY, WHITE),
(dh-108, '↓ Cardiac Output AND/OR ↓ SVR\n→ MAP < 65 mmHg → Tissue Hypoperfusion', BLUE, WHITE),
(dh-166, 'COMPENSATORY PHASE (reversible)\nBaroreceptors → SNS → ↑HR, ↑Contractility\nRAAA → Aldosterone → Na⁺/H₂O retention\nADH (vasopressin) → water reabsorption', LTBLUE, NAVY),
(dh-234, 'PROGRESSIVE PHASE\nAnaerobic glycolysis → Lactic acidosis\nCapillary leak (histamine/cytokines)\nMicrovascular sludging, microthrombi\nNa⁺/K⁺-ATPase failure → cell swelling', LTORANGE, NAVY),
(dh-296, 'IRREVERSIBLE SHOCK\n→ MODS (Multi-Organ Dysfunction Syndrome) → DEATH', RED, WHITE),
]
bhs = [36, 36, 58, 58, 36]
ys = []
for i, ((y, txt, fill, tc), bh) in enumerate(zip(steps, bhs)):
box(d, bx, y-bh//2, bw, bh, txt, fill, tc, fsize=9)
ys.append((y, bh))
for i in range(len(ys)-1):
y1, bh1 = ys[i]; y2, bh2 = ys[i+1]
arrow_down(d, cx, y1-bh1//2, length=y1-bh1//2 - (y2+bh2//2))
return d
# ─────────────────────────────────────────────────────────────────────────────
# DIAGRAM 6: Shock Resuscitation Flowchart
# ─────────────────────────────────────────────────────────────────────────────
def diag_shock_resus():
dw, dh = 510, 400
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=NAVY, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, 'SHOCK RESUSCITATION ALGORITHM',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=11))
# Top box – recognition
box(d, 90, dh-58, 330, 30, 'RECOGNITION: MAP<65 / HR>100 / ↓UO / Altered GCS', NAVY, WHITE, bold=True, fsize=9)
arrow_down(d, dw/2, dh-58, length=20)
# ABCDE box
box(d, 90, dh-108, 330, 30, 'ABCDE PRIMARY SURVEY | O₂ 15L/min | IV Access × 2', BLUE, WHITE, fsize=9)
arrow_down(d, dw/2, dh-108, length=16)
# Investigations box
box(d, 90, dh-154, 330, 30,
'Bloods: FBC • U&E • LFT • Coag • XM • ABG • Lactate\nImaging: CXR | FAST | eFAST | CT', LTBLUE, NAVY, fsize=8)
arrow_down(d, dw/2, dh-154, length=16)
# Identify type
diamond(d, dw/2-55, dh-218, 110, 36, 'Identify Type', LTGOLD, NAVY, fsize=9)
arrow_down(d, dw/2, dh-218, length=14)
# Four branches
types = [
(30, 'HAEMORRHAGIC\n• Permissive hypotension SBP 80-90\n• MTP 1:1:1 (pRBC:FFP:Plt)\n• TXA 1g IV < 3hrs\n• Surgical haemostasis', LTORANGE, NAVY),
(150, 'SEPTIC\n• Cultures × 2 FIRST\n• Abx within 1 hour\n• 30mL/kg crystalloid\n• Noradrenaline if MAP<65', LTBLUE, NAVY),
(280, 'CARDIOGENIC\n• Treat cause (PCI/pericardiocentesis)\n• Dobutamine/Dopamine\n• IABP / ECMO if refractory', LTGREEN, GREEN),
(400, 'ANAPHYLACTIC\n• Adrenaline 0.5mg IM (1:1000)\n• Remove trigger / O₂\n• Chlorphenamine + Hydrocortisone', LTTEAL, TEAL),
]
branch_y = dh-232
# horizontal line
d.add(Line(30, branch_y-20, 480, branch_y-20, strokeColor=NAVY, strokeWidth=1))
for (bx, txt, fill, tc) in types:
bw2 = 112
# vertical drop
d.add(Line(bx + bw2//2, branch_y-20, bx + bw2//2, branch_y-38, strokeColor=NAVY, strokeWidth=1))
d.add(Polygon([bx+bw2//2-4, branch_y-34, bx+bw2//2+4, branch_y-34, bx+bw2//2, branch_y-38],
fillColor=NAVY, strokeColor=NAVY))
box(d, bx, branch_y-120, bw2, 78, txt, fill, tc, fsize=7.5)
# Endpoints row
arrow_down(d, dw/2, branch_y-120, length=18)
box(d, 60, branch_y-162, 390, 26,
'TARGET: MAP≥65 | UO≥0.5 mL/kg/hr | Lactate<2 | ScvO₂>70% | Base excess normalised',
NAVY, WHITE, bold=True, fsize=8)
return d
# ─────────────────────────────────────────────────────────────────────────────
# DIAGRAM 7: ATLS Haemorrhage Classes
# ─────────────────────────────────────────────────────────────────────────────
def diag_atls():
dw, dh = 480, 160
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=LTBLUE, strokeWidth=1, rx=4))
d.add(String(dw/2, dh-14, 'ATLS CLASSIFICATION OF HAEMORRHAGIC SHOCK (70 kg adult)',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=9))
cols = ['CLASS I', 'CLASS II', 'CLASS III', 'CLASS IV']
fills = [LTGREEN, LTGOLD, LTORANGE, colors.HexColor('#FFCCCC')]
losses = ['<750 mL\n(<15%)', '750–1500 mL\n(15–30%)', '1500–2000 mL\n(30–40%)', '>2000 mL\n(>40%)']
params = ['HR <100\nBP normal\nAnxious', 'HR 100–120\n↓Pulse pressure\nMildly anxious', 'HR >120\n↓↓ BP\nConfused', 'HR >140\nNegligible BP\nUnconscionable']
for i in range(4):
bx = 10 + i*117; bw2 = 112
box(d, bx, dh-44, bw2, 24, cols[i], NAVY, WHITE, bold=True, fsize=9)
box(d, bx, dh-78, bw2, 28, losses[i], fills[i], NAVY, fsize=8)
box(d, bx, dh-138, bw2, 54, params[i], fills[i], NAVY, fsize=8)
return d
# ─────────────────────────────────────────────────────────────────────────────
# DIAGRAM 8: TPN Complications
# ─────────────────────────────────────────────────────────────────────────────
def diag_tpn():
dw, dh = 480, 240
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=LTBLUE, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, 'TPN COMPLICATIONS OVERVIEW',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=11))
# Three columns
cols_data = [
('CATHETER-RELATED', LTBLUE, NAVY,
['Pneumothorax (insertion)', 'Haemothorax / Air embolism',
'CLABSI (S. epidermidis)', 'Catheter thrombosis', 'Subclavian vein stenosis']),
('METABOLIC', LTGOLD, NAVY,
['Hyperglycaemia → insulin Rx', 'Refeeding syndrome\n(↓PO₄, ↓K⁺, ↓Mg²⁺)', 'Hyperlipidaemia',
'Metabolic acidosis', 'Electrolyte imbalance']),
('HEPATIC/GIT', LTORANGE, NAVY,
['Hepatic steatosis (fatty liver)', 'Cholestasis / Gallstones',
'Intestinal villous atrophy\n(disuse)', 'Bacterial translocation', 'Gut mucosal atrophy']),
]
col_w = 148
for ci, (hdr, fill, tc, items) in enumerate(cols_data):
bx = 8 + ci*(col_w+6)
box(d, bx, dh-46, col_w, 24, hdr, NAVY, WHITE, bold=True, fsize=9)
for ii, item in enumerate(items):
box(d, bx, dh-82-ii*36, col_w, 30, item, fill, tc, fsize=8)
return d
# ─────────────────────────────────────────────────────────────────────────────
# DIAGRAM 9: Rule of Nines – Body Diagram (schematic)
# ─────────────────────────────────────────────────────────────────────────────
def diag_rule_of_nines():
dw, dh = 480, 320
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=LTBLUE, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, 'RULE OF NINES — TBSA ASSESSMENT',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=11))
# Left: Anterior body diagram (schematic)
cx = 120
# Head
d.add(Ellipse(cx, dh-70, 28, 28, fillColor=LTBLUE, strokeColor=NAVY, strokeWidth=1))
d.add(String(cx+38, dh-68, '9% Head & Neck', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=9))
# Trunk
d.add(Rect(cx-30, dh-150, 60, 72, fillColor=LTBLUE, strokeColor=NAVY, strokeWidth=1))
d.add(String(cx+38, dh-118, '18% Anterior trunk', fillColor=NAVY, fontName='Helvetica', fontSize=8.5))
d.add(String(cx+38, dh-132, '18% Posterior trunk', fillColor=GREY, fontName='Helvetica', fontSize=8.5))
# Arms
d.add(Rect(cx-68, dh-148, 30, 64, rx=6, ry=6, fillColor=LTTEAL, strokeColor=NAVY, strokeWidth=1))
d.add(Rect(cx+38, dh-148, 30, 64, rx=6, ry=6, fillColor=LTTEAL, strokeColor=NAVY, strokeWidth=1))
d.add(String(cx-68, dh-100, '9%\nEach arm', fillColor=TEAL, fontName='Helvetica-Bold', fontSize=8, textAnchor='middle'))
# Perineum
d.add(Ellipse(cx, dh-163, 8, 8, fillColor=GOLD, strokeColor=NAVY, strokeWidth=1))
d.add(String(cx+38, dh-150, '1% Perineum', fillColor=NAVY, fontName='Helvetica', fontSize=8.5))
# Legs
d.add(Rect(cx-42, dh-272, 34, 100, rx=6, ry=6, fillColor=LTORANGE, strokeColor=NAVY, strokeWidth=1))
d.add(Rect(cx+8, dh-272, 34, 100, rx=6, ry=6, fillColor=LTORANGE, strokeColor=NAVY, strokeWidth=1))
d.add(String(cx+38, dh-240, '18% Each leg', fillColor=ORANGE, fontName='Helvetica-Bold', fontSize=8.5))
# Total
box(d, cx-60, 10, 120, 24, 'TOTAL = 100%', NAVY, WHITE, bold=True, fsize=10)
# Right: Table comparison
tbl_data = [
['Region', 'Adult', 'Child (1 yr)'],
['Head & Neck', '9%', '18%'],
['Each arm', '9%', '9%'],
['Anterior trunk', '18%', '18%'],
['Posterior trunk', '18%', '18%'],
['Each thigh', '9%', '6.5%'],
['Each lower leg', '9%', '7%'],
['Perineum', '1%', '1%'],
['TOTAL', '100%', '100%'],
]
t = make_table(tbl_data, col_widths=[120, 52, 72])
# render table as drawing at right side
# We'll just output the table separately in the story
d.add(String(310, dh-28, 'Comparison Table →', fillColor=NAVY,
fontName='Helvetica-Bold', fontSize=9))
return d
# ─────────────────────────────────────────────────────────────────────────────
# DIAGRAM 10: Blast Injury Classification
# ─────────────────────────────────────────────────────────────────────────────
def diag_blast():
dw, dh = 480, 260
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=RED, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, 'CLASSIFICATION OF BLAST INJURIES',
textAnchor='middle', fillColor=RED, fontName='Helvetica-Bold', fontSize=11))
# Central explosion circle
cx, cy = dw/2, dh/2 - 10
d.add(Ellipse(cx, cy, 38, 38, fillColor=GOLD, strokeColor=RED, strokeWidth=2))
d.add(String(cx, cy+4, 'BLAST', textAnchor='middle', fillColor=RED, fontName='Helvetica-Bold', fontSize=9))
d.add(String(cx, cy-8, 'EVENT', textAnchor='middle', fillColor=RED, fontName='Helvetica-Bold', fontSize=9))
# 5 rays
ray_data = [
(90, 'PRIMARY\nBlast wave\nEar/Lung/Bowel\nruptured', LTORANGE),
(180, 'SECONDARY\nFragmentation\nPenetrating injuries', LTBLUE),
(270, 'TERTIARY\nBlast wind\nBlunt trauma\nAmputations', LTGREEN),
(0, 'QUATERNARY\nBurns/Crush\nInhalation injury', colors.HexColor('#FFCCCC')),
(315, 'QUINARY\nHyperinflammatory\nBacterial/Radiation', LTGREY),
]
for angle_deg, txt, fill in ray_data:
rad = math.radians(angle_deg)
rx = cx + math.cos(rad)*100
ry = cy + math.sin(rad)*80
bx = rx - 56; by = ry - 24
box(d, bx, by, 112, 46, txt, fill, NAVY, fsize=8)
# line
lx = cx + math.cos(rad)*38
ly = cy + math.sin(rad)*38
ex = cx + math.cos(rad)*74
ey = cy + math.sin(rad)*60
d.add(Line(lx, ly, ex, ey, strokeColor=NAVY, strokeWidth=1))
return d
# ──────────────────────────────────────────────────────────────────────────────
# SPLENECTOMY TECHNIQUE DIAGRAM
# ──────────────────────────────────────────────────────────────────────────────
def diag_splenectomy():
dw, dh = 480, 290
d = Drawing(dw, dh)
d.add(Rect(0, 0, dw, dh, fillColor=WHITE, strokeColor=BLUE, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, 'STEPS OF OPEN SPLENECTOMY',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=11))
bw = 200; gap = 10
# Two columns
left_steps = [
'1. Position: Supine / Right lateral',
'2. Incision: Left subcostal (Kocher)',
'3. Divide splenocolic ligament',
'4. Ligate short gastric vessels',
'5. Divide splenorenal ligament',
]
right_steps = [
'6. Displace spleen medially',
'7. Ligate SPLENIC ARTERY first ★',
'8. Ligate splenic vein',
'9. Remove spleen',
'10. Check pancreatic tail for injury',
]
# Left column header
box(d, 20, dh-46, bw, 22, 'FIRST HALF', NAVY, WHITE, bold=True, fsize=9)
for i, step in enumerate(left_steps):
fill = LTGOLD if i == 4 else LTBLUE
box(d, 20, dh-78-i*42, bw, 36, step, fill, NAVY, fsize=9)
if i < len(left_steps)-1:
arrow_down(d, 120, dh-78-i*42, length=6)
# Right column header
box(d, 260, dh-46, bw, 22, 'SECOND HALF', NAVY, WHITE, bold=True, fsize=9)
for i, step in enumerate(right_steps):
fill = RED if i == 1 else LTBLUE
tc = WHITE if i == 1 else NAVY
box(d, 260, dh-78-i*42, bw, 36, step, fill, tc, fsize=9, bold=(i==1))
if i < len(right_steps)-1:
arrow_down(d, 360, dh-78-i*42, length=6)
# arrow from left to right bottom
d.add(Line(120, dh-78-4*42+4, 120, dh-280, strokeColor=NAVY, strokeWidth=1))
d.add(Line(120, dh-280, 360, dh-280, strokeColor=NAVY, strokeWidth=1))
d.add(Line(360, dh-280, 360, dh-78-4*42+4, strokeColor=NAVY, strokeWidth=1))
return d
# ══════════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ══════════════════════════════════════════════════════════════════════════════
def wrap_drawing(d, caption=None):
items = [d]
if caption:
items.append(Paragraph(caption, sCaption))
return KeepTogether(items)
story = []
# ── COVER PAGE ────────────────────────────────────────────────────────────────
story += [
Sp(30),
Paragraph('M.S. (Branch – I) Examination', sTitle),
Paragraph('July 2020 — General Surgery : Paper I', sSubTitle),
Paragraph('Model Answers with Professional Diagrams & Flowcharts', sMeta),
HR(NAVY, 2), Sp(4),
make_table([
['Question', 'Topic', 'Marks'],
['Q 1', 'Spleen — Anatomy, Physiology, Splenectomy & Complications', '30'],
['Q 2', 'Lymphoedema — Pathophysiology, Classification & Management','20'],
['Q 3', 'Shock — Pathophysiology, Classification & Resuscitation', '20'],
['Q 4(a)', 'Total Parenteral Nutrition (TPN)', '10'],
['Q 4(b)', 'Blast Injuries', '10'],
['Q 4(c)', 'Assessment of Area of Burns', '10'],
], col_widths=[60, 360, 60]),
Sp(6), HR(NAVY, 2),
Paragraph('Time: 3 Hours | Total Marks: 100 | All Questions Compulsory', sMeta),
PageBreak(),
]
# ══════════════════════════════════════════════════════════════════════════════
# Q 1: SPLEEN
# ══════════════════════════════════════════════════════════════════════════════
story += [
H1('QUESTION 1 (30 Marks)'),
Body('Write surgical anatomy, physiology and functions of spleen. Describe indications and technique of Splenectomy and post-splenectomy complications.'),
HR(), Sp(2),
H2('A. SURGICAL ANATOMY'),
H3('1. Gross Anatomy'),
Bul('Location: Left hypochondrium, under left dome of diaphragm, 9th–11th rib level'),
Bul('Weight: 100–150 g; Dimensions: 12 × 7 × 4 cm (Rule: 1, 3, 5, 7, 9, 11)'),
Bul('Surfaces: Diaphragmatic (convex, superolateral) and Visceral (concave — gastric, renal, colic, pancreatic impressions at hilum)'),
Bul('Superior border: Notched — distinguishes from kidney on palpation'),
Bul('Peritoneal covering: Intraperitoneal organ; capsule of fibromuscular tissue with trabeculae'),
Sp(2),
H3('2. Ligaments of the Spleen'),
make_table([
['Ligament', 'Contents', 'Surgical Significance'],
['Gastrosplenic', 'Short gastric arteries\nLeft gastroepiploic', 'Divided early in splenectomy; short gastric injury risk'],
['Splenorenal (lienorenal)', 'Splenic vessels, tail of pancreas', 'Pancreatic tail injury risk during division'],
['Phrenocolic', 'None — fibrous fold', '"Sustentaculum lienis" — supports inferior pole'],
['Splenocolic', 'None — fibrous fold', 'First divided to mobilise inferior pole'],
], col_widths=[120, 160, 180]),
Sp(4),
H3('3. Blood Supply'),
wrap_drawing(diag_splenic_blood_supply(), 'Fig 1: Splenic blood supply and microcirculation'),
Sp(4),
H3('4. Histology / Microscopic Anatomy'),
make_table([
['Component', 'Structure', 'Function'],
['White pulp', 'Periarteriolar lymphoid sheaths (PALS)\nLymphoid follicles (Malpighian bodies)', 'T-cell zone (PALS), B-cell zone (follicles)\nIgM production'],
['Red pulp', 'Venous sinuses + Cords of Billroth\n(reticular cells, macrophages)', 'Filters abnormal/old RBCs\nRemoves bacteria'],
['Marginal zone', 'Interface between red and white pulp', 'First contact with blood-borne antigens\nInnate immunity'],
], col_widths=[100, 200, 170]),
Sp(4),
H2('B. PHYSIOLOGY AND FUNCTIONS'),
make_table([
['Function', 'Detail'],
['Filtration', 'Removes senescent RBCs, pitted RBCs, Howell-Jolly bodies, siderocytes, target cells, and encapsulated bacteria'],
['Immune', 'Produces IgM antibodies; opsonins — Tuftsin & Properdin; NK cells, T/B lymphocytes; response to T-independent antigens'],
['Haematopoiesis', 'Extramedullary haematopoiesis in fetal life (3rd–5th month) and in adults with marrow failure'],
['Platelet reservoir','Stores 30% of total body platelets; releases on SNS stimulation'],
['Iron recycling', 'Macrophages phagocytose effete RBCs → haem → iron recycled via transferrin'],
['Blood reservoir', 'Contracts under sympathetic stimulation releasing stored blood (~250 mL)'],
], col_widths=[130, 340]),
Sp(4),
H2('C. INDICATIONS FOR SPLENECTOMY'),
H3('Haematological Conditions'),
Bul('Hereditary spherocytosis — definitive cure'),
Bul('Immune thrombocytopenic purpura (ITP) — second-line after steroids fail'),
Bul('Haemolytic anaemias — autoimmune, thalassaemia, sickle cell (hypersplenism)'),
Bul('Thrombotic thrombocytopenic purpura (TTP) — refractory'),
Bul('Myelofibrosis with massive splenomegaly'),
H3('Traumatic'),
Bul('AAST Grade III–V splenic lacerations'),
Bul('Haemodynamic instability despite resuscitation'),
Bul('Failed non-operative management / angioembolisation'),
H3('Neoplastic / Other'),
Bul('Splenic lymphoma, hairy cell leukaemia'),
Bul('Hypersplenism secondary to portal hypertension'),
Bul('Splenic artery aneurysm > 2 cm (or in pregnancy)'),
Bul('Large splenic cysts, abscess unresponsive to drainage'),
Bul('En-bloc resection for carcinoma of gastric fundus / pancreatic tail'),
Sp(4),
H2('D. PRE-OPERATIVE PREPARATION'),
Note('Vaccinate ≥ 2 WEEKS BEFORE surgery: Pneumococcus (PCV13/PPSV23), Meningococcus ACWY, Haemophilus influenzae type b'),
Bul('Correct thrombocytopenia (steroids / IV immunoglobulin / platelet transfusion for counts < 50 × 10⁹/L)'),
Bul('Group & crossmatch, consent for open conversion if laparoscopic'),
Bul('IV antibiotic prophylaxis (Cefuroxime 1.5 g at induction)'),
Bul('VTE prophylaxis — LMWH + TED stockings'),
Sp(4),
H2('E. TECHNIQUE OF SPLENECTOMY'),
wrap_drawing(diag_splenectomy(), 'Fig 2: Operative steps of open splenectomy (★ = ligate splenic artery first)'),
Sp(4),
H3('Laparoscopic Splenectomy'),
make_table([
['Aspect', 'Details'],
['Position', 'Right lateral decubitus (45°) or supine'],
['Ports', '4 ports — 10mm camera (umbilical/left paramedian), 3× 5mm working ports in LUQ'],
['Key steps', 'Divide splenocolic lig → short gastric vessels (LigaSure/Harmonic) → splenorenal lig → clip & divide hilum → extraction bag'],
['Advantages', 'Less pain, earlier mobilisation, shorter hospital stay, lower wound infection'],
['Conversion rate', '2–5% elective; higher for splenomegaly > 20 cm or trauma'],
['Contraindications','Haemodynamic instability, splenomegaly >25 cm (relative), severe portal hypertension'],
], col_widths=[110, 360]),
Sp(4),
H2('F. POST-SPLENECTOMY COMPLICATIONS'),
H3('Immediate (0–24 hours)'),
Bul('Primary haemorrhage from splenic hilum or short gastric vessels'),
Bul('Injury to tail of pancreas → acute pancreatitis, pancreatic fistula'),
Bul('Injury to stomach wall (short gastric ligation)'),
Bul('Injury to colon, left kidney, or left diaphragm'),
H3('Early (1–30 days)'),
Bul('Reactive thrombocytosis — platelet count may exceed 1000 × 10⁹/L → DVT / PE risk'),
Bul('Left subphrenic abscess (5–10%)'),
Bul('Left pleural effusion / basal atelectasis'),
Bul('Gastric fistula from short gastric vessel injury'),
H3('Late Complications'),
Bul('Portal/mesenteric vein thrombosis (reactive thrombocytosis) — anticoagulate if detected'),
Bul('Splenosis — autotransplantation of splenic tissue at peritoneal sites'),
Bul('Increased susceptibility to malaria, babesiosis, capnocytophaga canimorsus'),
Sp(4),
Note('OVERWHELMING POST-SPLENECTOMY INFECTION (OPSI) — MORTALITY UP TO 50%'),
wrap_drawing(diag_opsi(), 'Fig 3: OPSI recognition and management flowchart'),
Sp(2),
make_table([
['OPSI Feature', 'Details'],
['Incidence', '0.5–2% lifetime risk; highest in first 2 years post-splenectomy'],
['Organisms', 'S. pneumoniae (50%), N. meningitidis (15%), H. influenzae type b (10%)'],
['Mechanism', 'Loss of: filtration, opsonisation (tuftsin, properdin), IgM production'],
['Presentation', 'Sudden onset fever → rigors → septicaemia → DIC → multi-organ failure in <24 h'],
['Prevention', 'Vaccination (pre-op) + lifelong penicillin V 250 mg BD + patient education card'],
['Treatment', 'Blood cultures → IV Ceftriaxone 2g STAT → ICU → supportive care'],
], col_widths=[130, 340]),
PageBreak(),
]
# ══════════════════════════════════════════════════════════════════════════════
# Q 2: LYMPHOEDEMA
# ══════════════════════════════════════════════════════════════════════════════
story += [
H1('QUESTION 2 (20 Marks)'),
Body('Describe Pathophysiology, Classification and Management of Lymphoedema.'),
HR(), Sp(2),
H2('A. DEFINITION'),
Body('Lymphoedema is the accumulation of protein-rich interstitial fluid resulting from inadequate lymphatic transport, causing chronic soft-tissue swelling, progressive fibrosis, and adipose hypertrophy.'),
Sp(2),
H2('B. PATHOPHYSIOLOGY'),
wrap_drawing(diag_lymph_path(), 'Fig 4: Pathophysiology of lymphoedema — cascade from lymphatic damage to elephantiasis'),
Sp(2),
Bul('Normal lymphatic system transports 2–4 litres of protein-rich interstitial fluid per day back to the systemic circulation'),
Bul('When transport capacity is exceeded or lymphatics are destroyed, protein accumulates in interstitium'),
Bul('High interstitial oncotic pressure draws more water → worsening oedema (self-perpetuating)'),
Bul('Macrophage activation releases pro-fibrotic cytokines (TGF-β1, IL-6, VEGF-C) → collagen deposition'),
Bul('Chronic lymphostasis → fat hypertrophy (adipocyte proliferation) in subcutaneous tissue'),
Bul('Immune dysfunction → recurrent bacterial cellulitis / fungal infections → further lymphatic destruction (vicious cycle)'),
Sp(4),
H2('C. CLASSIFICATION'),
H3('I. Primary Lymphoedema (congenital/idiopathic)'),
make_table([
['Type', 'Onset', 'Genetics', 'Features'],
['Milroy\'s disease', 'At birth', 'VEGFR3 mutation\nAutosomal dominant', 'Bilateral lower limbs; aplastic lymphatics'],
['Lymphoedema Praecox\n(Meige\'s disease)', 'Puberty\n(most common)', 'Sporadic / FLT4 gene', 'Female predominance; unilateral lower limb; hypoplastic lymphatics'],
['Lymphoedema Tarda', '>35 years', 'Sporadic', 'Bilateral legs; slowly progressive'],
['Lymphangiectasia', 'Neonatal', 'Variable', 'Dilated incompetent vessels; chylous ascites possible'],
], col_widths=[130, 70, 110, 160]),
Sp(4),
H3('II. Secondary Lymphoedema (acquired) — causes'),
make_table([
['Cause', 'Mechanism'],
['Filariasis (W. bancrofti)','Most common worldwide; mosquito-borne nematode; obstructs lymphatics'],
['Post-surgical', 'Axillary, inguinal, or pelvic node dissection (breast/gynaecological/urological cancers)'],
['Radiotherapy', 'Radiation fibrosis of lymphatic channels — especially after breast / pelvic RT'],
['Malignant infiltration', 'Lymphoma, nodal metastases causing extrinsic compression'],
['Infection', 'TB, lymphogranuloma venereum, recurrent cellulitis'],
['Trauma / Burns', 'Disruption / scarring of lymphatic channels'],
['Chronic venous insufficiency', 'Secondary lymphatic overload from venous hypertension'],
], col_widths=[160, 310]),
Sp(4),
H3('III. ISL Staging'),
make_table([
['Stage', 'Clinical Features', 'Reversibility'],
['0 (Latent)', 'Lymphatic damage present but no clinical oedema', 'N/A'],
['I', 'Soft pitting oedema; reduces with limb elevation', 'Fully reversible'],
['II', 'Non-pitting oedema; does not reduce with elevation;\nFibrosis begins', 'Partially reversible'],
['III (Elephantiasis)', 'Massive non-pitting oedema; skin hyperkeratosis,\npapillomatosis, warty growths, ulceration', 'Irreversible'],
], col_widths=[100, 270, 100]),
Sp(2),
Note('Stemmer\'s Sign: Inability to pinch skin fold at base of 2nd toe — PATHOGNOMONIC of lymphoedema'),
Sp(4),
H2('D. INVESTIGATIONS'),
Bul('Lymphoscintigraphy (radionuclide): Gold standard — shows lymphatic anatomy, transport index, collateral formation'),
Bul('ICG (Indocyanine Green) lymphography: Real-time fluorescence imaging; maps superficial lymphatics for LVA planning'),
Bul('Duplex ultrasound: Exclude DVT; assess venous insufficiency; shows "honeycomb" pattern in subcutaneous tissue'),
Bul('MRI / CT: Cross-sectional anatomy; rule out malignant obstruction; increased T2 signal in subcutaneous fat'),
Bul('Bioimpedance spectroscopy: Early detection (Stage 0) — L-Dex score; non-invasive'),
Sp(4),
H2('E. MANAGEMENT'),
wrap_drawing(diag_cdt(), 'Fig 5: CDT phases and surgical options for lymphoedema management'),
Sp(2),
H3('1. Conservative — Complete Decongestive Therapy (CDT)'),
make_table([
['CDT Component', 'Phase 1 (Intensive)', 'Phase 2 (Maintenance)'],
['Manual Lymph Drainage (MLD)', 'Daily by therapist', 'Self-MLD daily'],
['Compression', 'Multilayer inelastic bandaging', 'Custom-fit garments (Class 2–3)'],
['Exercise', 'Active + passive exercises', 'Prescribed exercise programme'],
['Skin care', 'Moisturisers, antifungals', 'Daily skin hygiene + vigilance'],
], col_widths=[160, 160, 150]),
Sp(2),
Bul('Pharmacological: Diethylcarbamazine (DEC) 6 mg/kg/day for 12 days for filariasis; penicillin/amoxicillin for cellulitis episodes'),
Bul('Pneumatic compression: Sequential intermittent pneumatic compression pumps as adjunct to CDT'),
Sp(4),
H3('2. Surgical Management'),
make_table([
['Procedure', 'Indication', 'Mechanism'],
['Lymphatico-Venous Anastomosis (LVA)','Stage I–II; early fibrosis','Microsurgical bypass of obstruction; lymphatic → venous'],
['Vascularised LN Transfer (VLNT)', 'Stage II; failed CDT', 'Transfers LN flap → promotes lymphangiogenesis'],
['Liposuction', 'Chronic fat-dominant (Stage II)','Removes excess adipose; requires lifelong compression post-op'],
['Charles Procedure', 'Stage III (elephantiasis)', 'Radical excision of all subcutaneous tissue + skin grafting'],
['Homans\' (staged excision)', 'Stage III alternative', 'Less disfiguring staged subcutaneous excision under flaps'],
], col_widths=[155, 125, 190]),
PageBreak(),
]
# ══════════════════════════════════════════════════════════════════════════════
# Q 3: SHOCK
# ══════════════════════════════════════════════════════════════════════════════
story += [
H1('QUESTION 3 (20 Marks)'),
Body('Pathophysiology and classification of Shock. Discuss resuscitation and management of shock.'),
HR(), Sp(2),
H2('A. DEFINITION'),
Body('Shock is a life-threatening syndrome of acute circulatory failure with inadequate cellular oxygen utilisation (DO₂ < VO₂), resulting in anaerobic metabolism, lactic acidosis, cellular dysfunction, and ultimately death if untreated.'),
Sp(2),
H2('B. PATHOPHYSIOLOGY'),
wrap_drawing(diag_shock_path(), 'Fig 6: Pathophysiological cascade in shock from trigger to MODS'),
Sp(2),
Note('Lethal Triad of Trauma Shock: Hypothermia + Coagulopathy + Acidosis — each worsens the others'),
Sp(4),
H2('C. CLASSIFICATION OF SHOCK'),
make_table([
['Type', 'Primary Mechanism', 'Examples', 'Haemodynamic Pattern'],
['Hypovolaemic', 'Loss of circulating volume', 'Haemorrhage, burns, dehydration,\nvomiting, GI losses', 'CO↓, SVR↑, CVP↓, PCWP↓'],
['Septic\n(Distributive)', 'Vasodilation + endothelial injury + cardiac depression', 'Gram-negative bacteraemia (endotoxin),\nGram-positive toxins, fungal sepsis', 'Early: CO↑, SVR↓\nLate: CO↓, SVR↓'],
['Anaphylactic\n(Distributive)', 'IgE-mediated massive vasodilation +\nbronchospasm', 'Penicillin, bee stings,\nnuts, contrast media', 'CO↓/↑, SVR↓, CVP↓'],
['Neurogenic\n(Distributive)', 'Loss of sympathetic tone → vasodilation', 'T6 or higher spinal cord injury,\nhigh spinal anaesthesia', 'CO↓, SVR↓, HR bradycardia'],
['Cardiogenic', 'Pump failure', 'STEMI, arrhythmia, valve rupture,\nmyocarditis', 'CO↓, SVR↑, CVP↑, PCWP↑'],
['Obstructive', 'Mechanical obstruction to flow', 'Massive PE, tension pneumothorax,\ncardiac tamponade, aortic dissection', 'CO↓, SVR↑, CVP↑'],
], col_widths=[90, 120, 150, 110]),
Sp(4),
H3('ATLS Classification of Haemorrhagic Shock'),
wrap_drawing(diag_atls(), 'Fig 7: ATLS haemorrhagic shock classes and haemodynamic parameters'),
Sp(4),
H2('D. RESUSCITATION AND MANAGEMENT'),
wrap_drawing(diag_shock_resus(), 'Fig 8: Shock resuscitation algorithm — type-specific treatment pathways'),
Sp(4),
H3('1. Haemorrhagic Shock — Damage Control Resuscitation (DCR)'),
make_table([
['Component', 'Detail'],
['Permissive hypotension','Target SBP 80–90 mmHg until definitive haemostasis\n(NOT in TBI — keep MAP ≥80)'],
['Massive Transfusion', 'pRBC : FFP : Platelets = 1:1:1 ratio\nTarget: Hb >7, Fibrinogen >1.5 g/L, INR <1.5'],
['Tranexamic acid', '1 g IV over 10 min within 3 hours of injury (CRASH-2 trial)\nFollowed by 1 g over 8 hours'],
['Calcium', 'CaCl₂ 1 g IV per 4 units pRBC (chelation by citrate in banked blood)'],
['Avoid lethal triad', 'Warm all fluids, warming blanket; early FFP prevents coagulopathy;\nbicarbonate for pH <7.1'],
['Definitive haemostasis','Direct surgical control / IR angioembolisation'],
], col_widths=[140, 330]),
Sp(4),
H3('2. Septic Shock — Surviving Sepsis Campaign "Hour-1 Bundle" (2018)'),
Bul('Measure lactate — if ≥ 4 mmol/L: immediate resuscitation'),
Bul('Blood cultures × 2 sets BEFORE antibiotics (do not delay antibiotics >45 min to get cultures)'),
Bul('Broad-spectrum IV antibiotics within 1 hour of recognition'),
Bul('30 mL/kg IV crystalloid (Ringer\'s Lactate preferred) for hypotension or lactate ≥ 4'),
Bul('Noradrenaline (first-line vasopressor) to maintain MAP ≥ 65 mmHg'),
Bul('Reassess fluid responsiveness: Passive leg raise (PLR) or SVV'),
Bul('Hydrocortisone 200 mg/day if refractory to vasopressors'),
Sp(4),
H3('3. Anaphylactic Shock'),
Bul('Adrenaline (epinephrine) 0.5 mg IM (1:1000) into outer thigh — FIRST LINE'),
Bul('Remove trigger, O₂ 15 L/min, IV fluid 1–2 L crystalloid bolus'),
Bul('Chlorphenamine 10 mg IV (H1-blocker), Hydrocortisone 200 mg IV'),
Bul('Salbutamol 2.5–5 mg nebulised for bronchospasm'),
Bul('Repeat adrenaline every 5 minutes if no improvement'),
Sp(4),
H3('4. Cardiogenic Shock'),
Bul('Primary PCI for STEMI (within 90 min door-to-balloon)'),
Bul('Pericardiocentesis for tamponade; needle decompression for tension pneumothorax'),
Bul('Inotropes: Dobutamine (β1-agonist) first line; Dopamine if bradycardia'),
Bul('Mechanical support: IABP (reduces afterload), ECMO (last resort)'),
Sp(4),
H3('Endpoints of Resuscitation'),
make_table([
['Parameter', 'Target'],
['MAP', '≥ 65 mmHg'],
['Urine output', '≥ 0.5 mL/kg/hour (adult); ≥ 1 mL/kg/hour (child)'],
['Serum lactate', '< 2 mmol/L; clearance ≥ 10% per 2 hours'],
['ScvO₂', '≥ 70%'],
['Base excess', '> −2 mEq/L'],
['Temperature', '≥ 36°C'],
['INR / Coagulation', 'INR < 1.5; Fibrinogen > 1.5 g/L'],
], col_widths=[160, 310]),
PageBreak(),
]
# ══════════════════════════════════════════════════════════════════════════════
# Q 4(a): TPN
# ══════════════════════════════════════════════════════════════════════════════
story += [
H1('QUESTION 4(a) — Total Parenteral Nutrition (TPN)'),
HR(), Sp(2),
H2('Definition'),
Body('TPN is the complete intravenous provision of all macronutrients (carbohydrates, proteins, lipids), micronutrients (vitamins, trace elements), electrolytes, and fluid when the gastrointestinal tract cannot be used or is insufficient.'),
Sp(2),
H2('Indications'),
make_table([
['Category', 'Clinical Examples'],
['GI failure', 'Paralytic ileus, short bowel syndrome, high-output enteric fistula (>500 mL/day), intestinal obstruction'],
['GI inaccessibility','Severe acute pancreatitis (when EN fails), oesophageal/gastric surgery, bowel obstruction'],
['Inflammatory', 'Crohn\'s disease with fistula / toxic megacolon, severe IBD'],
['Oncological', 'Bone marrow transplant, chemotherapy-induced mucositis, severe anorexia'],
['Neonatal', 'Necrotising enterocolitis, very low birth weight, congenital GI anomalies'],
], col_widths=[130, 340]),
Sp(4),
H2('Composition and Requirements'),
make_table([
['Component', 'Daily Requirement', 'Source / Preparation', 'Energy Yield'],
['Carbohydrate', '3–5 g/kg/day\n(50–60% non-protein kcal)', 'Dextrose (glucose) 50%\n(GIR < 5 mg/kg/min)', '3.4 kcal/g'],
['Amino acids', '1.2–2.0 g/kg/day\n(0.2–0.3 g N/kg/day)', 'Crystalline amino acid solutions\n(essential + non-essential)', '4 kcal/g'],
['Lipid emulsion','1–2 g/kg/day\n(20–30% non-protein kcal)', 'Intralipid 20%\n(SMOF lipid — mixed oils)', '9 kcal/g'],
['Total calories','25–30 kcal/kg/day\n(non-obese, non-septic)', 'Non-protein:nitrogen ratio = 150:1', '—'],
['Electrolytes', 'Adjusted daily', 'Na⁺, K⁺, Ca²⁺, Mg²⁺, PO₄³⁻', '—'],
['Vitamins', 'Per AMA/ASPEN guidelines','Water-soluble (B-complex, C) +\nFat-soluble (A, D, E, K)', '—'],
['Trace elements','Per ASPEN guidelines', 'Zn, Cu, Se, Cr, Mn, Fe, I', '—'],
], col_widths=[80, 110, 160, 70]),
Sp(4),
H2('Vascular Access'),
make_table([
['Route', 'Indication', 'Key Points'],
['Central venous catheter (CVC)', 'Standard TPN', 'Subclavian > Internal jugular > Femoral; osmolarity can be high (>2000 mOsm/L)'],
['PICC line', 'Long-term TPN >2 weeks', 'Peripherally inserted; basilic > cephalic vein; lower infection risk than CVC'],
['Peripheral PN', 'Short-term (<7 days)', 'Osmolarity MUST be <800 mOsm/L; thrombophlebitis limits use'],
], col_widths=[140, 100, 230]),
Sp(4),
H2('Complications'),
wrap_drawing(diag_tpn(), 'Fig 9: TPN complications — catheter-related, metabolic, and hepatic/GI'),
Sp(2),
Note('Refeeding Syndrome: Occurs in severely malnourished patients when TPN is started rapidly — ↓ PO₄, ↓ K⁺, ↓ Mg²⁺ due to intracellular shift. Start TPN SLOWLY (50% of target), monitor electrolytes 4-hourly, supplement phosphate.'),
Sp(4),
H2('Monitoring of TPN'),
make_table([
['Frequency', 'Parameters'],
['4–6 hourly', 'Blood glucose (target 6–10 mmol/L); insulin infusion if >10'],
['Daily', 'Electrolytes (Na, K, Mg, Ca, PO₄), fluid balance, weight, clinical assessment'],
['Twice weekly','LFTs, urea & creatinine, triglycerides, FBC'],
['Weekly', 'Coagulation, trace elements, vitamins, nitrogen balance assessment'],
], col_widths=[100, 370]),
Sp(2),
Bul('Transition to enteral nutrition as soon as clinically feasible — gut "use it or lose it"'),
Bul('Cycle TPN over 12–16 hours if long-term (prevents liver dysfunction, improves quality of life)'),
PageBreak(),
]
# ══════════════════════════════════════════════════════════════════════════════
# Q 4(b): BLAST INJURIES
# ══════════════════════════════════════════════════════════════════════════════
story += [
H1('QUESTION 4(b) — Blast Injuries'),
HR(), Sp(2),
H2('Definition'),
Body('Blast injuries result from the sudden release of large amounts of energy from an explosive device, creating a supersonic pressure wave (blast wave), blast wind, fragmentation, and secondary ignition — producing a unique pattern of multi-system injuries.'),
Sp(2),
H2('Classification of Blast Injuries'),
wrap_drawing(diag_blast(), 'Fig 10: Five-category classification of blast injuries with affected organ systems'),
Sp(4),
make_table([
['Category', 'Mechanism', 'Organs Affected', 'Key Injuries'],
['PRIMARY', 'Blast overpressure wave\n(solid–gas interfaces most vulnerable)', 'Lung, Ear, Bowel, Brain', 'Blast lung (pulmonary contusion/haemorrhage), TM rupture, hollow viscus perforation, PTBI'],
['SECONDARY', 'Fragmentation — bomb casing, glass, nails, shrapnel penetrating body', 'Any', 'Penetrating wounds, impalement, ocular injuries'],
['TERTIARY', 'Blast wind — victim thrown against solid objects', 'Musculoskeletal, Brain', 'Traumatic amputations, fractures, head injury'],
['QUATERNARY', 'All other blast effects', 'Skin, Lungs, CNS', 'Burns (thermal/chemical), crush injuries, inhalation injury, toxic gas exposure'],
['QUINARY', 'Additives in device (bacteria, radioactive material)', 'Systemic', 'Hyperinflammatory state, radiation injury, bioterrorism agents'],
], col_widths=[75, 120, 100, 175]),
Sp(4),
H2('Specific Injuries'),
H3('Blast Lung (Most Serious Primary Blast Injury)'),
Bul('Mechanism: Rapid pressure wave causes alveolar haemorrhage, contusion, pneumothorax, haemothorax, air embolism'),
Bul('Presentation: May be initially asymptomatic → delayed onset up to 48 hours'),
Bul('"Butterfly" or "batwing" pattern opacification on CXR'),
Note('AVOID high positive airway pressure ventilation (risk of tension pneumothorax/air embolism) — use low tidal volume, permissive hypercapnia strategy'),
H3('Abdominal Blast Injury'),
Bul('Air-filled viscera (colon > small bowel > stomach) most susceptible to primary blast'),
Bul('Delayed perforation possible up to 72 hours post-blast — observe ALL blast survivors ≥ 24 hours'),
Bul('Solid organ (liver, spleen) lacerations from transmitted pressure'),
H3('Ear'),
Bul('Tympanic membrane rupture — most common primary blast injury; 50% recover spontaneously'),
Bul('Sensorineural hearing loss, tinnitus, vertigo'),
H3('Traumatic Brain Injury (PTBI)'),
Bul('Unique mechanism: direct transmission of pressure wave through skull'),
Bul('Diffuse axonal injury; neurobehavioral sequelae; blast-related chronic traumatic encephalopathy'),
Sp(4),
H2('Management'),
make_table([
['Phase', 'Actions'],
['Scene', 'Scene safety + decontamination → triage (START / SALT) → extrication'],
['Prehospital', 'ABCDE → tourniquet for limb haemorrhage → c-spine immobilisation → O₂'],
['ED', 'ATLS primary + secondary survey; CXR, AXR, FAST; ALL survivors observed ≥24 h'],
['Investigations','CT chest/abdomen if blast lung/abdominal signs; audiometry; ophthalmology review'],
['Surgery', 'Surgical exploration for haemodynamic instability, peritonism, or bowel perforation\nDelay primary closure of all blast wounds (high contamination risk)'],
['Wound care', 'Thorough debridement; tetanus prophylaxis; antibiotics for penetrating injuries\nDelayed primary closure at 48–72 hours'],
['Rehabilitation','Pain management; PTSD screening; audiology; prosthetics for amputees'],
], col_widths=[90, 380]),
PageBreak(),
]
# ══════════════════════════════════════════════════════════════════════════════
# Q 4(c): BURNS ASSESSMENT
# ══════════════════════════════════════════════════════════════════════════════
story += [
H1('QUESTION 4(c) — Assessment of Area of Burns (TBSA)'),
HR(), Sp(2),
H2('Importance'),
Body('Accurate estimation of Total Body Surface Area (TBSA) burned is fundamental for: (1) fluid resuscitation calculation, (2) determining need for burn centre referral, (3) prognostication, and (4) operative planning. Only 2nd-degree (partial thickness) and 3rd-degree (full thickness) burns are included — 1st-degree (superficial epidermal) burns are EXCLUDED.'),
Sp(2),
H2('Methods of TBSA Assessment'),
H3('1. Rule of Nines (Wallace, 1951)'),
wrap_drawing(diag_rule_of_nines(), 'Fig 11: Rule of Nines body map with adult and paediatric TBSA percentages'),
Sp(2),
make_table([
['Body Region', 'Adult TBSA', 'Child (1 yr) TBSA', 'Notes'],
['Head & Neck', '9%', '18%', 'Decreases with age (1% per year after age 1)'],
['Each arm (total)','9% (×2=18%)', '9% (×2=18%)', 'Upper arm 4%, forearm 3%, hand 2.5%'],
['Anterior trunk', '18%', '18%', 'Chest 9%, abdomen 9%'],
['Posterior trunk', '18%', '18%', 'Upper back 9%, lower back/buttocks 9%'],
['Each thigh', '9%', '6.5%', 'Increases with age in children'],
['Each lower leg', '9%', '7%', 'Lower leg 7%, foot 3.5%'],
['Perineum', '1%', '1%', 'Always 1%'],
['TOTAL', '100%', '100%', '—'],
], col_widths=[110, 80, 100, 180]),
Sp(2),
Bul('Quick, practical for pre-hospital and ED triage'),
Bul('Overestimates in obese patients; inaccurate in children < 15 years'),
Sp(4),
H3('2. Lund and Browder Chart (1944) — Most Accurate'),
Bul('Divides body into 19 anatomical segments with precise percentages that vary with age'),
Bul('Accounts for the changing body proportions as children grow (head large → decreasing; legs small → increasing)'),
Bul('Gold standard in all hospital settings and burns centres'),
Bul('Uses age-correction tables: "A" (head/2), "B" (thigh/2), "C" (lower leg/2) change with age'),
make_table([
['Age (years)', 'Head (A = ½ head)', 'Each Thigh (B = ½ thigh)', 'Each Lower leg (C = ½ leg)'],
['0 (infant)', '9.5%', '2.75%', '2.5%'],
['1', '8.5%', '3.25%', '2.5%'],
['5', '6.5%', '4.0%', '2.75%'],
['10', '5.5%', '4.25%', '3.0%'],
['15', '4.5%', '4.5%', '3.25%'],
['Adult', '3.5%', '4.75%', '3.5%'],
], col_widths=[80, 130, 150, 110]),
Sp(4),
H3('3. Palmar Method (Rule of Palm)'),
Bul('Patient\'s own palm (including fingers) = approximately 1% TBSA'),
Bul('Best for: Small, scattered, or irregular burns < 15% TBSA'),
Bul('Quick, always available, not affected by patient age'),
Bul('Limitation: Less accurate for large burns'),
Sp(4),
H3('4. Digital / Software Methods'),
Bul('Mersey Burns App, eBurncare: Mobile digital planimetry on tablet/phone'),
Bul('Photographic 3D body mapping (Burn Navigator): Integrates with weight for Parkland formula'),
Bul('Increasing use in major trauma centres and telemedicine burns consultation'),
Sp(4),
H2('Fluid Resuscitation — Clinical Application'),
Note('PARKLAND FORMULA: 4 mL × TBSA (%) × Body weight (kg) = Total Ringer\'s Lactate in first 24 hours from TIME OF BURN'),
make_table([
['Time', 'Volume', 'Fluid'],
['First 8 hours', '50% of total', 'Ringer\'s Lactate (Hartmann\'s solution)'],
['Next 16 hours', '50% of total', 'Ringer\'s Lactate'],
['After 24 hours', 'Colloid added', '0.5 mL/kg/% TBSA 5% albumin\n+ maintenance dextrose-saline for children'],
], col_widths=[130, 120, 220]),
Sp(2),
Bul('Time ZERO = time of burn (not time of arrival to hospital — adjust if delayed)'),
Bul('Urine output targets: Adult ≥ 0.5 mL/kg/hr; Child ≥ 1 mL/kg/hr; Electrical burns ≥ 1–2 mL/kg/hr'),
Bul('Avoid over-resuscitation ("fluid creep") → abdominal compartment syndrome, pulmonary oedema'),
Sp(4),
H2('Burns Referral Criteria (British Burn Association)'),
make_table([
['Refer to Burns Centre if:'],
['TBSA > 10% in adults OR > 5% in children'],
['Full-thickness burns of any size'],
['Burns to face, hands, feet, genitalia, perineum, major joints, or circumferential burns'],
['Inhalation injury / airway burns'],
['Chemical, electrical, or radiation burns'],
['Burns in patients with significant pre-existing co-morbidities'],
], col_widths=[470]),
Sp(6),
HR(NAVY, 2), Sp(2),
Paragraph('— END OF MODEL ANSWERS : M.S. Branch-I, July 2020, General Surgery Paper I —',
ParagraphStyle('end', parent=ss['Normal'], fontSize=10, textColor=GREY,
alignment=TA_CENTER, fontName='Helvetica-Oblique')),
Sp(2),
HR(NAVY, 1),
]
# ── HEADER / FOOTER ───────────────────────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
# Header
canvas.setFillColor(NAVY)
canvas.rect(30, H-38, W-60, 22, fill=1, stroke=0)
canvas.setFillColor(WHITE)
canvas.setFont('Helvetica-Bold', 9)
canvas.drawString(38, H-30, 'M.S. (Branch-I) | July 2020 | General Surgery Paper I | Model Answers')
canvas.drawRightString(W-38, H-30, f'Page {doc.page}')
# Footer
canvas.setFillColor(LTBLUE)
canvas.rect(30, 16, W-60, 14, fill=1, stroke=0)
canvas.setFillColor(NAVY)
canvas.setFont('Helvetica', 7.5)
canvas.drawCentredString(W/2, 21, 'For educational purposes only | All answers based on standard surgical textbooks (Bailey & Love, Schwartz, ATLS)')
canvas.restoreState()
# ── BUILD PDF ─────────────────────────────────────────────────────────────────
out_path = '/home/daytona/workspace/ms-surgery-answers/MS_Surgery_July2020_Paper1_ModelAnswers.pdf'
doc = SimpleDocTemplate(
out_path,
pagesize=A4,
leftMargin=28*mm, rightMargin=28*mm,
topMargin=22*mm, bottomMargin=18*mm,
title='MS General Surgery July 2020 Paper I - Model Answers',
author='Orris Medical AI',
)
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f'SUCCESS → {out_path}')
cd /home/daytona/workspace/ms-surgery-answers && python3 gen_pdf.py 2>&1
~/ms-surgery-answers/gen_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ms-surgery-answers/gen_pdf.py'
cd /home/daytona/workspace/ms-surgery-answers && python3 gen_pdf.py 2>&1
ls -lh /home/daytona/workspace/ms-surgery-answers/MS_Surgery_July2020_Paper1_ModelAnswers.pdf && python3 -c " from pypdf import PdfReader r = PdfReader('/home/daytona/workspace/ms-surgery-answers/MS_Surgery_July2020_Paper1_ModelAnswers.pdf') print(f'Pages: {len(r.pages)}') print(f'Title: {r.metadata.title}') # check text on first few pages for i in range(min(3, len(r.pages))): t = r.pages[i].extract_text() print(f'Page {i+1} text preview: {t[:120].strip()}') "
MS Surgery July2020 Paper1 ModelAnswers
PDF Document · PDF
| Fig | Diagram | Question |
|---|---|---|
| Fig 1 | Splenic blood supply — celiac axis to portal vein with open/closed circulation split | Q1 |
| Fig 2 | Operative steps of open splenectomy (2-column colour-coded flowchart) | Q1 |
| Fig 3 | OPSI management flowchart (red urgent escalation steps) | Q1 |
| Fig 4 | Lymphoedema pathophysiology cascade — obstruction to elephantiasis | Q2 |
| Fig 5 | CDT Phase 1 + Phase 2 + Surgical options overview | Q2 |
| Fig 6 | Shock pathophysiology — trigger to MODS (compensatory → progressive → irreversible) | Q3 |
| Fig 7 | ATLS haemorrhagic shock Class I–IV colour-coded boxes | Q3 |
| Fig 8 | Shock resuscitation algorithm — 4 type-specific treatment branches | Q3 |
| Fig 9 | TPN complications — 3-column: catheter / metabolic / hepatic | Q4a |
| Fig 10 | Blast injury classification — central explosion with 5 radial category boxes | Q4b |
| Fig 11 | Rule of Nines body schematic + adult vs child TBSA table | Q4c |
With standard textbooks images not AI generated
mkdir -p /home/daytona/workspace/ms-surgery-answers/textbook_images # Download all collected textbook images images=( "https://cdn.orris.care/cdss_images/dcd443d4966890f7b1beb44961c3083cba8d1b3a7da6d5efdfb72fef9682a60f.png spleen_diagram.png" "https://cdn.orris.care/cdss_images/1ded12717b1f0d7b3dd02d0459d056d40a39d8b81b6f6982543dcba31dcf21d2.png spleen_histology.png" "https://cdn.orris.care/cdss_images/335bbd7873afbe1e3774c6f520ca14c1e4c3f034328749041352c8d915c5afde.png lymph_conduit.png" "https://cdn.orris.care/cdss_images/722e057c3d11d6916acfacdd548867e0afd941d0089f0e584adaa3f7bc31c94b.png shock_resus_diagram.png" ) for entry in "${images[@]}"; do url=$(echo $entry | cut -d' ' -f1) fname=$(echo $entry | cut -d' ' -f2) curl -s -o "/home/daytona/workspace/ms-surgery-answers/textbook_images/$fname" "$url" size=$(wc -c < "/home/daytona/workspace/ms-surgery-answers/textbook_images/$fname") echo "$fname: $size bytes" done
~/ms-surgery-answers/gen_pdf_v2.py
#!/usr/bin/env python3
"""
MS General Surgery – July 2020 Paper I
PDF v2 – Real textbook images + professional vector diagrams
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
PageBreak, HRFlowable, KeepTogether, Image
)
from reportlab.platypus.flowables import Flowable
from reportlab.graphics.shapes import (
Drawing, Rect, String, Line, Polygon,
Group, Path, Circle, Ellipse
)
from reportlab.graphics import renderPDF
import os, math
IMG = '/home/daytona/workspace/ms-surgery-answers/textbook_images/'
# ── Colours ────────────────────────────────────────────────────────────────────
NAVY = colors.HexColor('#1F3864')
BLUE = colors.HexColor('#2E75B6')
LTBLUE = colors.HexColor('#BDD7EE')
VLTBLUE = colors.HexColor('#DEEAF1')
TEAL = colors.HexColor('#00B0A0')
LTTEAL = colors.HexColor('#C7F5F0')
RED = colors.HexColor('#C00000')
ORANGE = colors.HexColor('#ED7D31')
LTORANGE = colors.HexColor('#FCE4D6')
GREEN = colors.HexColor('#375623')
LTGREEN = colors.HexColor('#E2EFDA')
GOLD = colors.HexColor('#FFC000')
LTGOLD = colors.HexColor('#FFF2CC')
GREY = colors.HexColor('#595959')
LTGREY = colors.HexColor('#F2F2F2')
WHITE = colors.white
BLACK = colors.black
W, H = A4
# ── Styles ─────────────────────────────────────────────────────────────────────
ss = getSampleStyleSheet()
def S(name, parent='Normal', **kw):
return ParagraphStyle(name, parent=ss[parent], **kw)
sTitle = S('sTitle', fontSize=24, textColor=NAVY, alignment=TA_CENTER,
fontName='Helvetica-Bold', spaceAfter=4)
sSubTitle = S('sSub', fontSize=13, textColor=BLUE, alignment=TA_CENTER,
fontName='Helvetica-Bold', spaceAfter=4)
sMeta = S('sMeta', fontSize=10, textColor=GREY, alignment=TA_CENTER,
fontName='Helvetica', spaceAfter=10)
sH1 = S('sH1', fontSize=14, textColor=WHITE, fontName='Helvetica-Bold',
spaceAfter=4, spaceBefore=10,
backColor=NAVY, borderPadding=(5,8,5,8))
sH2 = S('sH2', fontSize=12, textColor=NAVY, fontName='Helvetica-Bold',
spaceAfter=3, spaceBefore=8)
sH3 = S('sH3', fontSize=10, textColor=BLUE, fontName='Helvetica-Bold',
spaceAfter=2, spaceBefore=5)
sBody = S('sBody', fontSize=10, textColor=BLACK, fontName='Helvetica',
spaceAfter=3, leading=14, alignment=TA_JUSTIFY)
sBul = S('sBul', fontSize=10, textColor=BLACK, fontName='Helvetica',
spaceAfter=3, leading=13, leftIndent=14, firstLineIndent=-10)
sNote = S('sNote', fontSize=10, textColor=NAVY, fontName='Helvetica-Bold',
spaceAfter=4, backColor=LTGOLD, borderPadding=(4,8,4,8),
leftIndent=4, rightIndent=4)
sCap = S('sCap', fontSize=8, textColor=GREY, fontName='Helvetica-Oblique',
alignment=TA_CENTER, spaceAfter=6, spaceBefore=2)
sSource = S('sSrc', fontSize=8, textColor=BLUE, fontName='Helvetica-Oblique',
alignment=TA_CENTER, spaceAfter=6)
def H1(t): return Paragraph(f' {t}', sH1)
def H2(t): return Paragraph(f'<font color="#2E75B6">◆</font> {t}', sH2)
def H3(t): return Paragraph(f'<font color="#2E75B6">▸</font> {t}', sH3)
def Body(t): return Paragraph(t, sBody)
def Bul(t): return Paragraph(f'• {t}', sBul)
def Note(t): return Paragraph(f'★ {t}', sNote)
def Sp(h=4): return Spacer(1, h*mm)
def HR(c=LTBLUE, th=1): return HRFlowable(width='100%', thickness=th, color=c,
spaceAfter=3, spaceBefore=3)
def Cap(t): return Paragraph(t, sCap)
def Source(t): return Paragraph(t, sSource)
def textbook_image(fname, width_mm=120, caption='', source=''):
path = IMG + fname
if not os.path.exists(path):
return []
img = Image(path, width=width_mm*mm, height=None) # auto height
items = [img]
if caption: items.append(Cap(caption))
if source: items.append(Source(f'Source: {source}'))
return [KeepTogether(items)]
# ── Table builder ──────────────────────────────────────────────────────────────
def mktbl(data, cw=None, hdr=True, stripe=True):
if cw is None:
n = len(data[0]); cw = [(W-80)/n]*n
t = Table(data, colWidths=cw, repeatRows=1 if hdr else 0)
ts = [
('FONTNAME', (0,0),(-1,-1),'Helvetica'),
('FONTSIZE', (0,0),(-1,-1),9),
('VALIGN', (0,0),(-1,-1),'TOP'),
('TOPPADDING', (0,0),(-1,-1),4),
('BOTTOMPADDING',(0,0),(-1,-1),4),
('LEFTPADDING', (0,0),(-1,-1),6),
('RIGHTPADDING', (0,0),(-1,-1),6),
('GRID', (0,0),(-1,-1),0.4, colors.HexColor('#BFBFBF')),
('ROWBACKGROUNDS',(0,0),(-1,-1),[WHITE, VLTBLUE] if stripe else [WHITE]),
]
if hdr:
ts += [
('BACKGROUND',(0,0),(-1,0),NAVY),
('TEXTCOLOR', (0,0),(-1,0),WHITE),
('FONTNAME', (0,0),(-1,0),'Helvetica-Bold'),
('FONTSIZE', (0,0),(-1,0),9),
('ALIGN', (0,0),(-1,0),'CENTER'),
]
t.setStyle(TableStyle(ts))
return t
# ══════════════════════════════════════════════════════════════════════════════
# VECTOR DIAGRAM HELPERS
# ══════════════════════════════════════════════════════════════════════════════
def vbox(d, x, y, w, h, txt, fill=LTBLUE, tc=NAVY, fsize=9, bold=False):
fn = 'Helvetica-Bold' if bold else 'Helvetica'
d.add(Rect(x, y, w, h, rx=4, ry=4, fillColor=fill, strokeColor=NAVY, strokeWidth=1))
lines = txt.split('\n'); lh = fsize*1.35
ty = y + h/2 + (len(lines)-1)*lh/2
for ln in lines:
d.add(String(x+w/2, ty-fsize*0.3, ln, textAnchor='middle',
fillColor=tc, fontName=fn, fontSize=fsize))
ty -= lh
def vdiamond(d, x, y, w, h, txt, fill=LTGOLD, tc=NAVY, fsize=9):
cx, cy = x+w/2, y+h/2
d.add(Polygon([cx,y+h, x+w,cy, cx,y, x,cy], fillColor=fill,
strokeColor=ORANGE, strokeWidth=1.2))
d.add(String(cx, cy-fsize*0.35, txt, textAnchor='middle',
fillColor=tc, fontName='Helvetica-Bold', fontSize=fsize))
def varrow_d(d, x, y, length=18, color=NAVY):
d.add(Line(x, y, x, y-length, strokeColor=color, strokeWidth=1.5))
d.add(Polygon([x-4,y-length+6, x+4,y-length+6, x,y-length],
fillColor=color, strokeColor=color))
def varrow_r(d, x, y, length=20, color=NAVY):
d.add(Line(x, y, x+length, y, strokeColor=color, strokeWidth=1.5))
d.add(Polygon([x+length-6,y-4, x+length-6,y+4, x+length,y],
fillColor=color, strokeColor=color))
# ─── Flowchart builder: list of (text, fill, textcolor) nodes ─────────────────
def flow_chart(dw, title, steps, step_heights=None, title_color=NAVY, border_color=LTBLUE):
bw = 360; cx = dw/2
total_h = 40
if step_heights is None:
step_heights = [36]*len(steps)
for sh in step_heights: total_h += sh + 14
dh = total_h + 20
d = Drawing(dw, dh)
d.add(Rect(0,0,dw,dh, fillColor=WHITE, strokeColor=border_color, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-16, title, textAnchor='middle',
fillColor=title_color, fontName='Helvetica-Bold', fontSize=11))
y = dh - 42
bx = cx - bw/2
for i, ((txt, fill, tc), sh) in enumerate(zip(steps, step_heights)):
vbox(d, bx, y-sh, bw, sh, txt, fill, tc, fsize=9, bold=(i==0 or fill==RED or fill==NAVY))
if i < len(steps)-1:
varrow_d(d, cx, y-sh, length=14)
y -= sh + 14
return d, dh
# ─── Spleen ligament diagram ───────────────────────────────────────────────────
def diag_spleen_ligaments():
dw, dh = 480, 200
d = Drawing(dw, dh)
d.add(Rect(0,0,dw,dh, fillColor=WHITE, strokeColor=LTBLUE, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-14, 'LIGAMENTS OF THE SPLEEN',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=11))
# Central spleen ellipse
sx, sy, srx, sry = 240, 95, 55, 45
d.add(Ellipse(sx, sy, srx, sry, fillColor=LTBLUE, strokeColor=NAVY, strokeWidth=2))
d.add(String(sx, sy+4, 'SPLEEN', textAnchor='middle',
fillColor=NAVY, fontName='Helvetica-Bold', fontSize=10))
d.add(String(sx, sy-10, '150g 9–11 rib', textAnchor='middle',
fillColor=GREY, fontName='Helvetica', fontSize=7.5))
# Ligaments
ligs = [
(sx-55, sy+30, 'Gastrosplenic\nShort gastric aa.', LTGOLD, NAVY, 'left'),
(sx+55, sy+30, 'Splenorenal\nSplenic vessels + pancreas tail', LTTEAL, NAVY, 'right'),
(sx, sy-45, 'Phrenocolic\n(supports inferior pole)', LTGREEN, NAVY, 'top'),
(sx-55, sy-25, 'Splenocolic\n(colon)', LTORANGE, NAVY, 'left'),
]
for (lx, ly, txt, fill, tc, side) in ligs:
w2, h2 = 130, 34
bx2 = lx - w2//2 if side in ('top','left','right') else lx
by2 = ly - h2//2 if side != 'top' else ly - h2 - 5
vbox(d, bx2, by2, w2, h2, txt, fill, tc, fsize=8)
# connector line
ex = bx2 + w2//2; ey = by2 + h2//2
d.add(Line(sx, sy, ex, ey, strokeColor=NAVY, strokeWidth=0.8,
strokeDashArray=[3,2]))
return d
# ─── Splenic blood supply ──────────────────────────────────────────────────────
def diag_splenic_supply():
dw = 480
steps = [
('Coeliac Axis', NAVY, WHITE),
('Splenic Artery (tortuous, runs along upper pancreatic border)', BLUE, WHITE),
('Trabecular Arteries → Central Arteries', LTBLUE, NAVY),
]
heights = [28, 32, 28]
d, dh = flow_chart(dw, 'SPLENIC BLOOD SUPPLY & MICROCIRCULATION', steps, heights,
title_color=NAVY, border_color=LTBLUE)
# split
cx = dw/2; bw2 = 170
split_y = dh - 42 - sum(heights) - len(heights)*14 + 14
# horizontal line
d.add(Line(cx-120, split_y-10, cx+120, split_y-10, strokeColor=NAVY, strokeWidth=1.2))
d.add(Line(cx-120, split_y-10, cx-120, split_y-48, strokeColor=NAVY, strokeWidth=1.2))
d.add(Line(cx+120, split_y-10, cx+120, split_y-48, strokeColor=NAVY, strokeWidth=1.2))
varrow_d(d, cx-120, split_y-48, length=14, color=TEAL)
varrow_d(d, cx+120, split_y-48, length=14, color=ORANGE)
vbox(d, cx-210, split_y-76, 170, 30, 'OPEN circulation\n(Sinuses — fast, 90%)', LTTEAL, NAVY, fsize=8)
vbox(d, cx+40, split_y-76, 170, 30, 'CLOSED circulation\n(Cords — slow, 10%)', LTORANGE, NAVY, fsize=8)
# merge
d.add(Line(cx-120, split_y-76, cx-120, split_y-96, strokeColor=NAVY, strokeWidth=1))
d.add(Line(cx+120, split_y-76, cx+120, split_y-96, strokeColor=NAVY, strokeWidth=1))
d.add(Line(cx-120, split_y-96, cx+120, split_y-96, strokeColor=NAVY, strokeWidth=1))
varrow_d(d, cx, split_y-96, length=14)
vbox(d, cx-90, split_y-124, 180, 24, 'Splenic Vein → Portal Vein', BLUE, WHITE, bold=True, fsize=9)
return d, max(dh, split_y + 130)
# ─── OPSI flowchart ────────────────────────────────────────────────────────────
def diag_opsi():
steps = [
('Asplenic patient + Fever / Rigors / Lethargy', LTORANGE, NAVY),
('DO NOT WAIT — Blood cultures × 2 THEN\nIV Ceftriaxone 2 g STAT (within 30 minutes)', RED, WHITE),
('Immediate hospital admission\nSepsis workup: FBC, CRP, Lactate, Blood cultures, ABG', LTBLUE, NAVY),
('Sepsis-6 bundle: O₂ • IV fluids 30mL/kg •\nMonitor UO • Reassess lactate every 2h', LTBLUE, NAVY),
('ICU if SOFA ≥ 2 / deteriorating\nNoradrenaline if MAP < 65 mmHg despite fluids', RED, WHITE),
]
heights = [30, 38, 36, 36, 36]
d, dh = flow_chart(480, 'OVERWHELMING POST-SPLENECTOMY INFECTION (OPSI) — MANAGEMENT',
steps, heights, title_color=RED, border_color=RED)
return d, dh
# ─── Lymphoedema pathophysiology ───────────────────────────────────────────────
def diag_lymph_path():
steps = [
('Lymphatic Obstruction / Aplasia / Damage', NAVY, WHITE),
('↓ Lymphatic transport capacity (normal 2–4 L/day)', BLUE, WHITE),
('Protein-rich fluid accumulates in interstitium\n→ ↑ Oncotic pressure → more water retention', LTBLUE, NAVY),
('Macrophage infiltration → TGF-β1, IL-6, VEGF-C\n→ Fibroblast activation → Collagen deposition', LTORANGE, NAVY),
('Adipose hypertrophy + irreversible subcutaneous fibrosis\n→ ELEPHANTIASIS (Stage III)', RED, WHITE),
]
heights = [28, 28, 38, 38, 36]
d, dh = flow_chart(480, 'PATHOPHYSIOLOGY OF LYMPHOEDEMA',
steps, heights, title_color=NAVY, border_color=LTBLUE)
return d, dh
# ─── CDT diagram ────────────────────────────────────────────────────────────────
def diag_cdt():
dw, dh = 480, 260
d = Drawing(dw, dh)
d.add(Rect(0,0,dw,dh, fillColor=WHITE, strokeColor=TEAL, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-14, 'COMPLETE DECONGESTIVE THERAPY (CDT) — Gold Standard',
textAnchor='middle', fillColor=TEAL, fontName='Helvetica-Bold', fontSize=10))
# Phase 1
d.add(Rect(15, dh-220, 215, 195, rx=4, fillColor=VLTBLUE, strokeColor=TEAL, strokeWidth=1.5))
d.add(String(122, dh-40, 'PHASE 1: INTENSIVE', textAnchor='middle',
fillColor=TEAL, fontName='Helvetica-Bold', fontSize=10))
d.add(String(122, dh-55, '(2–4 weeks with therapist)', textAnchor='middle',
fillColor=GREY, fontName='Helvetica-Oblique', fontSize=8))
phase1 = ['• Manual Lymphatic Drainage (MLD)',
' daily by certified therapist',
'• Multilayer inelastic compression',
' bandaging (short-stretch)',
'• Skin care: moisturisers,',
' antifungals, wound care',
'• Prescribed exercises']
for i, item in enumerate(phase1):
d.add(String(25, dh-75-i*18, item, fillColor=NAVY, fontName='Helvetica', fontSize=9))
# Phase 2
d.add(Rect(250, dh-220, 215, 195, rx=4, fillColor=LTGREEN, strokeColor=GREEN, strokeWidth=1.5))
d.add(String(357, dh-40, 'PHASE 2: MAINTENANCE', textAnchor='middle',
fillColor=GREEN, fontName='Helvetica-Bold', fontSize=10))
d.add(String(357, dh-55, '(lifelong self-management)', textAnchor='middle',
fillColor=GREY, fontName='Helvetica-Oblique', fontSize=8))
phase2 = ['• Custom compression garments',
' (Class 2–3, replaced 6-monthly)',
'• Self-MLD technique daily',
'• Ongoing exercise programme',
'• Skin care + vigilance for',
' cellulitis (start Abx early)',
'• Annual review by therapist']
for i, item in enumerate(phase2):
d.add(String(260, dh-75-i*18, item, fillColor=GREEN, fontName='Helvetica', fontSize=9))
# Arrow between
varrow_r(d, 230, dh-120, length=20, color=TEAL)
d.add(String(240, dh-115, 'Transition', textAnchor='middle', fillColor=TEAL,
fontName='Helvetica-Oblique', fontSize=7))
return d, dh
# ─── Shock pathophysiology ─────────────────────────────────────────────────────
def diag_shock_path():
steps = [
('Precipitating Trigger\n(Haemorrhage / Sepsis / Cardiac failure / Anaphylaxis)', NAVY, WHITE),
('↓ Cardiac Output AND/OR ↓ SVR\n→ MAP < 65 mmHg → Tissue Hypoperfusion', BLUE, WHITE),
('COMPENSATORY PHASE (reversible)\nBaroreceptors → SNS activation → ↑HR, ↑Contractility\nRAAS → Aldosterone → Na⁺/H₂O retention; ADH → ↑H₂O reabsorption', LTBLUE, NAVY),
('PROGRESSIVE (DECOMPENSATION) PHASE\nAnaerobic glycolysis → Lactic acidosis\nCapillary leak (histamine/cytokines) → Oedema\nMicrovascular sludging + microthrombi\nNa⁺/K⁺-ATPase failure → Cell swelling', LTORANGE, NAVY),
('IRREVERSIBLE SHOCK\n→ Multi-Organ Dysfunction Syndrome (MODS) → DEATH', RED, WHITE),
]
heights = [36, 34, 54, 58, 34]
d, dh = flow_chart(480, 'PATHOPHYSIOLOGY OF SHOCK — Cascade', steps, heights,
title_color=RED, border_color=RED)
return d, dh
# ─── ATLS table as drawing ─────────────────────────────────────────────────────
def diag_atls():
dw, dh = 480, 170
d = Drawing(dw, dh)
d.add(Rect(0,0,dw,dh, fillColor=WHITE, strokeColor=LTBLUE, strokeWidth=1, rx=4))
d.add(String(dw/2, dh-14, 'ATLS CLASSIFICATION OF HAEMORRHAGIC SHOCK (70 kg adult)',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=10))
# 4 class boxes
fills = [colors.HexColor('#E2EFDA'), LTGOLD, LTORANGE, colors.HexColor('#FFD7D7')]
losses = ['< 750 mL\n(< 15%)', '750–1500 mL\n(15–30%)',
'1500–2000 mL\n(30–40%)', '> 2000 mL\n(> 40%)']
params = ['HR < 100\nBP normal\nRR 14–20\nAlert',
'HR 100–120\n↓ Pulse pressure\nRR 20–30\nAnxious',
'HR > 120\n↓↓ BP\nRR 30–40\nConfused',
'HR > 140\nBP negligible\nRR > 35\nUnconscionable']
labels = ['CLASS I', 'CLASS II', 'CLASS III', 'CLASS IV']
for i in range(4):
bx = 8 + i*119; bw2 = 114
vbox(d, bx, dh-46, bw2, 24, labels[i], NAVY, WHITE, bold=True, fsize=9)
vbox(d, bx, dh-88, bw2, 36, losses[i], fills[i], NAVY, fsize=8)
vbox(d, bx, dh-158, bw2, 64, params[i], fills[i], NAVY, fsize=8)
return d
# ─── Shock resuscitation overview ──────────────────────────────────────────────
def diag_shock_resus():
dw, dh = 480, 370
d = Drawing(dw, dh)
d.add(Rect(0,0,dw,dh, fillColor=WHITE, strokeColor=NAVY, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-14, 'SHOCK RESUSCITATION ALGORITHM (Type-Specific)',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=11))
cx = dw/2
# Top 3 common steps
vbox(d, cx-180, dh-52, 360, 26, 'RECOGNITION: MAP<65 / HR>100 / ↓UO / Altered GCS', NAVY, WHITE, bold=True, fsize=9)
varrow_d(d, cx, dh-52, length=14)
vbox(d, cx-180, dh-100, 360, 28, 'PRIMARY SURVEY (ABCDE) | O₂ 15 L/min | 2 large-bore IV lines', BLUE, WHITE, fsize=9)
varrow_d(d, cx, dh-100, length=14)
vbox(d, cx-180, dh-150, 360, 40,
'Bloods: FBC • U&E • LFT • Coag • X-match • ABG • Lactate\nImaging: CXR | FAST/eFAST | CT', LTBLUE, NAVY, fsize=9)
varrow_d(d, cx, dh-150, length=14)
vdiamond(d, cx-55, dh-196, 110, 36, 'Identify Type', LTGOLD, NAVY, fsize=9)
# horizontal branch line
branch_y = dh-218
d.add(Line(35, branch_y, 445, branch_y, strokeColor=NAVY, strokeWidth=1.2))
types = [
(20, 110, 'HAEMORRHAGIC\n• Permissive hypotension\n SBP 80–90 mmHg\n• MTP 1:1:1 (pRBC:FFP:Plt)\n• TXA 1g IV within 3 hrs\n• Surgical haemostasis', LTORANGE, NAVY),
(142, 110, 'SEPTIC\n• Cultures × 2 FIRST\n• Abx within 1 hour\n• 30 mL/kg crystalloid\n• Noradrenaline\n if MAP < 65 mmHg', LTBLUE, NAVY),
(264, 110, 'CARDIOGENIC\n• Treat cause (PCI /\n pericardiocentesis)\n• Dobutamine\n• IABP / ECMO\n if refractory', LTGREEN, GREEN),
(386, 110, 'ANAPHYLACTIC\n• Adrenaline 0.5 mg\n IM (1:1000) FIRST\n• Remove trigger\n• Chlorphenamine\n• Hydrocortisone', LTTEAL, TEAL),
]
for (bx, bw2, txt, fill, tc) in types:
d.add(Line(bx+bw2//2, branch_y, bx+bw2//2, branch_y-16, strokeColor=NAVY, strokeWidth=1))
d.add(Polygon([bx+bw2//2-4, branch_y-12, bx+bw2//2+4, branch_y-12, bx+bw2//2, branch_y-16],
fillColor=NAVY, strokeColor=NAVY))
vbox(d, bx, branch_y-118, bw2, 100, txt, fill, tc, fsize=8)
# endpoints
varrow_d(d, cx, branch_y-118, length=16)
vbox(d, cx-200, branch_y-156, 400, 28,
'ENDPOINTS: MAP≥65 | UO≥0.5 mL/kg/h | Lactate<2 | ScvO₂>70% | Base excess normal',
NAVY, WHITE, bold=True, fsize=8)
return d, dh
# ─── TPN complications ─────────────────────────────────────────────────────────
def diag_tpn_comp():
dw, dh = 480, 240
d = Drawing(dw, dh)
d.add(Rect(0,0,dw,dh, fillColor=WHITE, strokeColor=LTBLUE, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-14, 'TPN COMPLICATIONS',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=11))
cols_data = [
('CATHETER\nRELATED', LTBLUE, NAVY,
['Pneumothorax (insertion)', 'Haemothorax / Air embolism',
'CLABSI (S. epidermidis)', 'CVC thrombosis', 'Subclavian stenosis']),
('METABOLIC', LTGOLD, NAVY,
['Hyperglycaemia → insulin Rx', 'Refeeding syndrome\n(↓PO₄, ↓K⁺, ↓Mg²⁺)',
'Hyperlipidaemia', 'Metabolic acidosis', 'Electrolyte imbalance']),
('HEPATIC / GIT', LTORANGE, NAVY,
['Hepatic steatosis', 'Cholestasis / gallstones',
'Gut mucosal atrophy\n(villous atrophy)', 'Bacterial translocation', 'TPN cholestasis']),
]
cw = 148
for ci, (hdr, fill, tc, items) in enumerate(cols_data):
bx = 8 + ci*(cw+6)
vbox(d, bx, dh-46, cw, 26, hdr, NAVY, WHITE, bold=True, fsize=9)
for ii, item in enumerate(items):
vbox(d, bx, dh-82-ii*34, cw, 28, item, fill, tc, fsize=8)
return d
# ─── Rule of Nines diagram ─────────────────────────────────────────────────────
def diag_rule_of_nines():
dw, dh = 480, 280
d = Drawing(dw, dh)
d.add(Rect(0,0,dw,dh, fillColor=WHITE, strokeColor=LTBLUE, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-14, 'RULE OF NINES — Schematic Body Map',
textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=11))
# Schematic body (left side)
cx = 105
# Head
d.add(Ellipse(cx, dh-56, 26, 24, fillColor=LTBLUE, strokeColor=NAVY, strokeWidth=1.5))
d.add(String(cx, dh-54, '9%', textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=9))
# Neck connector
d.add(Rect(cx-6, dh-84, 12, 16, fillColor=LTBLUE, strokeColor=NAVY, strokeWidth=1))
# Trunk
d.add(Rect(cx-35, dh-164, 70, 76, fillColor=LTBLUE, strokeColor=NAVY, strokeWidth=1.5))
d.add(String(cx, dh-120, '18%', textAnchor='middle', fillColor=NAVY, fontName='Helvetica-Bold', fontSize=10))
d.add(String(cx, dh-133, 'Anterior', textAnchor='middle', fillColor=NAVY, fontName='Helvetica', fontSize=8))
d.add(String(cx, dh-156, '18% Posterior', textAnchor='middle', fillColor=GREY, fontName='Helvetica-Oblique', fontSize=7))
# Arms
d.add(Rect(cx-68, dh-155, 26, 60, rx=6, fillColor=LTTEAL, strokeColor=NAVY, strokeWidth=1))
d.add(Rect(cx+42, dh-155, 26, 60, rx=6, fillColor=LTTEAL, strokeColor=NAVY, strokeWidth=1))
d.add(String(cx-55, dh-126, '9%', textAnchor='middle', fillColor=TEAL, fontName='Helvetica-Bold', fontSize=9))
d.add(String(cx+55, dh-126, '9%', textAnchor='middle', fillColor=TEAL, fontName='Helvetica-Bold', fontSize=9))
# Perineum dot
d.add(Ellipse(cx, dh-170, 6, 6, fillColor=GOLD, strokeColor=NAVY, strokeWidth=1))
d.add(String(cx+12, dh-172, '1%', textAnchor='start', fillColor=NAVY, fontName='Helvetica', fontSize=7))
# Legs
d.add(Rect(cx-34, dh-262, 28, 90, rx=5, fillColor=LTORANGE, strokeColor=NAVY, strokeWidth=1))
d.add(Rect(cx+6, dh-262, 28, 90, rx=5, fillColor=LTORANGE, strokeColor=NAVY, strokeWidth=1))
d.add(String(cx-20, dh-218, '18%', textAnchor='middle', fillColor=ORANGE, fontName='Helvetica-Bold', fontSize=9))
d.add(String(cx+20, dh-218, '18%', textAnchor='middle', fillColor=ORANGE, fontName='Helvetica-Bold', fontSize=9))
d.add(String(cx, dh-268, 'Each leg', textAnchor='middle', fillColor=ORANGE, fontName='Helvetica', fontSize=7.5))
# Total
vbox(d, cx-50, 5, 100, 20, 'TOTAL = 100%', NAVY, WHITE, bold=True, fsize=9)
# Right: labels
lx = 220
items = [
(dh-56, 'Head & Neck = 9% (Child 1yr = 18%)'),
(dh-95, 'Each arm = 9% ×2 = 18%'),
(dh-120, 'Anterior trunk = 18%'),
(dh-135, 'Posterior trunk = 18%'),
(dh-155, 'Perineum = 1%'),
(dh-185, 'Each thigh = 9%'),
(dh-205, 'Each lower leg = 9%'),
(dh-225, ' (Child: head↑, legs↓ — use Lund & Browder)'),
]
for (y, txt) in items:
bold = not txt.startswith(' ')
fn = 'Helvetica-Bold' if bold else 'Helvetica-Oblique'
col = NAVY if bold else GREY
d.add(String(lx, y-4, txt, fillColor=col, fontName=fn, fontSize=9))
# annotation arrow: child
d.add(String(lx, dh-240, '★ In children: Head >9%, Legs <18%', fillColor=RED,
fontName='Helvetica-Bold', fontSize=8.5))
return d
# ─── Blast injury ──────────────────────────────────────────────────────────────
def diag_blast():
dw, dh = 480, 250
d = Drawing(dw, dh)
d.add(Rect(0,0,dw,dh, fillColor=WHITE, strokeColor=RED, strokeWidth=1.5, rx=6))
d.add(String(dw/2, dh-14, 'BLAST INJURY — 5-CATEGORY CLASSIFICATION',
textAnchor='middle', fillColor=RED, fontName='Helvetica-Bold', fontSize=11))
cx, cy = dw/2, dh/2 - 5
d.add(Ellipse(cx, cy, 40, 36, fillColor=GOLD, strokeColor=RED, strokeWidth=2))
d.add(String(cx, cy+6, 'BLAST', textAnchor='middle', fillColor=RED, fontName='Helvetica-Bold', fontSize=10))
d.add(String(cx, cy-7, 'EVENT', textAnchor='middle', fillColor=RED, fontName='Helvetica-Bold', fontSize=9))
rays = [
(80, 'PRIMARY\nBlast overpressure wave\nEar (TM rupture), Lung,\nBowel, Brain', LTORANGE),
(165, 'SECONDARY\nFragmentation / Shrapnel\nPenetrating injuries\nOcular injuries', LTBLUE),
(258, 'TERTIARY\nBlast wind\nBlunt trauma\nTraumatic amputations\nFractures', LTGREEN),
(350, 'QUATERNARY\nBurns, Crush injuries\nInhalation injury\nToxic gas exposure', colors.HexColor('#FFD7D7')),
(40, 'QUINARY\nHyperinflammatory\nBioterrorism agents\nRadiation injury', LTGREY),
]
for (bx, txt, fill) in rays:
bw2 = 108; by = 30
vbox(d, bx, by, bw2, 82, txt, fill, NAVY, fsize=8)
# line to center
ex = bx + bw2//2; ey = by + 82
d.add(Line(ex, ey, cx, cy-36, strokeColor=NAVY, strokeWidth=0.8, strokeDashArray=[3,2]))
return d
# ══════════════════════════════════════════════════════════════════════════════
# PAGE HEADER / FOOTER
# ══════════════════════════════════════════════════════════════════════════════
def on_page(canvas, doc):
canvas.saveState()
canvas.setFillColor(NAVY)
canvas.rect(28, H-36, W-56, 20, fill=1, stroke=0)
canvas.setFillColor(WHITE); canvas.setFont('Helvetica-Bold', 8.5)
canvas.drawString(36, H-28, 'M.S. (Branch-I) | July 2020 | General Surgery Paper I | Model Answers with Textbook Images')
canvas.drawRightString(W-36, H-28, f'Page {doc.page}')
canvas.setFillColor(LTBLUE)
canvas.rect(28, 14, W-56, 14, fill=1, stroke=0)
canvas.setFillColor(NAVY); canvas.setFont('Helvetica', 7.5)
canvas.drawCentredString(W/2, 19, 'Textbook images from: Bailey & Love\'s Surgery 28e | Cellular & Molecular Immunology | For educational purposes only')
canvas.restoreState()
# ══════════════════════════════════════════════════════════════════════════════
# STORY
# ══════════════════════════════════════════════════════════════════════════════
story = []
# ── COVER ──────────────────────────────────────────────────────────────────────
story += [
Sp(30),
Paragraph('M.S. (Branch – I) Examination', sTitle),
Paragraph('July 2020 — General Surgery : Paper I', sSubTitle),
Paragraph('Model Answers | Standard Textbook Images | Professional Diagrams', sMeta),
HR(NAVY, 2), Sp(2),
mktbl([
['Q', 'Topic', 'Marks'],
['1', 'Spleen — Surgical Anatomy, Physiology, Splenectomy & Complications', '30'],
['2', 'Lymphoedema — Pathophysiology, Classification & Management', '20'],
['3', 'Shock — Pathophysiology, Classification & Resuscitation', '20'],
['4(a)', 'Total Parenteral Nutrition (TPN)', '10'],
['4(b)', 'Blast Injuries', '10'],
['4(c)', 'Assessment of Area of Burns (TBSA)', '10'],
], cw=[40, 390, 50]),
Sp(4), HR(NAVY, 2),
Paragraph('Time: 3 Hours | Total Marks: 100 | All Questions Compulsory', sMeta),
PageBreak(),
]
# ═══════════════════════════════════════════════════════════════════
# Q1: SPLEEN
# ═══════════════════════════════════════════════════════════════════
story += [H1('QUESTION 1 (30 Marks)'),
Body('Write surgical anatomy, physiology and functions of spleen. Describe indications and technique of Splenectomy and post-splenectomy complications.'),
HR(), Sp(2),
H2('A. SURGICAL ANATOMY'),
H3('1. Gross Anatomy'),
Bul('Location: Left hypochondrium, under left dome of diaphragm, 9th–11th rib level'),
Bul('Weight: 100–150 g; Size: 12 × 7 × 4 cm (Rule of 1, 3, 5, 7, 9, 11)'),
Bul('Surfaces: Diaphragmatic (smooth, convex) and Visceral (concave — gastric, renal, colic, pancreatic impressions at hilum)'),
Bul('Superior border: Notched — helps distinguish spleen from left kidney on clinical palpation'),
Bul('Peritoneal covering: Intraperitoneal organ; capsule of fibromuscular tissue with trabeculae'),
Sp(2),
H3('2. Ligaments of the Spleen'),
KeepTogether([diag_spleen_ligaments(),
Cap('Fig 1. Ligaments of the spleen — their contents and surgical significance')]),
Sp(4),
H3('3. Blood Supply — Microcirculation'),
] + [KeepTogether([d]) for d, dh in [diag_splenic_supply()]] + [
Cap('Fig 2. Splenic blood supply from coeliac axis through open and closed splenic microcirculation to portal vein'),
Sp(4),
H3('4. Histology — Microscopic Anatomy'),
# REAL TEXTBOOK IMAGE — spleen diagram
*textbook_image('spleen_diagram.png', width_mm=130,
caption='Fig 3. Microanatomy of the spleen showing white pulp (periarteriolar lymphoid sheaths and follicles), red pulp (sinusoids and cords of Billroth), and marginal zone.',
source='Cellular and Molecular Immunology, 10th Edition (Abbas, Lichtman & Pillai)'),
Sp(2),
# REAL TEXTBOOK IMAGE — spleen histology
*textbook_image('spleen_histology.png', width_mm=130,
caption='Fig 4. Light micrograph of splenic white pulp showing central artery, periarteriolar lymphoid sheath (PALS), lymphoid follicle, and surrounding red pulp (L = lymphocytes).',
source='Cellular and Molecular Immunology, 10th Edition'),
Sp(2),
mktbl([
['Component', 'Structure', 'Function'],
['White pulp', 'Periarteriolar lymphoid sheaths (PALS — T cells)\nLymphoid follicles (B cells)', 'Adaptive immunity; IgM production; T-cell activation'],
['Red pulp', 'Venous sinusoids + Cords of Billroth\n(macrophages, reticular cells)', 'Filters senescent RBCs, opsonised bacteria; iron recycling'],
['Marginal zone','Between red and white pulp; marginal zone B cells\n+ specialised macrophages', 'First contact with blood-borne antigens; innate immunity'],
], cw=[80, 220, 170]),
Sp(4),
H2('B. PHYSIOLOGY AND FUNCTIONS'),
mktbl([
['Function', 'Detail'],
['Filtration', 'Removes senescent/abnormal RBCs, Howell-Jolly bodies, pitted RBCs, siderocytes, encapsulated bacteria'],
['Immunological', 'IgM production; opsonins — Tuftsin & Properdin; NK cells; T & B lymphocyte activation'],
['Haematopoiesis', 'Extramedullary haematopoiesis in fetal life (3rd–5th month) and in adults with marrow failure'],
['Platelet storage', 'Stores ~30% of total body platelets; releases under sympathetic stimulation'],
['Iron recycling', 'Macrophages phagocytose effete RBCs → haem → iron recycled via transferrin'],
['Blood volume', 'Reservoir; contracts under SNS stimulation releasing ~250 mL stored blood'],
], cw=[130, 340]),
Sp(4),
H2('C. INDICATIONS FOR SPLENECTOMY'),
mktbl([
['Category', 'Indications'],
['Haematological','Hereditary spherocytosis (definitive cure)\nITP refractory to steroids\nAutoimmune haemolytic anaemia\nTTP (refractory)\nMyelofibrosis with massive splenomegaly'],
['Traumatic', 'AAST Grade III–V splenic injury\nFailed non-operative management\nHaemodynamic instability'],
['Neoplastic', 'Splenic lymphoma, hairy cell leukaemia\nEn-bloc resection for gastric / pancreatic tail cancer'],
['Other', 'Hypersplenism (portal hypertension)\nSplenic artery aneurysm > 2 cm\nLarge symptomatic splenic cysts / abscess'],
], cw=[110, 360]),
Sp(4),
H2('D. PRE-OPERATIVE PREPARATION'),
Note('Vaccinate ≥ 2 WEEKS BEFORE elective splenectomy: Pneumococcus (PCV13 + PPSV23), Meningococcus ACWY, Haemophilus influenzae type b'),
Bul('Correct thrombocytopenia: IV methylprednisolone ± IVIG ± platelet transfusion for count < 50 × 10⁹/L'),
Bul('Group & crossmatch, consent for open conversion'),
Bul('Antibiotic prophylaxis: Cefuroxime 1.5 g IV at induction'),
Bul('VTE prophylaxis: LMWH + TED stockings'),
Sp(4),
H2('E. TECHNIQUE OF OPEN SPLENECTOMY'),
mktbl([
['Step', 'Action', 'Key Point'],
['1','Supine / right lateral decubitus position','Left side elevated 30–45°'],
['2','Left subcostal (Kocher) incision, or midline/roof-top','Adequate exposure of LUQ essential'],
['3','Divide splenocolic ligament (inferior)','First step — opens the lesser sac'],
['4','Ligate short gastric vessels (gastrosplenic lig.)','Risk of gastric wall injury'],
['5','Divide splenorenal ligament','★ Risk of pancreatic tail injury'],
['6','Displace spleen medially, expose hilum','Identify tail of pancreas'],
['7','★ LIGATE SPLENIC ARTERY FIRST (at hilum)','Allows autotransfusion of ~250 mL stored blood; reduces blood loss'],
['8','Ligate splenic vein','Prevent venous engorgement'],
['9','Divide remaining attachments, extract spleen','Use specimen bag if malignancy suspected'],
['10','Check pancreatic tail — amylase from drain if doubt','Left subphrenic drain optional'],
], cw=[30, 240, 200]),
Sp(4),
H2('F. POST-SPLENECTOMY COMPLICATIONS'),
mktbl([
['Timing', 'Complication', 'Management'],
['Immediate','Haemorrhage (hilum/short gastric)','Return to theatre; angioembolisation'],
['Immediate','Pancreatic tail injury → fistula','Drain, ERCP, conservative / surgery'],
['Immediate','Gastric wall injury', 'Primary repair'],
['Early', 'Reactive thrombocytosis (>1000×10⁹/L)', 'Aspirin; LMWH if symptomatic DVT/PE'],
['Early', 'Left subphrenic abscess', 'CT-guided drainage; IV antibiotics'],
['Early', 'Left pleural effusion / atelectasis','Physiotherapy; drain if large'],
['Late', 'OPSI (most feared)', 'See flowchart below'],
['Late', 'Portal/mesenteric vein thrombosis','Anticoagulation; MDT decision'],
['Late', 'Splenosis', 'Usually harmless; may restore partial function'],
], cw=[60, 200, 210]),
Sp(4),
]
opsi_d, opsi_dh = diag_opsi()
story += [
KeepTogether([opsi_d,
Cap('Fig 5. OPSI management algorithm — immediate recognition and treatment is life-saving')]),
Sp(2),
mktbl([
['OPSI Feature','Detail'],
['Incidence', '0.5–2% lifetime; highest in first 2 years'],
['Organisms', 'S. pneumoniae (50%), N. meningitidis (15%), H. influenzae type b (10%)'],
['Mechanism', 'Loss of: filtration, opsonisation (tuftsin/properdin), IgM production'],
['Presentation','Sudden fever → septicaemia → DIC → MOF in < 24 hours'],
['Prevention', 'Pre-op vaccination + lifelong penicillin V 250 mg BD + patient education card'],
], cw=[110, 360]),
PageBreak(),
]
# ═══════════════════════════════════════════════════════════════════
# Q2: LYMPHOEDEMA
# ═══════════════════════════════════════════════════════════════════
lymph_d, lymph_dh = diag_lymph_path()
cdt_d, cdt_dh = diag_cdt()
story += [H1('QUESTION 2 (20 Marks)'),
Body('Describe Pathophysiology, Classification and Management of Lymphoedema.'),
HR(), Sp(2),
H2('A. DEFINITION'),
Body('Lymphoedema is chronic soft-tissue swelling due to accumulation of protein-rich interstitial fluid from inadequate lymphatic transport, leading to progressive fibrosis, adipose hypertrophy, and immune dysfunction.'),
Sp(2),
H2('B. PATHOPHYSIOLOGY'),
KeepTogether([lymph_d, Cap('Fig 6. Pathophysiology of lymphoedema — from obstruction to irreversible elephantiasis')]),
Sp(2),
Bul('Normal lymphatic system transports 2–4 L of protein-rich fluid per day back to systemic circulation'),
Bul('When transport is inadequate, protein accumulates → ↑ oncotic pressure → more water enters interstitium (self-perpetuating cycle)'),
Bul('Macrophage infiltration → pro-fibrotic cytokines (TGF-β1, IL-6, VEGF-C) → collagen deposition and progressive fibrosis'),
Bul('Adipocyte proliferation in chronic phase → fat hypertrophy (lipoedema component)'),
Bul('Immune dysfunction → recurrent cellulitis → further lymphatic destruction (vicious cycle)'),
Sp(4),
# Lymph node microanatomy image (also relevant for lymphoedema pathophysiology)
*textbook_image('lymph_conduit.png', width_mm=110,
caption='Fig 7. Immunofluorescence of a lymphatic conduit — collagen (green) and laminin basement membrane (red). Damage to such structures causes lymphoedema.',
source='Cellular and Molecular Immunology, 10th Edition (Abbas, Lichtman & Pillai)'),
Sp(4),
H2('C. CLASSIFICATION'),
H3('I. Primary Lymphoedema'),
mktbl([
['Type', 'Onset', 'Genetics', 'Features'],
['Milroy\'s disease', 'Birth', 'VEGFR3/FLT4 mutation\nAutosomal dominant', 'Bilateral legs; aplastic lymphatics; family history'],
['Lymphoedema Praecox\n(Meige\'s disease)', 'Puberty\n(most common)', 'Sporadic; FLT4', 'Female predominance; unilateral leg; hypoplastic lymphatics'],
['Lymphoedema Tarda', '>35 years', 'Sporadic', 'Bilateral; slowly progressive; filarial mimic'],
['Lymphangiectasia', 'Neonatal', 'Variable', 'Dilated incompetent vessels; chylous ascites'],
], cw=[120, 65, 110, 175]),
Sp(4),
H3('II. Secondary Lymphoedema (Acquired)'),
mktbl([
['Cause', 'Mechanism'],
['Filariasis (W. bancrofti)','Most common worldwide; mosquito-borne nematode; obstructs lymphatics → chronic lymphangitis'],
['Post-surgical', 'Axillary dissection (breast ca.), pelvic / inguinal LN dissection (gynae/urological ca.)'],
['Radiotherapy', 'Radiation fibrosis of lymphatic channels — especially post-breast / pelvic RT'],
['Malignant infiltration', 'Lymphoma, carcinoma en cuirasse, nodal metastases causing extrinsic compression'],
['Infection', 'TB lymphadenitis, LGV, recurrent bacterial cellulitis'],
['Chronic venous insufficiency', 'Venous hypertension → secondary lymphatic overload'],
], cw=[160, 310]),
Sp(4),
H3('III. ISL Staging'),
mktbl([
['Stage', 'Clinical Features', 'Reversibility'],
['0 (Latent)', 'Lymphatic damage present; no oedema visible', 'N/A — subclinical'],
['I', 'Soft pitting oedema; reduces fully with elevation', 'Fully reversible'],
['II', 'Non-pitting oedema; does NOT reduce with elevation;\nSkin fibrosis begins', 'Partially reversible'],
['III (Elephantiasis)', 'Massive non-pitting oedema; hyperkeratosis,\npapillomatosis, warty changes, recurrent ulceration', 'Irreversible'],
], cw=[80, 270, 120]),
Sp(2),
Note('Stemmer\'s Sign (Kaposi-Stemmer): Inability to pinch/lift skin fold at base of 2nd toe — PATHOGNOMONIC for lymphoedema'),
Sp(4),
H2('D. INVESTIGATIONS'),
Bul('Lymphoscintigraphy (radionuclide): Gold standard — lymphatic anatomy, transport index, collateral pathways'),
Bul('ICG lymphography: Real-time fluorescence imaging; maps superficial lymphatics for LVA surgical planning'),
Bul('Duplex ultrasound: Exclude DVT; "honeycomb" pattern in subcutaneous tissue on ultrasound'),
Bul('MRI/CT: Cross-sectional anatomy; rule out malignant obstruction; ↑ T2 signal in subcutaneous fat'),
Bul('Bioimpedance spectroscopy: Early detection (Stage 0) — L-Dex score; non-invasive screening'),
Sp(4),
H2('E. MANAGEMENT'),
KeepTogether([cdt_d, Cap('Fig 8. Complete Decongestive Therapy (CDT) — the gold standard treatment for lymphoedema')]),
Sp(4),
H3('1. Conservative (CDT — Complete Decongestive Therapy)'),
mktbl([
['Phase', 'Duration', 'Components'],
['Phase 1\n(Intensive)', '2–4 weeks\nwith therapist', '• Manual Lymphatic Drainage (MLD) daily\n• Multilayer inelastic compression bandaging\n• Skin care (moisturisers, antifungals)\n• Prescribed graded exercises'],
['Phase 2\n(Maintenance)', 'Lifelong\nself-management', '• Custom compression garments (Class 2–3)\n• Self-MLD technique (patient taught)\n• Ongoing exercises\n• Skin care + early treatment of infections'],
], cw=[80, 80, 310]),
Sp(2),
Bul('Pharmacological: DEC (diethylcarbamazine) 6 mg/kg/day × 12 days for filarial lymphoedema; amoxicillin/penicillin for acute cellulitis episodes'),
Bul('Pneumatic compression pumps: Sequential intermittent pneumatic compression as adjunct to CDT'),
Sp(4),
H3('2. Surgical Management'),
mktbl([
['Procedure', 'Indication', 'Mechanism / Notes'],
['Lymphatico-Venous Anastomosis (LVA)','Stage I–II; early','Microsurgical bypass; lymphatic → venous; ↓volume 30–40%'],
['Vascularised LN Transfer (VLNT)', 'Stage II; CDT failed','LN flap transfer → promotes lymphangiogenesis; donor site: groin/axilla/supraclavicular'],
['Liposuction', 'Fat-dominant Stage II','Removes excess adipose; requires lifelong compression post-op'],
['Charles Procedure', 'Stage III elephantiasis','Radical excision all subcutaneous tissue + split-skin grafting'],
['Homans\' Procedure', 'Stage III alternative','Staged subcutaneous excision under skin flaps; less disfiguring'],
], cw=[145, 110, 215]),
PageBreak(),
]
# ═══════════════════════════════════════════════════════════════════
# Q3: SHOCK
# ═══════════════════════════════════════════════════════════════════
shock_d, shock_dh = diag_shock_path()
resus_d, resus_dh = diag_shock_resus()
story += [H1('QUESTION 3 (20 Marks)'),
Body('Pathophysiology and classification of Shock. Discuss resuscitation and management of shock.'),
HR(), Sp(2),
H2('A. DEFINITION'),
Body('Shock is a life-threatening acute circulatory failure with inadequate cellular oxygen utilisation (DO₂ < VO₂), causing anaerobic metabolism, lactic acidosis, and progressive multi-organ dysfunction.'),
Note('Lethal Triad of Trauma: Hypothermia + Coagulopathy + Metabolic Acidosis — each perpetuates the others'),
Sp(2),
H2('B. PATHOPHYSIOLOGY'),
KeepTogether([shock_d, Cap('Fig 9. Pathophysiological cascade of shock — from trigger to MODS')]),
Sp(4),
H2('C. CLASSIFICATION'),
mktbl([
['Type', 'Mechanism', 'Examples', 'Haemodynamics'],
['Hypovolaemic', 'Loss of circulating volume', 'Haemorrhage, burns,\ndehydration, GI losses', 'CO↓ SVR↑ CVP↓'],
['Septic\n(Distributive)', 'Vasodilation + endothelial\ninjury + myocardial depression', 'Gram-neg bacteraemia,\nGram-pos toxins, fungi', 'Early: CO↑ SVR↓\nLate: CO↓ SVR↓'],
['Anaphylactic\n(Distributive)', 'IgE-mediated massive\nvasodilation + bronchospasm', 'Penicillin, nuts, stings,\ncontrast media', 'CO↓/↑ SVR↓ CVP↓'],
['Neurogenic\n(Distributive)', 'Loss of sympathetic tone', 'T6 or higher SCI,\nhigh spinal anaesthesia', 'CO↓ SVR↓\nBradycardia'],
['Cardiogenic', 'Pump failure', 'STEMI, arrhythmia,\nvalve rupture, myocarditis', 'CO↓ SVR↑ CVP↑'],
['Obstructive', 'Mechanical obstruction to flow', 'Massive PE, tension\npneumothorax, tamponade', 'CO↓ SVR↑ CVP↑'],
], cw=[85, 115, 130, 90]),
Sp(4),
H3('ATLS Classification of Haemorrhagic Shock'),
KeepTogether([diag_atls(), Cap('Fig 10. ATLS Class I–IV haemorrhagic shock parameters (70 kg adult)')]),
Sp(4),
H2('D. RESUSCITATION AND MANAGEMENT'),
KeepTogether([resus_d, Cap('Fig 11. Shock resuscitation algorithm with type-specific treatment pathways')]),
Sp(4),
# REAL TEXTBOOK IMAGE — haemorrhage resuscitation diagram
*textbook_image('shock_resus_diagram.png', width_mm=140,
caption='Fig 12. Damage control resuscitation pathway — prioritising coagulation versus perfusion based on bleeding status. (Bailey & Love\'s Surgery, 28th Edition)',
source='Bailey and Love\'s Short Practice of Surgery, 28th Edition'),
Sp(4),
H3('1. Haemorrhagic Shock — Damage Control Resuscitation (DCR)'),
mktbl([
['Principle', 'Action'],
['Permissive hypotension', 'Target SBP 80–90 mmHg until haemostasis achieved (NOT in TBI — maintain MAP ≥80)'],
['Massive Transfusion', 'pRBC : FFP : Platelets = 1:1:1 ratio\nTarget: Hb >7, Fibrinogen >1.5 g/L, INR <1.5, Platelets >50'],
['Tranexamic acid', '1 g IV over 10 min within 3 hours of injury (CRASH-2 trial); then 1 g over 8 hours'],
['Calcium', '1 g CaCl₂ IV per 4 units pRBC (citrate chelation in stored blood)'],
['Avoid lethal triad', 'Warm all fluids; warming blanket; early FFP prevents coagulopathy; bicarb if pH <7.1'],
['Haemostasis', 'Direct pressure, tourniquet → damage control surgery / angioembolisation'],
], cw=[130, 340]),
Sp(4),
H3('2. Septic Shock — Surviving Sepsis Campaign "Hour-1 Bundle"'),
Bul('Measure lactate; if ≥ 4 mmol/L: immediate aggressive resuscitation'),
Bul('Blood cultures × 2 BEFORE antibiotics (but do not delay Abx > 45 min)'),
Bul('Broad-spectrum IV antibiotics within 1 hour of recognition'),
Bul('IV Ringer\'s Lactate 30 mL/kg for hypotension or lactate ≥ 4 mmol/L'),
Bul('Noradrenaline (first-line vasopressor) if MAP < 65 mmHg despite fluids'),
Bul('Hydrocortisone 200 mg/day if vasopressor-refractory'),
Sp(4),
H3('3. Anaphylactic Shock'),
Bul('Adrenaline (epinephrine) 0.5 mg IM (1:1000) into outer thigh — FIRST AND MOST IMPORTANT'),
Bul('Remove trigger; O₂ 15 L/min; IV crystalloid 1–2 L bolus'),
Bul('Chlorphenamine 10 mg IV (H1-blocker); Hydrocortisone 200 mg IV'),
Bul('Salbutamol nebuliser 2.5–5 mg for bronchospasm; repeat adrenaline every 5 min if needed'),
Sp(4),
H3('4. Cardiogenic Shock'),
Bul('Primary PCI (door-to-balloon < 90 min) for STEMI; pericardiocentesis for tamponade'),
Bul('Dobutamine (β1 inotrope) first line; dopamine if bradycardia'),
Bul('IABP (intra-aortic balloon pump) or ECMO in refractory cases'),
Sp(4),
H3('Endpoints of Resuscitation'),
mktbl([
['Parameter', 'Target'],
['MAP', '≥ 65 mmHg'],
['Urine output', '≥ 0.5 mL/kg/hour (adult); ≥ 1 mL/kg/hour (child)'],
['Serum lactate', '< 2 mmol/L; clearance ≥ 10% per 2 hours'],
['ScvO₂', '≥ 70%'],
['Base excess', '> −2 mEq/L'],
['Temperature', '≥ 36°C (avoid hypothermia)'],
['Coagulation', 'INR < 1.5; Fibrinogen > 1.5 g/L; Platelets > 50 × 10⁹/L'],
], cw=[130, 340]),
PageBreak(),
]
# ═══════════════════════════════════════════════════════════════════
# Q4(a): TPN
# ═══════════════════════════════════════════════════════════════════
story += [H1('QUESTION 4(a) — Total Parenteral Nutrition (TPN)'),
HR(), Sp(2),
H2('Definition'),
Body('TPN is the complete intravenous provision of all nutritional requirements — macronutrients (carbohydrates, proteins, lipids), micronutrients (vitamins, trace elements), electrolytes, and water — when the GI tract cannot be used or is insufficient.'),
Sp(2),
H2('Indications'),
mktbl([
['Category', 'Examples'],
['GI failure', 'Paralytic ileus, short bowel syndrome, high-output fistula (>500 mL/day), intestinal obstruction'],
['GI inaccessibility','Severe acute pancreatitis (when EN fails), major GI surgery, oesophageal surgery'],
['Inflammatory', 'Crohn\'s with fistula / toxic megacolon; severe IBD flare'],
['Oncological', 'BMT, chemotherapy mucositis, severe anorexia unresponsive to EN'],
['Neonatal', 'NEC, VLBW, congenital GI anomalies (gastroschisis, jejunal atresia)'],
], cw=[120, 350]),
Sp(4),
H2('Composition'),
mktbl([
['Component', 'Daily Requirement', 'Source', 'Energy'],
['Carbohydrate', '3–5 g/kg/day\n(50–60% non-protein kcal)', 'Dextrose 50%\nGIR < 5 mg/kg/min', '3.4 kcal/g'],
['Amino acids', '1.2–2.0 g/kg/day', 'Crystalline AA solutions\n(essential + non-essential)', '4 kcal/g'],
['Lipid emulsion','1–2 g/kg/day\n(20–30% kcal)', 'Intralipid 20%/SMOF lipid', '9 kcal/g'],
['Total calories','25–30 kcal/kg/day', 'Non-protein:nitrogen = 150:1', '—'],
['Electrolytes', 'Adjusted daily', 'Na⁺, K⁺, Ca²⁺, Mg²⁺, PO₄³⁻','—'],
['Vitamins', 'AMA/ASPEN guidelines', 'Water-soluble (B, C) +\nFat-soluble (A, D, E, K)', '—'],
['Trace elements','ASPEN guidelines', 'Zn, Cu, Se, Cr, Mn', '—'],
], cw=[80, 115, 145, 60]),
Sp(4),
H2('Vascular Access'),
mktbl([
['Route', 'Indication', 'Notes'],
['CVC (subclavian/IJV)', 'Standard TPN', 'Osmolarity can be > 2000 mOsm/L; infection risk'],
['PICC line', 'Long-term (> 2 weeks)', 'Lower infection risk than CVC; basilic > cephalic vein'],
['Peripheral PN','Short-term (< 7 days)', 'Osmolarity MUST be < 800 mOsm/L; thrombophlebitis risk'],
], cw=[130, 110, 230]),
Sp(4),
H2('Complications'),
KeepTogether([diag_tpn_comp(), Cap('Fig 13. TPN complications overview — catheter-related, metabolic and hepatic/GIT')]),
Sp(2),
Note('Refeeding Syndrome: Malnourished patient + TPN → ↓PO₄, ↓K⁺, ↓Mg²⁺ (intracellular shift) → arrhythmia, seizures. PREVENT by starting TPN slowly (50% target), monitor electrolytes 4-hourly, supplement phosphate.'),
Sp(4),
H2('Monitoring'),
mktbl([
['Frequency', 'Parameters'],
['4–6 hourly', 'Blood glucose — target 6–10 mmol/L; insulin infusion if > 10'],
['Daily', 'Electrolytes (Na, K, Mg, Ca, PO₄), fluid balance, weight, clinical assessment'],
['Twice weekly','LFTs, urea & creatinine, triglycerides, FBC'],
['Weekly', 'Coagulation, trace elements, vitamins, nitrogen balance assessment'],
], cw=[100, 370]),
Bul('Transition to enteral nutrition AS SOON AS clinically feasible — gut "use it or lose it"'),
PageBreak(),
]
# ═══════════════════════════════════════════════════════════════════
# Q4(b): BLAST INJURIES
# ═══════════════════════════════════════════════════════════════════
story += [H1('QUESTION 4(b) — Blast Injuries'),
HR(), Sp(2),
H2('Definition'),
Body('Blast injuries result from the sudden release of large amounts of energy from an explosive device, producing a supersonic pressure wave (blast overpressure), blast wind, fragmentation projectiles, thermal flash, and toxic gases — causing a unique pattern of multi-system injury.'),
Sp(2),
H2('Classification'),
KeepTogether([diag_blast(), Cap('Fig 14. Five-category blast injury classification — mechanisms and target organ systems')]),
Sp(4),
mktbl([
['Category', 'Mechanism', 'Key Organs / Injuries'],
['PRIMARY', 'Blast overpressure wave (solid–gas interfaces)', 'Lungs (blast lung), TM rupture, hollow bowel perforation, primary traumatic brain injury (PTBI)'],
['SECONDARY', 'Fragmentation — casing, glass, nails, shrapnel', 'Penetrating wounds to any body part; ocular injuries'],
['TERTIARY', 'Blast wind throws victim against structures', 'Traumatic amputations, long bone fractures, blunt head injury'],
['QUATERNARY','All other effects: thermal, chemical, crush', 'Burns, inhalation injury, crush syndrome, toxic gas exposure'],
['QUINARY', 'Device additives: bacteria, radioactive material', 'Hyperinflammatory state, radiation injury, bioterrorism'],
], cw=[75, 160, 235]),
Sp(4),
H2('Target Organ Injuries'),
H3('Blast Lung — Most Serious Primary Blast Injury'),
Bul('Mechanism: Rapid compression-decompression of gas-filled alveoli → haemorrhage, contusion, pneumothorax'),
Bul('May be initially SILENT — delayed presentation up to 48 hours post-blast'),
Bul('"Butterfly" / "batwing" opacification on CXR'),
Note('AVOID high positive pressure ventilation in blast lung — risk of tension pneumothorax and systemic air embolism. Use low TV (6 mL/kg), permissive hypercapnia strategy'),
H3('Abdominal Blast Injury'),
Bul('Air-filled viscera (colon > small bowel > stomach) most vulnerable to primary blast'),
Bul('Delayed perforation up to 72 hours — observe ALL blast survivors ≥ 24 hours'),
Bul('Solid organ rupture (liver, spleen) from pressure transmission'),
H3('Ear & Head'),
Bul('TM rupture — most common primary blast injury; 50% recover spontaneously'),
Bul('Sensorineural hearing loss, tinnitus, vertigo'),
Bul('Primary traumatic brain injury (PTBI): diffuse axonal injury; chronic traumatic encephalopathy risk'),
Sp(4),
H2('Management'),
mktbl([
['Phase', 'Actions'],
['Scene safety','Decontaminate; triage (START/SALT); extricate; all blast survivors observed ≥ 24 h'],
['Prehospital', 'ABCDE; tourniquet for limb haemorrhage; O₂; c-spine immobilisation'],
['Emergency Dept','ATLS primary + secondary survey; CXR, AXR, FAST/eFAST; ECG'],
['Investigations','CT chest/abdomen; audiometry; ophthalmology; head CT if PTBI'],
['Surgical', 'Explore for haemodynamic instability / peritonism\nDelay primary closure of all blast wounds (72 h)'],
['Wound care', 'Thorough debridement; tetanus prophylaxis; antibiotics; delayed primary closure at 48–72 h'],
['Rehabilitation','Pain management; PTSD screening; prosthetics; audiology; long-term follow-up'],
], cw=[90, 380]),
PageBreak(),
]
# ═══════════════════════════════════════════════════════════════════
# Q4(c): BURNS ASSESSMENT
# ═══════════════════════════════════════════════════════════════════
story += [H1('QUESTION 4(c) — Assessment of Area of Burns (TBSA)'),
HR(), Sp(2),
H2('Importance'),
Body('Accurate estimation of Total Body Surface Area (TBSA) burned determines: fluid resuscitation volumes, need for burns centre referral, prognosis, and operative planning. Only partial-thickness (2nd degree) and full-thickness (3rd/4th degree) burns are included — superficial epidermal (1st degree) burns are EXCLUDED from TBSA calculation.'),
Sp(2),
H2('Methods of TBSA Assessment'),
H3('1. Rule of Nines (Wallace, 1951)'),
KeepTogether([diag_rule_of_nines(), Cap('Fig 15. Rule of Nines schematic body map with adult TBSA percentages')]),
Sp(4),
mktbl([
['Region', 'Adult TBSA', 'Child (1 yr)', 'Notes'],
['Head & Neck', '9%', '18%', 'Decreases 1%/year in children after age 1'],
['Each arm', '9%', '9%', '×2 = 18% both arms; arm 4%, forearm 3%, hand 2.5%'],
['Anterior trunk', '18%', '18%', 'Chest 9% + Abdomen 9%'],
['Posterior trunk','18%', '18%', 'Upper back 9% + Lower back/buttocks 9%'],
['Each leg', '18%', '13.5%', 'Thigh 9% + lower leg 7% + foot 3.5% (adult)'],
['Perineum', '1%', '1%', 'Always constant at 1%'],
['TOTAL', '100%', '100%', '—'],
], cw=[110, 80, 90, 190]),
Sp(4),
H3('2. Lund and Browder Chart — Most Accurate'),
Bul('Divides body into 19 anatomical segments; accounts for age-related body proportions'),
Bul('Mandatory in hospital settings — especially for children and elderly'),
Bul('Uses age-correction tables for "A" (half of head), "B" (half of thigh), "C" (half of lower leg)'),
mktbl([
['Age (years)', '½ Head (A)', '½ Thigh (B)', '½ Lower leg (C)'],
['0 (infant)', '9.5%', '2.75%', '2.5%'],
['1', '8.5%', '3.25%', '2.5%'],
['5', '6.5%', '4.0%', '2.75%'],
['10', '5.5%', '4.25%', '3.0%'],
['15', '4.5%', '4.5%', '3.25%'],
['Adult', '3.5%', '4.75%', '3.5%'],
], cw=[80, 130, 130, 130]),
Sp(4),
H3('3. Palmar Method'),
Bul('Patient\'s own palm (including fingers) ≈ 1% TBSA'),
Bul('Best for small (< 15%) or scattered, irregular burns'),
Bul('Quick; available at bedside; not affected by patient age'),
Sp(4),
H3('4. Digital / Software Methods'),
Bul('Mersey Burns App / eBurncare: Mobile planimetry on tablet/phone; integrates with Parkland formula'),
Bul('3D photographic body mapping (Burn Navigator): increasingly used in tertiary burn centres'),
Sp(4),
H2('Fluid Resuscitation — Clinical Application'),
Note('PARKLAND FORMULA: 4 mL × TBSA (%) × Body weight (kg) = Total Ringer\'s Lactate in first 24 hours FROM TIME OF BURN'),
mktbl([
['Time', 'Volume', 'Fluid'],
['First 8 hours', '50% of total', 'Ringer\'s Lactate (Hartmann\'s solution)'],
['Next 16 hours', '50% of total', 'Ringer\'s Lactate'],
['After 24 hours','Colloid added','0.5 mL/kg/% TBSA albumin 5% + maintenance D/S in children'],
], cw=[120, 120, 230]),
Sp(2),
Bul('Time zero = time of BURN (not arrival to hospital — adjust if delayed)'),
Bul('UO targets: Adult ≥ 0.5 mL/kg/h; Child ≥ 1 mL/kg/h; Electrical burns ≥ 1–2 mL/kg/h'),
Bul('Avoid "fluid creep" (over-resuscitation) → abdominal compartment syndrome, pulmonary oedema'),
Sp(4),
H2('Burns Referral Criteria (British Burn Association)'),
mktbl([
['Refer to Burns Centre if ANY of the following:'],
['TBSA > 10% in adults OR > 5% in children'],
['Any full-thickness burn'],
['Burns to face, hands, feet, genitalia, perineum, major joints, or circumferential burns'],
['Inhalation injury or airway burns'],
['Chemical, electrical, or radiation burns'],
['Burns in patients with significant co-morbidities or extremes of age'],
], cw=[470]),
Sp(6),
HR(NAVY, 2), Sp(2),
Paragraph('— END OF MODEL ANSWERS —', ParagraphStyle('end', parent=ss['Normal'],
fontSize=11, textColor=GREY, alignment=TA_CENTER, fontName='Helvetica-BoldOblique')),
Sp(1),
Paragraph('M.S. Branch-I | July 2020 | General Surgery Paper I', sMeta),
HR(NAVY, 1),
]
# ── BUILD ──────────────────────────────────────────────────────────────────────
out = '/home/daytona/workspace/ms-surgery-answers/MS_Surgery_July2020_Paper1_TextbookImages.pdf'
doc = SimpleDocTemplate(out, pagesize=A4,
leftMargin=26*mm, rightMargin=26*mm, topMargin=22*mm, bottomMargin=20*mm,
title='MS General Surgery July 2020 Paper I - Model Answers with Textbook Images',
author='Orris Medical AI',
)
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f'SUCCESS → {out}')
cd /home/daytona/workspace/ms-surgery-answers && python3 gen_pdf_v2.py 2>&1
python3 -c " from PIL import Image as PILImage import os imgs = os.listdir('/home/daytona/workspace/ms-surgery-answers/textbook_images/') for img in sorted(imgs): path = f'/home/daytona/workspace/ms-surgery-answers/textbook_images/{img}' i = PILImage.open(path) print(f'{img}: {i.size[0]}x{i.size[1]} px, mode={i.mode}') "
~/ms-surgery-answers/gen_pdf_v2.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ms-surgery-answers/gen_pdf_v2.py'
~/ms-surgery-answers/gen_pdf_v2.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ms-surgery-answers/gen_pdf_v2.py'
~/ms-surgery-answers/gen_pdf_v2.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ms-surgery-answers/gen_pdf_v2.py'
~/ms-surgery-answers/gen_pdf_v2.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ms-surgery-answers/gen_pdf_v2.py'
cd /home/daytona/workspace/ms-surgery-answers && python3 gen_pdf_v2.py 2>&1
python3 -c " from pypdf import PdfReader r = PdfReader('/home/daytona/workspace/ms-surgery-answers/MS_Surgery_July2020_Paper1_TextbookImages.pdf') print(f'Pages: {len(r.pages)}') import os size = os.path.getsize('/home/daytona/workspace/ms-surgery-answers/MS_Surgery_July2020_Paper1_TextbookImages.pdf') print(f'File size: {size/1024:.0f} KB') "
MS Surgery July2020 Paper1 TextbookImages
PDF Document · PDF
| Fig | Image | Textbook Source |
|---|---|---|
| Fig 3 | Spleen microanatomy — cross-section diagram showing white pulp (PALS + follicles), red pulp, marginal zone | Cellular & Molecular Immunology, 10th Ed (Abbas, Lichtman & Pillai) |
| Fig 4 | Spleen histology micrograph — white pulp, central artery, lymphoid follicle, red pulp (L = lymphocytes) | Cellular & Molecular Immunology, 10th Ed |
| Fig 7 | Lymphatic conduit immunofluorescence — collagen (green) + laminin (red) — illustrates lymphoedema pathology | Cellular & Molecular Immunology, 10th Ed |
| Fig 12 | Damage control resuscitation pathway diagram — coagulation vs perfusion priorities | Bailey & Love's Short Practice of Surgery, 28th Ed |