Can u make a note on a page containing all the best nd boss season tion in fmt in pc Ignatius in a order that I can remember nd revise

Asking for Preferences

Can u make a note on a page containing all the bns nd bnss season tion in fmt in pc Ignatius in a order that I can remember nd revise

Asking for Preferences
Asking for Preferences
Searching the Web

BNS BNSS sections relevant forensic medicine toxicology PC Ignatius medical students

Reading File
Running Command

mkdir -p /tmp/workspace/fmt-bns-notes && ls /tmp/workspace/fmt-bns-notes/

Writing File

~/fmt-bns-notes/generate_pdf.py

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

doc_path = "/tmp/workspace/fmt-bns-notes/BNS_BNSS_FMT_Revision_Notes.pdf"

doc = SimpleDocTemplate(
    doc_path,
    pagesize=A4,
    rightMargin=15*mm,
    leftMargin=15*mm,
    topMargin=18*mm,
    bottomMargin=18*mm
)

styles = getSampleStyleSheet()

# Custom styles
NAVY = colors.HexColor("#1a2e5a")
TEAL = colors.HexColor("#0e6b7a")
GOLD = colors.HexColor("#c8860a")
LIGHT_BLUE = colors.HexColor("#dbeeff")
LIGHT_GREEN = colors.HexColor("#e6f7f0")
LIGHT_YELLOW = colors.HexColor("#fff8e1")
LIGHT_PINK = colors.HexColor("#fce4ec")
LIGHT_PURPLE = colors.HexColor("#f3e5f5")
LIGHT_ORANGE = colors.HexColor("#fff3e0")
WHITE = colors.white
DARK_GRAY = colors.HexColor("#2d2d2d")

title_style = ParagraphStyle(
    "TitleStyle",
    parent=styles["Title"],
    fontSize=20,
    textColor=WHITE,
    alignment=TA_CENTER,
    fontName="Helvetica-Bold",
    spaceAfter=4,
)
subtitle_style = ParagraphStyle(
    "SubtitleStyle",
    parent=styles["Normal"],
    fontSize=10,
    textColor=colors.HexColor("#c8e6ff"),
    alignment=TA_CENTER,
    fontName="Helvetica",
    spaceAfter=2,
)
section_header_style = ParagraphStyle(
    "SectionHeader",
    parent=styles["Normal"],
    fontSize=13,
    textColor=WHITE,
    fontName="Helvetica-Bold",
    alignment=TA_LEFT,
    leftIndent=4,
    spaceAfter=2,
    spaceBefore=2,
)
subsection_style = ParagraphStyle(
    "SubsectionStyle",
    parent=styles["Normal"],
    fontSize=10.5,
    textColor=NAVY,
    fontName="Helvetica-Bold",
    alignment=TA_LEFT,
    spaceBefore=4,
    spaceAfter=2,
)
body_style = ParagraphStyle(
    "BodyStyle",
    parent=styles["Normal"],
    fontSize=9.5,
    textColor=DARK_GRAY,
    fontName="Helvetica",
    alignment=TA_JUSTIFY,
    spaceBefore=1,
    spaceAfter=1,
    leading=13,
)
note_style = ParagraphStyle(
    "NoteStyle",
    parent=styles["Normal"],
    fontSize=8.5,
    textColor=colors.HexColor("#555555"),
    fontName="Helvetica-Oblique",
    alignment=TA_LEFT,
    leftIndent=8,
    spaceBefore=1,
    spaceAfter=1,
)
small_bold = ParagraphStyle(
    "SmallBold",
    parent=styles["Normal"],
    fontSize=9,
    textColor=DARK_GRAY,
    fontName="Helvetica-Bold",
)
table_header_style = ParagraphStyle(
    "TableHeader",
    parent=styles["Normal"],
    fontSize=9,
    textColor=WHITE,
    fontName="Helvetica-Bold",
    alignment=TA_CENTER,
)
table_cell_style = ParagraphStyle(
    "TableCell",
    parent=styles["Normal"],
    fontSize=8.5,
    textColor=DARK_GRAY,
    fontName="Helvetica",
    alignment=TA_LEFT,
    leading=11,
)
table_cell_center = ParagraphStyle(
    "TableCellCenter",
    parent=styles["Normal"],
    fontSize=8.5,
    textColor=DARK_GRAY,
    fontName="Helvetica",
    alignment=TA_CENTER,
    leading=11,
)
highlight_style = ParagraphStyle(
    "HighlightStyle",
    parent=styles["Normal"],
    fontSize=9,
    textColor=colors.HexColor("#7b0000"),
    fontName="Helvetica-Bold",
    leftIndent=6,
)

story = []

# ─── TITLE BANNER ────────────────────────────────────────────────────────────
def make_title_banner():
    data = [[
        Paragraph("BNS & BNSS Sections", title_style),
        ],
        [Paragraph("Relevant to Forensic Medicine & Toxicology", subtitle_style)],
        [Paragraph("As per PC Ignatius | Quick Revision Notes", subtitle_style)],
    ]
    t = Table(data, colWidths=[180*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), NAVY),
        ("ALIGN", (0,0), (-1,-1), "CENTER"),
        ("TOPPADDING", (0,0), (-1,0), 10),
        ("BOTTOMPADDING", (0,-1), (-1,-1), 10),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("RIGHTPADDING", (0,0), (-1,-1), 8),
        ("ROUNDEDCORNERS", [6]),
    ]))
    return t

story.append(make_title_banner())
story.append(Spacer(1, 6*mm))

# ─── INTRO BOX ───────────────────────────────────────────────────────────────
intro_data = [[Paragraph(
    "<b>KEY:</b>  BNS = Bharatiya Nyaya Sanhita 2023 (replaces IPC) &nbsp;|&nbsp; "
    "BNSS = Bharatiya Nagarik Suraksha Sanhita 2023 (replaces CrPC) &nbsp;|&nbsp; "
    "BSA = Bharatiya Sakshya Adhiniyam 2023 (replaces IEA)",
    body_style
)]]
intro_t = Table(intro_data, colWidths=[180*mm])
intro_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), LIGHT_YELLOW),
    ("BOX", (0,0), (-1,-1), 1, GOLD),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING", (0,0), (-1,-1), 8),
    ("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
story.append(intro_t)
story.append(Spacer(1, 5*mm))

# ─────────────────────────────────────────────────────────────────────────────
# HELPER: section banner
# ─────────────────────────────────────────────────────────────────────────────
def section_banner(text, color=TEAL):
    data = [[Paragraph(text, section_header_style)]]
    t = Table(data, colWidths=[180*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), color),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("RIGHTPADDING", (0,0), (-1,-1), 8),
    ]))
    return t

# ─────────────────────────────────────────────────────────────────────────────
# SECTION 1: BNS — OFFENCES (ex-IPC sections)
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_banner("SECTION 1: BNS 2023 — Offences Relevant to FMT", color=NAVY))
story.append(Spacer(1, 3*mm))

# TABLE: BNS sections
bns_headers = [
    Paragraph("BNS Sec.", table_header_style),
    Paragraph("Old IPC", table_header_style),
    Paragraph("Topic", table_header_style),
    Paragraph("Key Points for FMT", table_header_style),
]

bns_data = [
    # General
    ["11", "44", "Injury", "Bodily harm to any person — foundation for wound description in MLRs"],
    ["2(17)", "—", "Child", "Person <18 yrs — relevant to infanticide, POCSO cases"],
    ["2(20)", "—", "Death", "Cessation of life — medico-legal definition used in PME"],
    ["2(22)", "—", "Document", "Includes medical certificates, post-mortem reports"],
    ["2(55)", "—", "Wrongful gain/loss", "Relevant to medical negligence fraud cases"],
    # Culpable homicide & murder
    ["100", "299", "Culpable Homicide (CH)", "Causing death with intention / knowledge it will likely cause death"],
    ["101", "300", "Murder", "CH becomes murder if done with intention to cause death or bodily injury sufficient to cause death; Exceptions: grave provocation, exceeding private defence"],
    ["105", "304A", "Death by Negligence", "No intention; rash/negligent act by doctor = medical negligence; 2 yrs imprisonment / fine / both"],
    ["106", "304B", "Dowry Death", "Death within 7 yrs of marriage due to burns/bodily injury; ILL-TREATMENT by husband or relatives"],
    ["109", "307", "Attempt to Murder", "Act done with intention/knowledge to cause death"],
    ["115", "319", "Hurt", "Causing bodily pain, disease or infirmity"],
    ["116", "320", "Grievous Hurt", "Emasculation; permanent privation of sight/hearing; loss of any limb/joint; permanent disfiguration of head/face; fracture or dislocation of bone/tooth; any hurt endangering life / causing 20-day severe body pain"],
    ["117", "321", "Voluntarily causing Hurt", "Person causes hurt; used in MLR for classifying assault injuries"],
    ["118", "322", "Voluntarily causing Grievous Hurt", "—"],
    ["124", "326A", "Acid Attack", "Permanent or partial damage by acid; min 10 yrs to life imprisonment"],
    ["125", "326B", "Attempt to throw Acid", "2–7 yrs imprisonment"],
    ["131", "338", "Grievous Hurt by Rash/Negligent Act", "Endangering life/safety of others; 2 yrs / fine / both"],
    ["138", "304A", "Causing Death by Negligence", "Rash/negligent act not amounting to CH — medical negligence"],
    # Sexual offences
    ["63", "375", "Rape", "6 exceptions: includes age <18 always rape; MLR mandatory; examination by female doctor preferred"],
    ["64", "376", "Punishment for Rape", "Min 10 yrs to life + fine"],
    ["65", "376A–D", "Aggravated Rape", "By police/public servant/gang rape; min 20 yrs to life/death"],
    ["69", "376C", "Sexual intercourse by deceit/false promise of marriage", "Imprisonment up to 10 yrs + fine"],
    ["70", "376D", "Gang Rape", "Rigorous imprisonment ≥20 yrs to life"],
    ["74", "354", "Outraging Modesty", "1–5 yrs; includes stalking"],
    ["75", "354A", "Sexual Harassment", "Up to 3 yrs / fine / both"],
    ["77", "354C", "Voyeurism", "1st offence: 1–3 yrs; 2nd: 3–7 yrs"],
    ["78", "354D", "Stalking", "1st: 3 yrs; 2nd: 5 yrs"],
    ["94", "377", "Unnatural Offences", "Voluntarily having carnal intercourse against the order of nature"],
    # Abortion
    ["88", "312", "Causing Miscarriage (Abortion)", "Unless to save mother's life; 3 yrs / fine / both; 7 yrs if woman quick with child"],
    ["89", "313", "Abortion without Consent", "Life imprisonment or 10 yrs + fine"],
    ["90", "314", "Death caused in attempt to cause Miscarriage", "10 yrs or life imprisonment"],
    ["91", "315", "Acts to prevent child from being born alive / cause death after birth", "10 yrs / fine / both"],
    ["92", "316", "Causing Death of Quick Unborn Child", "Culpable homicide – life imprisonment"],
    # Infanticide & abandonment
    ["93", "317", "Exposure & Abandonment of child <12 yrs", "7 yrs / fine / both"],
    ["86", "310B", "Child Trafficking", "—"],
    # False evidence/certificates
    ["227", "191", "Giving False Evidence", "7 yrs + fine; relevant to doctors giving false certificates"],
    ["228", "192", "Fabricating False Evidence", "—"],
    ["231", "196", "Using False Evidence as True", "—"],
    ["237", "202", "Omission to give information", "Withholding info from magistrate/police"],
    ["240", "204", "Destruction of Document", "Destroying medical/legal evidence"],
    # Negligence / Public servant
    ["202", "304A", "Medical Negligence (general)", "Rash/negligent act; NOT intentional killing"],
    ["174B", "197B", "False certificate by public servant", "1 yr / fine / both — relevant to MOs issuing false certificates"],
    # Poisoning
    ["122", "328", "Causing Hurt by Poison", "Administering poison/stupefying substance; 10 yrs / fine"],
    # Consent
    ["20", "87", "Consent – no offence for acts causing grievous hurt by consent", "Consent <18 yrs = not valid"],
    ["21", "88", "Medical treatment under consent", "Good faith treatment; patient consents to harm; valid legal defence for doctors"],
    ["22", "89", "Act done in good faith for child/insane person", "Guardian consent valid"],
]

bns_table_data = [bns_headers]
for row in bns_data:
    bns_table_data.append([
        Paragraph(f"<b>{row[0]}</b>", table_cell_center),
        Paragraph(row[1], table_cell_center),
        Paragraph(f"<b>{row[2]}</b>", table_cell_style),
        Paragraph(row[3], table_cell_style),
    ])

bns_t = Table(
    bns_table_data,
    colWidths=[18*mm, 18*mm, 44*mm, 100*mm],
    repeatRows=1
)
bns_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), NAVY),
    ("TEXTCOLOR", (0,0), (-1,0), WHITE),
    ("ALIGN", (0,0), (1,-1), "CENTER"),
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("FONTSIZE", (0,0), (-1,0), 9),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 4),
    ("RIGHTPADDING", (0,0), (-1,-1), 4),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
    ("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#aaaaaa")),
    ("LINEBELOW", (0,0), (-1,0), 1.5, GOLD),
]))
story.append(bns_t)
story.append(Spacer(1, 5*mm))

# ─────────────────────────────────────────────────────────────────────────────
# SECTION 2: BNSS — Procedure (ex-CrPC)
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_banner("SECTION 2: BNSS 2023 — Procedure Relevant to FMT", color=colors.HexColor("#145a32")))
story.append(Spacer(1, 3*mm))

bnss_headers = [
    Paragraph("BNSS Sec.", table_header_style),
    Paragraph("Old CrPC", table_header_style),
    Paragraph("Topic", table_header_style),
    Paragraph("Key Points for FMT", table_header_style),
]

bnss_data = [
    ["173", "154", "FIR (First Information Report)", "Duty of police to register; copy to magistrate; doctor informs police of ML case"],
    ["176(1)", "174", "Inquest by Police", "Investigation of unnatural/sudden death; constable/police officer in charge"],
    ["176(3)", "NEW", "Forensic Expert at Scene", "MANDATORY forensic team for offences punishable ≥7 yrs; 5-yr implementation period; forensic expert must document & collect evidence"],
    ["194", "176", "Magistrate Inquest", "Inquest by Executive Magistrate: dowry deaths, police custody deaths, gang rape victims, acid attack deaths"],
    ["195", "177", "Jurisdiction of Inquest", "Magistrate of district where body found"],
    ["230", "198B", "Complaint for Rape of wife", "Court cannot take cognisance unless wife files complaint (wife ≥18 yrs)"],
    ["248", "161", "Examination of witnesses by police", "Statements to police — not admissible; doctor's verbal information"],
    ["249", "162", "Statements not to be signed; use of statement", "Police statements can be used to contradict a witness in court"],
    ["312", "273", "Evidence to be in presence of accused", "Doctor's court testimony given in presence of accused"],
    ["329", "293", "Government Scientific Expert's Report", "Written report admissible in evidence without oral testimony; BNSS expands to 'any other scientific expert' beyond govt expert; Experts listed: FSL, Chemical Examiner, Serologist, Fingerprint, Handwriting, Ballistic experts + others"],
    ["349", "311A", "Power of Magistrate to order samples", "Finger impressions, handwriting, voice samples, blood, saliva, semen etc. on written order from 1st class Magistrate; BNSS allows without prior arrest (broader than old CrPC 311A)"],
    ["350", "312", "Examination of accused by doctor", "Medical examination of accused by registered medical practitioner on request of police officer (rape cases)"],
    ["351", "313", "Power to examine accused", "Court may examine accused; used in mental state assessments"],
    ["376", "327", "Trial of rape in camera", "In-camera trial for rape; identity of victim protected"],
    ["397", "357", "Compensation to victims", "Court can award compensation to victim of crime including rape/acid attack"],
    ["530(a)", "509", "Insult to modesty – word/gesture", "Simple imprisonment up to 3 yrs + fine"],
    ["184", "185", "Examination of person in police custody", "Magistrate can order medical examination; important in custodial torture cases"],
    ["360", "316", "Detention in safe custody (insane accused)", "Accused of unsound mind detained until fit for trial — Sec 84 BNS defence applies"],
    ["505", "482", "Inherent powers of High Court", "HC can quash FIR/proceedings — relevant to medical negligence FIRs"],
]

bnss_table_data = [bnss_headers]
for row in bnss_data:
    bnss_table_data.append([
        Paragraph(f"<b>{row[0]}</b>", table_cell_center),
        Paragraph(row[1], table_cell_center),
        Paragraph(f"<b>{row[2]}</b>", table_cell_style),
        Paragraph(row[3], table_cell_style),
    ])

bnss_t = Table(
    bnss_table_data,
    colWidths=[18*mm, 18*mm, 44*mm, 100*mm],
    repeatRows=1
)
bnss_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#145a32")),
    ("TEXTCOLOR", (0,0), (-1,0), WHITE),
    ("ALIGN", (0,0), (1,-1), "CENTER"),
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("FONTSIZE", (0,0), (-1,0), 9),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 4),
    ("RIGHTPADDING", (0,0), (-1,-1), 4),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_GREEN]),
    ("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#aaaaaa")),
    ("LINEBELOW", (0,0), (-1,0), 1.5, GOLD),
]))
story.append(bnss_t)
story.append(Spacer(1, 5*mm))

# ─────────────────────────────────────────────────────────────────────────────
# SECTION 3: BSA (Bharatiya Sakshya Adhiniyam) — Evidence
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_banner("SECTION 3: BSA 2023 — Evidence Relevant to FMT", color=colors.HexColor("#6d1a7a")))
story.append(Spacer(1, 3*mm))

bsa_headers = [
    Paragraph("BSA Sec.", table_header_style),
    Paragraph("Old IEA", table_header_style),
    Paragraph("Topic", table_header_style),
    Paragraph("Key Points for FMT", table_header_style),
]
bsa_data = [
    ["26", "32(1)", "Dying Declaration", "Statement by person who believes death imminent; admissible even if declarant dies; doctor may record; no oath needed; thumb impression accepted"],
    ["27", "32(2)–(8)", "Statements by deceased in other situations", "Includes cause of death of deceased in proceedings where their death is in question"],
    ["39", "45", "Expert Witness", "Opinions of expert in science, art, foreign law etc. — doctor as expert witness in court"],
    ["40", "46", "Facts bearing upon opinions of experts", "Facts on which expert's opinion is based — basis of medico-legal report"],
    ["57", "65B", "Admissibility of Electronic Records", "Electronic evidence (CCTV, digital records) — important in new era forensics"],
    ["63", "73", "Comparison of signatures / handwriting", "Handwriting expert evidence — questioned documents"],
    ["30", "35", "Relevance of entries in public records", "Hospital admission records, death registers — admissible as evidence"],
    ["114", "114", "Presumptions of fact by court", "Court may presume: rape accused knew victim was <18 if she looks <18; woman's recent absence = presumed dead if 7 yrs"],
    ["118", "118", "Who may testify", "All persons competent to testify unless court considers them unable to understand due to mental illness etc."],
    ["119", "119", "Deaf-mute witness", "Can give evidence in writing or by signs; relevant to forensic psychiatry"],
    ["166", "165", "Judge's power to ask questions", "Judge may ask any question in any form at any time — affects expert witness examination"],
]
bsa_table_data = [bsa_headers]
for row in bsa_data:
    bsa_table_data.append([
        Paragraph(f"<b>{row[0]}</b>", table_cell_center),
        Paragraph(row[1], table_cell_center),
        Paragraph(f"<b>{row[2]}</b>", table_cell_style),
        Paragraph(row[3], table_cell_style),
    ])
bsa_t = Table(
    bsa_table_data,
    colWidths=[18*mm, 18*mm, 44*mm, 100*mm],
    repeatRows=1
)
bsa_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#6d1a7a")),
    ("TEXTCOLOR", (0,0), (-1,0), WHITE),
    ("ALIGN", (0,0), (1,-1), "CENTER"),
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("FONTSIZE", (0,0), (-1,0), 9),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 4),
    ("RIGHTPADDING", (0,0), (-1,-1), 4),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_PURPLE]),
    ("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#aaaaaa")),
    ("LINEBELOW", (0,0), (-1,0), 1.5, GOLD),
]))
story.append(bsa_t)
story.append(Spacer(1, 5*mm))

# ─────────────────────────────────────────────────────────────────────────────
# SECTION 4: TOPIC-WISE QUICK CROSS-REFERENCE
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_banner("SECTION 4: Topic-wise Quick Cross Reference (Exam-Ready)", color=colors.HexColor("#8b1a1a")))
story.append(Spacer(1, 3*mm))

xref_data = [
    [Paragraph("<b>FMT Topic</b>", table_header_style), Paragraph("<b>BNS Section</b>", table_header_style), Paragraph("<b>BNSS Section</b>", table_header_style), Paragraph("<b>BSA Section</b>", table_header_style)],
    [Paragraph("<b>Wounds / Injuries</b>", table_cell_style), Paragraph("Sec 11 (Injury)\nSec 115–131 (Hurt → Grievous Hurt)\nSec 124–125 (Acid Attack)", table_cell_style), Paragraph("Sec 350 (Medical exam of accused)\nSec 184 (Custody exam)", table_cell_style), Paragraph("Sec 39 (Expert opinion)\nSec 40 (Expert's basis)", table_cell_style)],
    [Paragraph("<b>Death Investigation</b>", table_cell_style), Paragraph("Sec 100–105 (CH/Murder)\nSec 106 (Dowry death)\nSec 105 (Negligent death)", table_cell_style), Paragraph("Sec 176(1) (Police inquest)\nSec 194 (Magistrate inquest)\nSec 176(3) (Forensic expert at scene)", table_cell_style), Paragraph("Sec 26 (Dying Declaration)\nSec 27 (Deceased's statements)", table_cell_style)],
    [Paragraph("<b>Rape / Sexual Assault</b>", table_cell_style), Paragraph("Sec 63–70 (Rape, aggravated, gang)\nSec 74–78 (Outraging modesty)\nSec 94 (Unnatural offences)", table_cell_style), Paragraph("Sec 350 (Exam of accused)\nSec 376 (In-camera trial)\nSec 230 (Complaint by wife)", table_cell_style), Paragraph("Sec 114 (Presumption re: age)\nSec 39 (Expert witness)", table_cell_style)],
    [Paragraph("<b>Abortion / MTP</b>", table_cell_style), Paragraph("Sec 88–92 (Miscarriage, quick child)\nSec 91–92 (Infanticide-adjacent)", table_cell_style), Paragraph("—", table_cell_style), Paragraph("—", table_cell_style)],
    [Paragraph("<b>Infanticide / Child</b>", table_cell_style), Paragraph("Sec 93 (Exposure of child)\nSec 2(17) (Child <18 yrs)\nSec 86 (Child trafficking)", table_cell_style), Paragraph("Sec 176(3) (Crime scene forensics)", table_cell_style), Paragraph("Sec 118–119 (Witness competency)", table_cell_style)],
    [Paragraph("<b>Medical Negligence</b>", table_cell_style), Paragraph("Sec 105 (Negligent death / 304A)\nSec 131 (GH by negligence)\nSec 21 (Consent – doctor defence)", table_cell_style), Paragraph("Sec 505 (HC quash FIR)\nSec 248 (Witness examination)", table_cell_style), Paragraph("Sec 39 (Expert witness)", table_cell_style)],
    [Paragraph("<b>Poisoning</b>", table_cell_style), Paragraph("Sec 122 (Causing hurt by poison)\nSec 105 (Negligent death by drugs)", table_cell_style), Paragraph("Sec 329 (Expert report admissible)\nSec 349 (Biological sample order)", table_cell_style), Paragraph("Sec 39 (Toxicologist as expert)", table_cell_style)],
    [Paragraph("<b>Identification / Forensic Science</b>", table_cell_style), Paragraph("—", table_cell_style), Paragraph("Sec 329 (Govt scientific expert)\nSec 349 (Fingerprints/voice samples)\nSec 176(3) (Forensic at scene)", table_cell_style), Paragraph("Sec 57 (Electronic evidence)\nSec 63 (Handwriting comparison)", table_cell_style)],
    [Paragraph("<b>Mental Health / Psychiatry</b>", table_cell_style), Paragraph("Sec 22 BNS (Unsoundness of mind)\nSec 84 IPC → Sec 22 BNS: McNaughten rules", table_cell_style), Paragraph("Sec 360 (Detention of insane accused)\nSec 351 (Examination of accused)", table_cell_style), Paragraph("Sec 118 (Competency of witness)", table_cell_style)],
    [Paragraph("<b>Dying Declaration</b>", table_cell_style), Paragraph("—", table_cell_style), Paragraph("Sec 176 (Inquest note dying decl.)", table_cell_style), Paragraph("Sec 26 BSA (Dying Declaration admissible)\nDoctor's fitness certificate validates", table_cell_style)],
    [Paragraph("<b>False Certificates</b>", table_cell_style), Paragraph("Sec 227–228 (False evidence)\nSec 174B (False cert by public servant)", table_cell_style), Paragraph("—", table_cell_style), Paragraph("Sec 30 (Public record entries)", table_cell_style)],
]
xref_t = Table(
    xref_data,
    colWidths=[40*mm, 50*mm, 48*mm, 42*mm],
    repeatRows=1
)
xref_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#8b1a1a")),
    ("TEXTCOLOR", (0,0), (-1,0), WHITE),
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 4),
    ("RIGHTPADDING", (0,0), (-1,-1), 4),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_PINK]),
    ("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#aaaaaa")),
    ("LINEBELOW", (0,0), (-1,0), 1.5, GOLD),
]))
story.append(xref_t)
story.append(Spacer(1, 5*mm))

# ─────────────────────────────────────────────────────────────────────────────
# SECTION 5: HIGH-YIELD MNEMONICS & MEMORY AIDS
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_banner("SECTION 5: High-Yield Mnemonics & Memory Aids", color=colors.HexColor("#b35900")))
story.append(Spacer(1, 3*mm))

mnemonics = [
    ("GRIEVOUS HURT (BNS Sec.116) — Mnemonic: 'E-PELL-FBH'",
     "E = Emasculation\n"
     "P = Privation of sight (permanent)\n"
     "E = Ear (permanent privation of hearing)\n"
     "L = Limb / joint loss (any member / joint)\n"
     "L = Look (permanent disfiguration of head/face)\n"
     "F = Fracture or dislocation of bone or tooth\n"
     "B = Body pain >20 days or severe pain\n"
     "H = Hurt endangering life"
    ),
    ("RAPE (BNS Sec.63) — 6 EXCEPTIONS where consent irrelevant",
     "1. Wife <18 yrs (marital rape of minor)\n"
     "2. Fear of death or hurt\n"
     "3. Unsoundness of mind / intoxication\n"
     "4. Below age of consent (18 yrs)\n"
     "5. Consent obtained by fraud / impersonation\n"
     "6. Communicates consent but in a state unable to understand"
    ),
    ("MAGISTRATE INQUEST (BNSS Sec.194) — Mnemonic: 'D-PGA'",
     "D = Dowry death (within 7 yrs)\n"
     "P = Police custody death\n"
     "G = Gang rape victim's death\n"
     "A = Acid attack victim's death"
    ),
    ("DYING DECLARATION (BSA Sec.26) — 'FACE'",
     "F = Fit to make statement (doctor certifies mental fitness)\n"
     "A = Ante mortem (made when death was apprehended)\n"
     "C = Complete (though incomplete may still be accepted)\n"
     "E = Even without oath; thumb impression valid"
    ),
    ("BNSS Sec.329 — Experts who can send report without court appearance",
     "Chemical Examiner / Asst Chemical Examiner\n"
     "Chief Inspector of Explosives\n"
     "Director of Fingerprint Bureau\n"
     "Director / Deputy Director — FSL\n"
     "Serologist to Government\n"
     "+ Any other scientific expert notified by Central/State Govt"
    ),
    ("IPC vs BNS — KEY SECTION PAIRS to remember",
     "IPC 302 (Murder) → BNS 101\n"
     "IPC 304A (Negligence) → BNS 105 / 106\n"
     "IPC 312 (Abortion) → BNS 88\n"
     "IPC 320 (Grievous Hurt) → BNS 116\n"
     "IPC 375 (Rape) → BNS 63\n"
     "IPC 328 (Poison) → BNS 122\n"
     "IPC 87–89 (Consent) → BNS 20–22"
    ),
]

for title, content in mnemonics:
    m_data = [
        [Paragraph(f"<b>{title}</b>", ParagraphStyle("mT", parent=styles["Normal"], fontSize=9.5, textColor=colors.HexColor("#5a2d00"), fontName="Helvetica-Bold"))],
        [Paragraph(content.replace("\n", "<br/>"), ParagraphStyle("mB", parent=styles["Normal"], fontSize=9, textColor=DARK_GRAY, fontName="Courier", leading=13, leftIndent=6))],
    ]
    m_t = Table(m_data, colWidths=[180*mm])
    m_t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), LIGHT_ORANGE),
        ("BACKGROUND", (0,1), (-1,1), colors.HexColor("#fffdf5")),
        ("BOX", (0,0), (-1,-1), 0.7, colors.HexColor("#e08000")),
        ("TOPPADDING", (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING", (0,0), (-1,-1), 7),
        ("RIGHTPADDING", (0,0), (-1,-1), 7),
    ]))
    story.append(m_t)
    story.append(Spacer(1, 2.5*mm))

story.append(Spacer(1, 3*mm))

# ─────────────────────────────────────────────────────────────────────────────
# SECTION 6: IMPORTANT NUMBERS / PENALTIES AT A GLANCE
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_banner("SECTION 6: Important Numbers & Punishments at a Glance", color=colors.HexColor("#1a3c5a")))
story.append(Spacer(1, 3*mm))

num_data = [
    [Paragraph("<b>Offence</b>", table_header_style), Paragraph("<b>BNS Sec.</b>", table_header_style), Paragraph("<b>Punishment</b>", table_header_style)],
    ["Culpable Homicide not amounting to Murder", "101", "Life / 10 yrs + fine"],
    ["Murder", "101", "Death / Life + fine"],
    ["Negligent Death (Medical Negligence)", "105", "2 yrs / fine / both"],
    ["Dowry Death", "106", "7 yrs → Life"],
    ["Rape (basic)", "64", "Min 10 yrs → Life + fine"],
    ["Gang Rape", "70", "≥20 yrs → Life"],
    ["Aggravated Rape (custody/repeat)", "65", "Min 20 yrs → Life / Death"],
    ["Acid Attack", "124", "Min 10 yrs → Life + fine (special)"],
    ["Attempt to throw Acid", "125", "2–7 yrs + fine"],
    ["Causing Miscarriage", "88", "3 yrs / fine (7 yrs if quick with child)"],
    ["Causing Hurt by Poison", "122", "10 yrs + fine"],
    ["Grievous Hurt by Negligence", "131", "2 yrs / fine / both"],
    ["Outraging Modesty of Woman", "74", "1–5 yrs + fine"],
    ["False Evidence (Certificate)", "227", "7 yrs + fine"],
    ["False Certificate by Public Servant", "174B", "1 yr / fine / both"],
    ["Exposure/Abandonment of child <12 yrs", "93", "7 yrs / fine / both"],
    ["Unnatural Offences", "94", "Life / 10 yrs + fine"],
]
num_t_data = [num_data[0]]
for row in num_data[1:]:
    num_t_data.append([
        Paragraph(row[0], table_cell_style),
        Paragraph(f"<b>{row[1]}</b>", table_cell_center),
        Paragraph(row[2], table_cell_style),
    ])
num_t = Table(num_t_data, colWidths=[90*mm, 22*mm, 68*mm], repeatRows=1)
num_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#1a3c5a")),
    ("TEXTCOLOR", (0,0), (-1,0), WHITE),
    ("ALIGN", (1,0), (1,-1), "CENTER"),
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 5),
    ("RIGHTPADDING", (0,0), (-1,-1), 5),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BLUE]),
    ("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#aaaaaa")),
    ("LINEBELOW", (0,0), (-1,0), 1.5, GOLD),
]))
story.append(num_t)
story.append(Spacer(1, 5*mm))

# ─────────────────────────────────────────────────────────────────────────────
# FOOTER NOTE
# ─────────────────────────────────────────────────────────────────────────────
footer_data = [[Paragraph(
    "<b>Note:</b> BNS (Bharatiya Nyaya Sanhita), BNSS (Bharatiya Nagarik Suraksha Sanhita) and BSA (Bharatiya Sakshya Adhiniyam) came into force on <b>1st July 2024</b>, "
    "replacing IPC 1860, CrPC 1973, and IEA 1872 respectively. Always check the latest notifications as sections may be amended. "
    "Compiled for FMT revision as per PC Ignatius textbook framework.",
    note_style
)]]
footer_t = Table(footer_data, colWidths=[180*mm])
footer_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), LIGHT_YELLOW),
    ("BOX", (0,0), (-1,-1), 0.7, GOLD),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING", (0,0), (-1,-1), 8),
    ("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
story.append(footer_t)

# ─────────────────────────────────────────────────────────────────────────────
# BUILD
# ─────────────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF saved to: {doc_path}")
Running Command

cd /tmp/workspace/fmt-bns-notes && python generate_pdf.py 2>&1

Running Command

ls -lh /tmp/workspace/fmt-bns-notes/BNS_BNSS_FMT_Revision_Notes.pdf

Your PDF is ready! Download it here:

BNS BNSS FMT Revision Notes

PDF Document · PDF


Here's what's inside, organised for maximum retention:
Section 1 - BNS 2023 (replaces IPC) — ~35 sections All FMT-relevant offences: Hurt, Grievous Hurt, Murder, Culpable Homicide, Negligent Death, Dowry Death, Rape (Sec 63–70), Acid Attack, Abortion, Infanticide, Poisoning, Consent sections (20–22), False Certificates
Section 2 - BNSS 2023 (replaces CrPC) — ~20 sections FIR, Police Inquest (Sec 176), Magistrate Inquest (Sec 194), the NEW Sec 176(3) mandating forensic experts at crime scenes, Magistrate's power to order biological samples (Sec 349), Expert report without court appearance (Sec 329), Medical exam of accused (Sec 350), In-camera rape trial (Sec 376)
Section 3 - BSA 2023 (replaces IEA) — ~11 sections Dying Declaration (Sec 26), Expert Witness (Sec 39–40), Electronic evidence (Sec 57), Handwriting comparison (Sec 63), Witness competency (Sec 118)
Section 4 - Topic-wise Cross Reference table Maps every FMT topic (wounds, rape, death, poisoning, negligence, psychiatry etc.) to the right BNS + BNSS + BSA section at a glance
Section 5 - Mnemonics
  • Grievous Hurt: "E-PELL-FBH"
  • Magistrate Inquest: "D-PGA"
  • Dying Declaration: "FACE"
  • IPC → BNS quick conversion pairs
Section 6 - Punishments at a glance table All key penalties (years of imprisonment) mapped by offence
Reminder: BNS, BNSS and BSA came into force on 1st July 2024. All new exams will ask BNS/BNSS sections, not IPC/CrPC - but the old section numbers are kept in the table for cross-reference.

Make note on chelating agents with mneumonics

Reading File
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Running Command

mkdir -p /tmp/workspace/fmt-chelating-notes

Writing File

~/fmt-chelating-notes/generate_chelating_pdf.py

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY

doc_path = "/tmp/workspace/fmt-chelating-notes/Chelating_Agents_FMT_Notes.pdf"

doc = SimpleDocTemplate(
    doc_path,
    pagesize=A4,
    rightMargin=14*mm,
    leftMargin=14*mm,
    topMargin=16*mm,
    bottomMargin=16*mm
)

styles = getSampleStyleSheet()

# Colours
NAVY    = colors.HexColor("#1a2e5a")
TEAL    = colors.HexColor("#0e6b7a")
GOLD    = colors.HexColor("#c8860a")
MAROON  = colors.HexColor("#8b1a1a")
PURPLE  = colors.HexColor("#5c1f7a")
DKGREEN = colors.HexColor("#145a32")
ORANGE  = colors.HexColor("#b35900")
LGRAY   = colors.HexColor("#f5f5f5")
WHITE   = colors.white
DKGRAY  = colors.HexColor("#2d2d2d")

LT_BLUE   = colors.HexColor("#dbeeff")
LT_GREEN  = colors.HexColor("#e6f7f0")
LT_YELLOW = colors.HexColor("#fff8e1")
LT_PINK   = colors.HexColor("#fce4ec")
LT_PURPLE = colors.HexColor("#f3e5f5")
LT_ORANGE = colors.HexColor("#fff3e0")
LT_TEAL   = colors.HexColor("#e0f7fa")

def st(name, base="Normal", **kw):
    s = ParagraphStyle(name, parent=styles[base])
    for k, v in kw.items():
        setattr(s, k, v)
    return s

TITLE_S  = st("TitleS", fontSize=21, textColor=WHITE, alignment=TA_CENTER, fontName="Helvetica-Bold")
SUB_S    = st("SubS",   fontSize=10, textColor=colors.HexColor("#c8e6ff"), alignment=TA_CENTER, fontName="Helvetica")
SEC_S    = st("SecS",   fontSize=13, textColor=WHITE, fontName="Helvetica-Bold", leftIndent=4)
DRUG_S   = st("DrugS",  fontSize=12, textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)
BODY_S   = st("BodyS",  fontSize=9.5, textColor=DKGRAY, fontName="Helvetica", alignment=TA_JUSTIFY, leading=13)
BOLD_S   = st("BoldS",  fontSize=9.5, textColor=NAVY, fontName="Helvetica-Bold", leading=13)
NOTE_S   = st("NoteS",  fontSize=8.5, textColor=colors.HexColor("#555555"), fontName="Helvetica-Oblique", leading=12)
TH_S     = st("ThS",    fontSize=9,   textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)
TC_S     = st("TcS",    fontSize=8.8, textColor=DKGRAY, fontName="Helvetica", leading=12)
TC_C     = st("TcC",    fontSize=8.8, textColor=DKGRAY, fontName="Helvetica", alignment=TA_CENTER, leading=12)
MNEM_T   = st("MnT",    fontSize=10,  textColor=colors.HexColor("#5a2d00"), fontName="Helvetica-Bold")
MNEM_B   = st("MnB",    fontSize=9.2, textColor=DKGRAY, fontName="Courier", leading=14, leftIndent=6)
HL_S     = st("HlS",    fontSize=9,   textColor=MAROON, fontName="Helvetica-Bold", leftIndent=4)

def banner(text, color=NAVY):
    t = Table([[Paragraph(text, SEC_S)]], colWidths=[182*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), color),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("RIGHTPADDING",  (0,0), (-1,-1), 8),
    ]))
    return t

def drug_banner(name, alias, color=TEAL):
    rows = [
        [Paragraph(name, DRUG_S)],
        [Paragraph(alias, st("AlS", fontSize=9, textColor=colors.HexColor("#c8e6ff"), fontName="Helvetica-Oblique", alignment=TA_CENTER))],
    ]
    t = Table(rows, colWidths=[182*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), color),
        ("TOPPADDING",    (0,0), (0,0),   5),
        ("BOTTOMPADDING", (0,-1), (-1,-1), 5),
        ("TOPPADDING",    (0,1), (-1,1),   2),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("RIGHTPADDING",  (0,0), (-1,-1), 8),
    ]))
    return t

def info_table(rows_data, bg_col=LT_BLUE, border_col=TEAL):
    data = []
    for label, val in rows_data:
        data.append([
            Paragraph(f"<b>{label}</b>", TC_S),
            Paragraph(val, TC_S),
        ])
    t = Table(data, colWidths=[42*mm, 140*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (0,-1), bg_col),
        ("BACKGROUND",    (1,0), (1,-1), WHITE),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
        ("BOX",           (0,0), (-1,-1), 0.7, border_col),
        ("INNERGRID",     (0,0), (-1,-1), 0.3, colors.HexColor("#cccccc")),
    ]))
    return t

def mnemonic_box(title, lines):
    data = [
        [Paragraph(title, MNEM_T)],
        [Paragraph("<br/>".join(lines), MNEM_B)],
    ]
    t = Table(data, colWidths=[182*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), LT_ORANGE),
        ("BACKGROUND",    (0,1), (-1,1), colors.HexColor("#fffdf5")),
        ("BOX",           (0,0), (-1,-1), 0.8, ORANGE),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 7),
        ("RIGHTPADDING",  (0,0), (-1,-1), 7),
    ]))
    return t

def warn_box(text, bg=LT_PINK, border=MAROON):
    t = Table([[Paragraph(text, st("WS", fontSize=9, textColor=MAROON, fontName="Helvetica-Bold", leading=13))]], colWidths=[182*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), bg),
        ("BOX",           (0,0), (-1,-1), 1, border),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("RIGHTPADDING",  (0,0), (-1,-1), 8),
    ]))
    return t

def sp(n=3): return Spacer(1, n*mm)

story = []

# ── TITLE ────────────────────────────────────────────────────────────────────
title_rows = [
    [Paragraph("CHELATING AGENTS", TITLE_S)],
    [Paragraph("Forensic Medicine & Toxicology | Revision Notes", SUB_S)],
    [Paragraph("Based on PC Ignatius / PC Dikshit Framework", st("SubS2", fontSize=9, textColor=colors.HexColor("#90caf9"), alignment=TA_CENTER, fontName="Helvetica-Oblique"))],
]
title_t = Table(title_rows, colWidths=[182*mm])
title_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,-1), NAVY),
    ("TOPPADDING",    (0,0), (-1,0),  10),
    ("BOTTOMPADDING", (0,-1), (-1,-1), 10),
    ("LEFTPADDING",   (0,0), (-1,-1), 8),
    ("RIGHTPADDING",  (0,0), (-1,-1), 8),
]))
story.append(title_t)
story.append(sp(4))

# ── DEFINITION BOX ───────────────────────────────────────────────────────────
defn = Table([[Paragraph(
    "<b>Definition:</b> Chelating agents are compounds that form stable, soluble, non-toxic ring structures (chelates) "
    "with metallic ions, rendering them water-soluble and non-ionized so they are excreted in urine without damaging "
    "the liver or kidneys. The word 'Chelate' comes from the Greek <i>chele</i> = claw (the metal is 'gripped').",
    BODY_S)]], colWidths=[182*mm])
defn.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,-1), LT_YELLOW),
    ("BOX",           (0,0), (-1,-1), 1, GOLD),
    ("TOPPADDING",    (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING",   (0,0), (-1,-1), 8),
    ("RIGHTPADDING",  (0,0), (-1,-1), 8),
]))
story.append(defn)
story.append(sp(4))

# ── MASTER TABLE ─────────────────────────────────────────────────────────────
story.append(banner("MASTER QUICK-REFERENCE TABLE — All Chelating Agents at a Glance", NAVY))
story.append(sp(2))

master_hdr = [
    Paragraph("Agent", TH_S),
    Paragraph("Drug / Full Name", TH_S),
    Paragraph("Metals Chelated", TH_S),
    Paragraph("Route", TH_S),
    Paragraph("Key Use / Unique Fact", TH_S),
    Paragraph("Contraindicated In", TH_S),
]
master_rows = [
    ["BAL\n(Dimercaprol)", "British Anti-Lewisite\nDimercaptopropanol", "As, Hg, Pb, Sb, Au, Tl\n(+ Cu, Bi)", "IM only\n(deep, in oil)", "Drug of choice: Arsenic & Mercury\nChloice in impaired renal function\n2 mol BAL : 1 atom metal", "Cadmium (nephrotoxic complex)\nLiver disease"],
    ["CaNa₂EDTA\n(Calcium Disodium Versenate)", "Ethylene Diamine\nTetra-acetic Acid", "Pb (best), Zn, Mn,\nCu, Ni, Cd, Fe", "IV / IM\n(NOT oral)", "Best for inorganic lead\nNOT effective in tetraethyl lead\nGive BAL 4 hrs BEFORE EDTA", "Raised intracranial pressure\n(fluids restricted)"],
    ["Penicillamine\n(Cuprimine / D-Pen)", "β,β-Dimethylcysteine\n(hydrolysis product of penicillin)", "Cu (main), Pb, Hg,\nZn, Fe", "Oral\n(unique advantage)", "Drug of choice: Wilson's disease, Cystinuria\nOnly agent given orally for long term\nGive Pyridoxine 25–50 mg/day with it", "Penicillin allergy\nPregnancy (teratogenic)"],
    ["Deferoxamine\n(Desferrioxamine)", "Deferoxamine mesylate\nDesferal", "Fe³⁺ (ferric ion only)\nAluminium", "Oral / IM / IV\n(all routes)", "Drug of choice: Acute iron poisoning & Haemochromatosis\nDoes NOT chelate Fe from Hb or cytochromes\nUrine turns 'vin rosé' (pink-orange) = positive test", "Not for primary haemochromatosis treatment alone"],
    ["DMSA\n(Succimer)", "Dimercaptosuccinic acid\n2,3-DMSA", "Pb (children), As,\nHg, Cd", "Oral\n(water soluble BAL analogue)", "Drug of choice: Pb poisoning in children\nWater-soluble; less toxic than BAL\nCan cross blood–brain barrier (minor)", "—"],
    ["DMPS", "2,3-Dimercaptopropane-\n1-sulphonate", "Hg (organic + inorganic),\nAs, Pb", "IV / Oral", "Used in mercury poisoning (esp. organic)\nMore water-soluble than BAL", "—"],
    ["Prussian Blue\n(Ferric hexacyanoferrate)", "Ferric ferrocyanide", "Thallium (Tl)\nRadiocesium (¹³⁷Cs)", "Oral", "Ion exchange in gut; prevents reabsorption\nFDA approved for Tl & radiocesium\nBlue stool expected", "—"],
    ["Deferiprone\n(L1)", "1,2-Dimethyl-3-\nhydroxypyrid-4-one", "Fe³⁺ (oral iron chelator)", "Oral", "Used in thalassaemia iron overload\nSecond-line if deferoxamine fails\nSide effect: Agranulocytosis (monitor WBC)", "—"],
    ["Desferasirox\n(Exjade)", "Deferasirox", "Fe³⁺", "Oral\n(once daily)", "Newer oral iron chelator\nUsed in transfusion-related iron overload", "Renal failure (nephrotoxic)"],
    ["Dithiocarb\n(Diethyldithiocarbamate)", "Sodium diethyldithiocarbamate", "Nickel carbonyl (main)", "IV", "Drug of choice: Nickel carbonyl pneumonitis", "—"],
    ["Hydroxocobalamin", "Vitamin B12a", "Cyanide (CN⁻)", "IV", "Drug of choice: Cyanide poisoning\nBinds CN to form cyanocobalamin\nTurns urine red", "—"],
    ["Protamine Sulphate", "Basic protein (from fish sperm)", "Heparin (not a metal)", "IV", "Antidote for heparin overdose\nNot a classical chelator but functionally similar", "—"],
]

master_tdata = [master_hdr]
row_bgs = [WHITE, LT_BLUE]
for i, row in enumerate(master_rows):
    bg = row_bgs[i % 2]
    master_tdata.append([Paragraph(f"<b>{row[0]}</b>", TC_C), Paragraph(row[1], TC_S), Paragraph(f"<b>{row[2]}</b>", TC_S), Paragraph(row[3], TC_C), Paragraph(row[4], TC_S), Paragraph(row[5], TC_S)])

mt = Table(master_tdata, colWidths=[24*mm, 32*mm, 28*mm, 18*mm, 52*mm, 28*mm], repeatRows=1)
mt.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0), NAVY),
    ("TEXTCOLOR",     (0,0), (-1,0), WHITE),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LT_BLUE]),
    ("GRID",          (0,0), (-1,-1), 0.3, colors.HexColor("#aaaaaa")),
    ("LINEBELOW",     (0,0), (-1,0),  1.5, GOLD),
]))
story.append(mt)
story.append(sp(5))

# ─── DRUG PROFILES ───────────────────────────────────────────────────────────
story.append(banner("INDIVIDUAL DRUG PROFILES (Exam Detail)", TEAL))
story.append(sp(3))

# ─ BAL ─
story.append(drug_banner("1. BAL — British Anti-Lewisite (Dimercaprol)", "Dimercaptopropanol | 2,3-Dimercapto-1-propanol", color=TEAL))
story.append(sp(2))
story.append(info_table([
    ("Full name",      "British Anti-Lewisite (BAL) | Dimercaptopropanol"),
    ("Mechanism",      "Heavy metal ions combine with sulphydryl (SH) groups of tissue enzymes, blocking them. "
                       "BAL has 2 thiol (-SH) groups that compete with tissue SH groups, grab the metal ion, "
                       "form a stable chelate ring (2 mol BAL : 1 mol metal) → excreted in urine & bile."),
    ("Metals chelated","Arsenic (DOC), Mercury (DOC), Lead, Antimony, Gold, Thallium, Copper, Bismuth"),
    ("Route / Dose",   "Deep IM (ONLY) in arachis/peanut oil with 20% benzyl benzoate; "
                       "Dose: 3–4 mg/kg body weight; 4-hourly × 2 days, then 3× daily × 10 days"),
    ("Preparation",    "Ampoule: 100 mg/mL — 2 mL of 10% compound in arachis oil"),
    ("Side effects",   "Anorexia / Nausea / Vomiting | Excessive salivation, lachrymation | "
                       "Generalised aches & pains | Hyperthermia | Chest constriction | "
                       "Burning eyes & throat | Fall in BP (appear at >3.5 mg/kg)"),
    ("Contraindicated","Cadmium poisoning (forms nephrotoxic BAL-Cd complex) | Hepatic disease | "
                       "Relatively CI in renal disease"),
    ("Special facts",  "Originally developed as antidote for Lewisite (arsenic war gas) | "
                       "Give BAL at least 4 hours BEFORE EDTA in lead poisoning | "
                       "Chelator of CHOICE when renal function is impaired"),
], LT_TEAL, TEAL))
story.append(sp(4))

# ─ EDTA ─
story.append(drug_banner("2. CaNa₂EDTA — Calcium Disodium Versenate", "Ethylene Diamine Tetra-acetic Acid (Calcium Disodium Edetate)", color=DKGREEN))
story.append(sp(2))
story.append(info_table([
    ("Full name",      "Calcium Disodium EDTA (CaNa₂EDTA) | Calcium Disodium Versenate"),
    ("Mechanism",      "Acts as an ion exchanger: Ca²⁺ is exchanged for heavy metal ion (Pb²⁺). "
                       "Lead displaces calcium, forming stable, soluble, non-ionized Pb-EDTA complex → excreted in urine. "
                       "Chelates extracellular lead in soft tissues AND bones. "
                       "Urinary lead excretion increases ×50 above baseline."),
    ("Metals chelated","Lead (BEST — inorganic only), Zinc, Manganese, Copper, Nickel, Cadmium, Iron"),
    ("NOT effective",  "Tetraethyl lead (organic lead) | Less effective for Manganese, Iron, Cd, radioactive elements | "
                       "INFERIOR to BAL for Arsenic & Mercury"),
    ("Route / Dose",   "IV infusion (NOT oral — oral increases GIT lead absorption!) | "
                       "5 mL of 20% solution in 250–500 mL NS or 5% dextrose-saline; "
                       "concentration must NOT exceed 3%; drip >2 hours; "
                       "50–70 mg/kg/day; 1 g IV twice daily × 5 days; repeat after 3-day gap"),
    ("Side effects",   "Thrombophlebitis (strong solution) | Lower nephron nephrosis | "
                       "Hypersensitivity | Fever, headache, malaise | Lachrymation, nasal congestion | "
                       "Sneezing, muscle pain | Hypotension"),
    ("Contraindicated","Raised intracranial pressure (fluids must be restricted)"),
    ("Special facts",  "NEVER give orally (chelates gut lead → increased absorption) | "
                       "Give BAL 4 hrs BEFORE EDTA in lead poisoning | "
                       "Best chelator for inorganic lead poisoning"),
], LT_GREEN, DKGREEN))
story.append(sp(4))

# ─ Penicillamine ─
story.append(drug_banner("3. Penicillamine (Cuprimine / D-Pen)", "β,β-Dimethylcysteine — Hydrolysis Product of Penicillin", color=PURPLE))
story.append(sp(2))
story.append(info_table([
    ("Full name",      "D-Penicillamine | Cuprimine | β,β-Dimethylcysteine"),
    ("Mechanism",      "Contains stable SH (thiol) groups (product of penicillin hydrolysis). "
                       "SH groups chelate heavy metals. Can be given orally and continuously without major toxicity."),
    ("Metals chelated","Copper (PRIMARY — DOC for Wilson's disease), Lead, Mercury, Zinc, Iron"),
    ("Indications",    "Wilson's disease (hepatolenticular degeneration — copper metabolism disorder) | "
                       "Cystinuria | Lead, Cu, Hg, Zn poisoning | Rheumatoid arthritis (DMARDs use)"),
    ("Route / Dose",   "ORAL (unique advantage over BAL, EDTA) | "
                       "0.5 g orally 30 min before meals × 4 times/day × 8–10 days | "
                       "Also IM: 30 mg/kg body weight"),
    ("Side effects",   "Hypersensitivity: skin rashes, nephrotoxicity | "
                       "Optic neuritis (due to pyridoxine deficiency — give Pyridoxine 25–50 mg/day) | "
                       "Leucopenia, Thrombocytopenia, Agranulocytosis"),
    ("Contraindicated","Penicillin allergy | Pregnancy (teratogenic) | Systemic lupus"),
    ("Special facts",  "Only oral chelating agent for LONG-TERM use | "
                       "Always supplement Pyridoxine (Vit B6) 25–50 mg/day | "
                       "DOC for Wilson's disease and Cystinuria | "
                       "Commercial preparation: controlled decomposition of penicillin"),
], LT_PURPLE, PURPLE))
story.append(sp(4))

# ─ Deferoxamine ─
story.append(drug_banner("4. Deferoxamine (Desferrioxamine / Desferal)", "Siderophore — Specific Ferric (Fe³⁺) Chelator", color=MAROON))
story.append(sp(2))
story.append(info_table([
    ("Full name",      "Desferrioxamine mesylate | Deferoxamine | Desferal"),
    ("Mechanism",      "Water-soluble compound with great affinity for ferric ion (Fe³⁺). "
                       "Removes iron from ferritin and hemosiderin. "
                       "Does NOT chelate iron from haemoglobin or cytochromes (selective). "
                       "Forms ferrioxamine complex → excreted in urine."),
    ("Metals chelated","Iron (Fe³⁺) — PRIMARY; also Aluminium"),
    ("Indications",    "DOC: Acute iron poisoning | Haemochromatosis (iron overload) | "
                       "Thalassaemia (iron overload from transfusions — with deferiprone)"),
    ("Route / Dose",   "Oral: 8–10 g in 80–100 mL distilled water | "
                       "IM: 1 g initially → 0.5 g 2–3× daily | "
                       "IV: 1–2 g in 500 mL 5% dextrose saline; NOT more than 15 mg/kg/hr or 80 mg/kg/24 hr"),
    ("Key test",       "Urine turns PINK-ORANGE ('Vin rosé' colour) after deferoxamine → confirms iron poisoning"),
    ("Side effects",   "Hypotension (rapid IV) | Allergic reactions | Neurotoxicity (long-term) | "
                       "Growth retardation in children | Yersinia enterocolitica infection risk"),
    ("Special facts",  "Does NOT remove iron from Hb or cytochromes | "
                       "Vin rosé urine = diagnostic AND therapeutic confirmation | "
                       "Also used in intracerebral haemorrhage research (removes haematoma iron)"),
], LT_PINK, MAROON))
story.append(sp(4))

# ─ DMSA ─
story.append(drug_banner("5. DMSA — Succimer (Dimercaptosuccinic Acid)", "Oral BAL Analogue — Drug of Choice for Paediatric Lead Poisoning", color=ORANGE))
story.append(sp(2))
story.append(info_table([
    ("Full name",      "2,3-Dimercaptosuccinic acid (DMSA) | Succimer | Chemet"),
    ("Mechanism",      "Water-soluble analogue of BAL with 2 thiol (SH) groups. "
                       "Can be given orally (unlike BAL). Less toxic. "
                       "Chelates lead intracellularly and extracellularly."),
    ("Metals chelated","Lead (PRIMARY — children's DOC), Arsenic, Mercury, Cadmium"),
    ("Route / Dose",   "ORAL: 10 mg/kg every 8 hrs × 5 days, then every 12 hrs × 14 days"),
    ("Side effects",   "GI upset | Skin rash | Transaminase elevation | Sulphurous odour (from thiol groups)"),
    ("Special facts",  "DOC for lead poisoning in CHILDREN | "
                       "More water-soluble and less toxic than BAL | "
                       "Can penetrate CNS (minor) | "
                       "First oral chelator approved for paediatric lead poisoning (FDA)"),
], LT_ORANGE, ORANGE))
story.append(sp(5))

# ── MNEMONICS ────────────────────────────────────────────────────────────────
story.append(banner("MNEMONICS & MEMORY AIDS", color=colors.HexColor("#b35900")))
story.append(sp(3))

mnemonics = [
    (
        "🔑 METALS CHELATED BY BAL — Mnemonic: 'A MAGIC Compound'",
        [
            "A  = Arsenic (DOC)",
            "M  = Mercury (DOC)",
            "A  = Antimony",
            "G  = Gold",
            "I  = [lead] Intracellular chelation",
            "C  = Copper / Cobalt / Cadmium (CI — nephrotoxic!)",
            "   → Also: Thallium, Bismuth",
        ]
    ),
    (
        "🔑 DOC (Drug of Choice) for each metal — Mnemonic: 'BAIL PEDF'",
        [
            "B  = BAL        → Arsenic, Mercury (also Lead in renal impairment)",
            "A  = —",
            "I  = —",
            "L  = Lead       → CaNa₂EDTA (inorganic Pb); DMSA (children)",
            "   ─────────────────────────────────────",
            "P  = Penicillamine → Copper (Wilson's disease), Cystinuria",
            "E  = EDTA       → Inorganic Lead (adults)",
            "D  = Deferoxamine → Iron",
            "F  = DMSA (Fine for children) → Paediatric Lead",
        ]
    ),
    (
        "🔑 PENICILLAMINE side effects — Mnemonic: 'HOL-P'",
        [
            "H  = Hypersensitivity (rash, nephropathy)",
            "O  = Optic neuritis (pyridoxine deficiency → give Vit B6!)",
            "L  = Leucopenia / thrombocytopenia / agranulocytosis",
            "P  = Pyridoxine deficiency (always supplement B6 25–50 mg/day)",
        ]
    ),
    (
        "🔑 DEFEROXAMINE — Key facts to remember: 'VIN ROSE'",
        [
            "V  = Vin rosé urine (pink-orange) = positive test for iron poisoning",
            "I  = Iron (Fe³⁺) only — ferric iron",
            "N  = NOT Hb, NOT cytochromes (spared)",
            "R  = Removes iron from ferritin, hemosiderin",
            "O  = Oral / IM / IV (all routes)",
            "S  = Selective ferric ion chelator",
            "E  = Emergency use in acute iron poisoning",
        ]
    ),
    (
        "🔑 BAL CONTRAINDICATIONS — Mnemonic: 'BAL CAN'T do Cadmium'",
        [
            "Cadmium  → BAL + Cd = nephrotoxic complex (ABSOLUTELY CI)",
            "Hepatic disease → absolutely contraindicated",
            "Kidney disease  → relatively contraindicated",
            "Also: BAL must be given 4 hrs BEFORE EDTA in lead poisoning",
        ]
    ),
    (
        "🔑 EDTA — 'Never give EDTA by mouth' (Oral EDTA increases Pb absorption from GIT!)",
        [
            "E  = Exchange — Ca for Pb (ion exchanger mechanism)",
            "D  = Drip (IV, slow, >2 hrs; concentration <3%)",
            "T  = Twice daily × 5 days, then 3-day gap, repeat",
            "A  = Always give BAL 4 hrs BEFORE EDTA",
            "EXTRA: Urinary Pb excretion ×50 above baseline after EDTA",
        ]
    ),
    (
        "🔑 COMPARISON TABLE: BAL vs EDTA vs Penicillamine — Quick Recall",
        [
            "Feature         | BAL            | EDTA            | Penicillamine",
            "─────────────────────────────────────────────────────────────────────",
            "Route           | IM only         | IV / IM         | ORAL (only oral)",
            "Metal (DOC)     | As, Hg          | Pb (inorganic)  | Cu (Wilson's)",
            "Mechanism       | Thiol (SH) grp  | Ion exchange    | Thiol (SH) grp",
            "CI              | Cadmium, Liver  | Raised ICP      | PCN allergy, Preg",
            "Give with       | Nothing special | BAL 4 hr before | Pyridoxine (B6)",
            "Solvent         | Arachis oil     | Saline/Dextrose | —",
        ]
    ),
    (
        "🔑 Urine Colour Clues in Chelation Therapy",
        [
            "Pink-Orange (Vin rosé) → Deferoxamine given for iron poisoning",
            "Blue stool              → Prussian Blue given for Thallium / Radiocesium",
            "Red urine               → Hydroxocobalamin given for Cyanide poisoning",
        ]
    ),
]

for title, lines in mnemonics:
    story.append(mnemonic_box(title, lines))
    story.append(sp(2.5))

story.append(sp(3))

# ── HIGH-YIELD EXAM POINTS ────────────────────────────────────────────────────
story.append(banner("HIGH-YIELD EXAM POINTS (Must Know)", MAROON))
story.append(sp(2))

exam_data = [
    [Paragraph("<b>Question / Scenario</b>", TH_S), Paragraph("<b>Answer</b>", TH_S)],
    [Paragraph("DOC for arsenic poisoning", TC_S), Paragraph("<b>BAL (Dimercaprol)</b>", TC_S)],
    [Paragraph("DOC for mercury poisoning", TC_S), Paragraph("<b>BAL</b> (DMPS for organic mercury)", TC_S)],
    [Paragraph("DOC for inorganic lead in adults", TC_S), Paragraph("<b>CaNa₂EDTA</b> (give BAL 4 hrs before)", TC_S)],
    [Paragraph("DOC for lead poisoning in children", TC_S), Paragraph("<b>DMSA (Succimer)</b> — oral", TC_S)],
    [Paragraph("DOC for copper poisoning / Wilson's disease", TC_S), Paragraph("<b>Penicillamine</b> (oral)", TC_S)],
    [Paragraph("DOC for acute iron poisoning", TC_S), Paragraph("<b>Deferoxamine</b> (Desferrioxamine)", TC_S)],
    [Paragraph("DOC for thallium poisoning", TC_S), Paragraph("<b>Prussian Blue</b> (Ferric hexacyanoferrate)", TC_S)],
    [Paragraph("DOC for nickel carbonyl poisoning", TC_S), Paragraph("<b>Dithiocarb (Diethyldithiocarbamate)</b>", TC_S)],
    [Paragraph("DOC for cyanide poisoning", TC_S), Paragraph("<b>Hydroxocobalamin</b> (IV) ± Sodium thiosulphate", TC_S)],
    [Paragraph("Only chelator given ORALLY long-term", TC_S), Paragraph("<b>Penicillamine</b>", TC_S)],
    [Paragraph("BAL absolutely contraindicated in which metal?", TC_S), Paragraph("<b>Cadmium</b> (forms nephrotoxic complex)", TC_S)],
    [Paragraph("Why NOT give EDTA orally?", TC_S), Paragraph("Chelates gut lead → <b>INCREASES absorption</b> from GIT", TC_S)],
    [Paragraph("Order of giving BAL + EDTA in lead poisoning", TC_S), Paragraph("<b>BAL first (4 hrs before EDTA)</b> — BAL mobilizes intracellular Pb, then EDTA mops up", TC_S)],
    [Paragraph("Vin rosé (pink-orange) urine after chelation", TC_S), Paragraph("<b>Deferoxamine</b> — confirms iron poisoning / therapy working", TC_S)],
    [Paragraph("Vitamin to give with Penicillamine", TC_S), Paragraph("<b>Pyridoxine (Vit B6)</b> 25–50 mg/day", TC_S)],
    [Paragraph("Penicillamine source / origin", TC_S), Paragraph("<b>Hydrolysis of Penicillin</b> (controlled decomposition)", TC_S)],
    [Paragraph("EDTA mechanism in brief", TC_S), Paragraph("Ion exchange: Ca²⁺ displaced by Pb²⁺ → Pb-EDTA complex excreted in urine; urinary Pb ×50 baseline", TC_S)],
    [Paragraph("Which chelator works in impaired renal function?", TC_S), Paragraph("<b>BAL</b> — excreted via bile (not dependent on renal excretion)", TC_S)],
    [Paragraph("Deferoxamine does NOT chelate iron from?", TC_S), Paragraph("<b>Haemoglobin and Cytochromes</b>", TC_S)],
]

exam_t = Table(exam_data, colWidths=[82*mm, 100*mm], repeatRows=1)
exam_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0), MAROON),
    ("TEXTCOLOR",     (0,0), (-1,0), WHITE),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("RIGHTPADDING",  (0,0), (-1,-1), 5),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, LT_PINK]),
    ("GRID",          (0,0), (-1,-1), 0.3, colors.HexColor("#aaaaaa")),
    ("LINEBELOW",     (0,0), (-1,0),  1.5, GOLD),
]))
story.append(exam_t)
story.append(sp(4))

# ── FOOTER ────────────────────────────────────────────────────────────────────
foot = Table([[Paragraph(
    "<b>Sources:</b> PC Dikshit Textbook of Forensic Medicine & Toxicology | "
    "Katzung's Basic & Clinical Pharmacology 16e | Compiled for FMT exam revision. "
    "All dose information is for academic reference — always verify with current clinical guidelines.",
    NOTE_S)]], colWidths=[182*mm])
foot.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,-1), LT_YELLOW),
    ("BOX",           (0,0), (-1,-1), 0.7, GOLD),
    ("TOPPADDING",    (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING",   (0,0), (-1,-1), 8),
    ("RIGHTPADDING",  (0,0), (-1,-1), 8),
]))
story.append(foot)

doc.build(story)
print(f"PDF created: {doc_path}")
Running Command

cd /tmp/workspace/fmt-chelating-notes && python generate_chelating_pdf.py 2>&1

Running Command

ls -lh /tmp/workspace/fmt-chelating-notes/Chelating_Agents_FMT_Notes.pdf

Your PDF is ready! Download here:

Chelating Agents FMT Notes

PDF Document · PDF


Here's what the note covers, in order:

Definition - What chelation means (claw-like ring structure, renders metals water-soluble for urinary excretion)

Master Quick-Reference Table (all agents at one glance)
AgentMetalsRouteCI
BALAs, Hg, Pb, Sb, Au, TlIM only (oil)Cadmium, Liver disease
CaNa₂EDTAPb (best), Zn, Mn, CuIV/IM (NOT oral)Raised ICP
PenicillamineCu, Pb, Hg, ZnORALPCN allergy, Pregnancy
DeferoxamineFe³⁺ onlyOral/IM/IV
DMSA (Succimer)Pb (children), As, HgOral
Prussian BlueThallium, RadiocesiumOral
Deferirpone / DeferasiroxFe³⁺OralAgranulocytosis risk
HydroxocobalaminCyanideIV

Individual Drug Profiles (BAL, EDTA, Penicillamine, Deferoxamine, DMSA) - each with mechanism, dose, side effects, contraindications

8 Mnemonics:
  • BAL metals: "A MAGIC Compound" (Arsenic, Mercury, Antimony, Gold, Intracellular lead, Copper/Cadmium-CI)
  • DOC for each metal: "BAIL PEDF"
  • Penicillamine side effects: "HOL-P"
  • Deferoxamine recall: "VIN ROSE"
  • BAL CI: "BAL CAN'T do Cadmium"
  • EDTA: "EDTA never by mouth"
  • Urine colour clues (vin rosé = iron; blue stool = thallium; red = cyanide)
  • BAL vs EDTA vs Penicillamine comparison table

20-row High-Yield Exam Q&A table - DOC for each metal, order of BAL+EDTA, why not oral EDTA, vin rosé urine, pyridoxine with penicillamine, and more
This is a shared conversation. Sign in to Orris to start your own chat.