~/cmd-pharmacology/generate_pdf.py
#!/usr/bin/env python3
"""
CMD Pharmacology Study Guide PDF Generator
Topic: Non-Clinical Pharmacology & Analytical Biochemical Assay
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.lib import colors
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate
# ─── Color Palette ─────────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1A3A5C")
MID_BLUE = colors.HexColor("#2E6DA4")
LIGHT_BLUE = colors.HexColor("#D6E8F7")
ACCENT_TEAL = colors.HexColor("#0E7C7B")
ACCENT_GREEN = colors.HexColor("#2E8B57")
GOLD = colors.HexColor("#C8860A")
LIGHT_GOLD = colors.HexColor("#FFF3CD")
LIGHT_GRAY = colors.HexColor("#F4F6F8")
DARK_GRAY = colors.HexColor("#2C2C2C")
MED_GRAY = colors.HexColor("#555555")
RED_ACCENT = colors.HexColor("#C0392B")
PAGE_W, PAGE_H = A4
# ─── Styles ────────────────────────────────────────────────────────────────────
def make_styles():
base = getSampleStyleSheet()
styles = {
# Cover
"cover_title": ParagraphStyle("cover_title",
fontSize=28, textColor=colors.white, alignment=TA_CENTER,
fontName="Helvetica-Bold", leading=34, spaceAfter=6),
"cover_sub": ParagraphStyle("cover_sub",
fontSize=15, textColor=colors.HexColor("#BFD7F0"), alignment=TA_CENTER,
fontName="Helvetica", leading=20, spaceAfter=4),
"cover_meta": ParagraphStyle("cover_meta",
fontSize=11, textColor=colors.HexColor("#90C3E8"), alignment=TA_CENTER,
fontName="Helvetica", leading=16),
# Section / Question headers
"q_header": ParagraphStyle("q_header",
fontSize=14, textColor=colors.white, fontName="Helvetica-Bold",
leading=18, spaceBefore=14, spaceAfter=4,
leftIndent=0, rightIndent=0),
"sub_header": ParagraphStyle("sub_header",
fontSize=12, textColor=DARK_BLUE, fontName="Helvetica-Bold",
leading=16, spaceBefore=10, spaceAfter=3),
"sub_header2": ParagraphStyle("sub_header2",
fontSize=11, textColor=ACCENT_TEAL, fontName="Helvetica-Bold",
leading=15, spaceBefore=7, spaceAfter=2),
"sub_header3": ParagraphStyle("sub_header3",
fontSize=10.5, textColor=GOLD, fontName="Helvetica-Bold",
leading=14, spaceBefore=5, spaceAfter=1),
# Body
"body": ParagraphStyle("body",
fontSize=9.5, textColor=DARK_GRAY, fontName="Helvetica",
leading=14, spaceBefore=2, spaceAfter=2, alignment=TA_JUSTIFY),
"bullet": ParagraphStyle("bullet",
fontSize=9.5, textColor=DARK_GRAY, fontName="Helvetica",
leading=13, spaceBefore=1, spaceAfter=1,
leftIndent=14, bulletIndent=4),
"bullet2": ParagraphStyle("bullet2",
fontSize=9, textColor=MED_GRAY, fontName="Helvetica",
leading=12, spaceBefore=0, spaceAfter=0,
leftIndent=28, bulletIndent=16),
"note": ParagraphStyle("note",
fontSize=9, textColor=colors.HexColor("#5A3E00"),
fontName="Helvetica-Oblique", leading=13,
leftIndent=10, spaceBefore=3, spaceAfter=3,
backColor=LIGHT_GOLD, borderPad=4),
"formula": ParagraphStyle("formula",
fontSize=9.5, textColor=DARK_BLUE, fontName="Helvetica-Bold",
leading=14, leftIndent=20, spaceBefore=3, spaceAfter=3,
backColor=LIGHT_BLUE, borderPad=5),
"toc_item": ParagraphStyle("toc_item",
fontSize=10, textColor=DARK_BLUE, fontName="Helvetica",
leading=15, leftIndent=10),
"footer_style": ParagraphStyle("footer_style",
fontSize=8, textColor=colors.HexColor("#888888"),
fontName="Helvetica", alignment=TA_CENTER),
}
return styles
S = make_styles()
# ─── Helper Builders ──────────────────────────────────────────────────────────
def q_banner(text, color=MID_BLUE):
"""Colored banner for question headings."""
tbl = Table([[Paragraph(text, S["q_header"])]], colWidths=[17*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("ROUNDEDCORNERS", [4, 4, 4, 4]),
]))
return tbl
def info_box(text, bg=LIGHT_BLUE, border=MID_BLUE):
style = ParagraphStyle("ib", parent=S["body"], backColor=bg,
leftIndent=8, rightIndent=8, spaceBefore=4, spaceAfter=4)
tbl = Table([[Paragraph(text, style)]], colWidths=[17*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 1.5, border),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
]))
return tbl
def make_table(headers, rows, col_widths=None):
data = [headers] + rows
if col_widths is None:
col_widths = [17*cm / len(headers)] * len(headers)
tbl = Table(data, colWidths=col_widths)
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), DARK_BLUE),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,0), 9),
("FONTNAME", (0,1), (-1,-1), "Helvetica"),
("FONTSIZE", (0,1), (-1,-1), 8.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, LIGHT_GRAY]),
("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
("ALIGN", (0,0), (-1,-1), "LEFT"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
]))
return tbl
def hr(color=MID_BLUE):
return HRFlowable(width="100%", thickness=1, color=color, spaceAfter=4, spaceBefore=4)
def sp(h=6):
return Spacer(1, h)
def p(text, style="body"):
return Paragraph(text, S[style])
def b(text):
return Paragraph(f"• {text}", S["bullet"])
def b2(text):
return Paragraph(f"◦ {text}", S["bullet2"])
# ─── Page decorations ─────────────────────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
# Top bar
canvas.setFillColor(DARK_BLUE)
canvas.rect(0, PAGE_H - 18*mm, PAGE_W, 18*mm, fill=1, stroke=0)
canvas.setFillColor(colors.white)
canvas.setFont("Helvetica-Bold", 9)
canvas.drawString(1.5*cm, PAGE_H - 11*mm, "CMD Pharmacology Study Guide")
canvas.setFont("Helvetica", 8)
canvas.drawRightString(PAGE_W - 1.5*cm, PAGE_H - 11*mm,
"Non-Clinical Pharmacology & Analytical Biochemical Assay")
# Bottom bar
canvas.setFillColor(DARK_BLUE)
canvas.rect(0, 0, PAGE_W, 10*mm, fill=1, stroke=0)
canvas.setFillColor(colors.white)
canvas.setFont("Helvetica", 8)
canvas.drawCentredString(PAGE_W/2, 3.5*mm, f"Page {doc.page}")
canvas.setFont("Helvetica-Oblique", 7.5)
canvas.drawString(1.5*cm, 3.5*mm, "Date: 10.07.26 | MM: 60 | Time: 2.30 Hrs")
canvas.restoreState()
def on_cover(canvas, doc):
canvas.saveState()
# Full background gradient simulation via two rects
canvas.setFillColor(DARK_BLUE)
canvas.rect(0, 0, PAGE_W, PAGE_H, fill=1, stroke=0)
canvas.setFillColor(MID_BLUE)
canvas.rect(0, PAGE_H*0.35, PAGE_W, PAGE_H*0.65, fill=1, stroke=0)
# Decorative bottom strip
canvas.setFillColor(GOLD)
canvas.rect(0, 0, PAGE_W, 8*mm, fill=1, stroke=0)
# Side accent
canvas.setFillColor(ACCENT_TEAL)
canvas.rect(0, 0, 8*mm, PAGE_H, fill=1, stroke=0)
canvas.restoreState()
# ─── Cover Page ───────────────────────────────────────────────────────────────
def cover_page():
elems = []
elems.append(sp(90))
elems.append(p("CMD PHARMACOLOGY", "cover_title"))
elems.append(p("COMPREHENSIVE STUDY GUIDE", "cover_sub"))
elems.append(sp(8))
elems.append(HRFlowable(width="60%", thickness=2, color=GOLD,
spaceAfter=10, spaceBefore=4, hAlign="CENTER"))
elems.append(p("Non-Clinical Pharmacology &<br/>Analytical Biochemical Assay", "cover_sub"))
elems.append(sp(30))
elems.append(p("Test Date: 10.07.2026 | Time: 2½ Hours | Max Marks: 60",
"cover_meta"))
elems.append(sp(10))
elems.append(p("6 Questions · 12 Sub-parts · Each carrying 5 Marks", "cover_meta"))
elems.append(sp(50))
elems.append(HRFlowable(width="40%", thickness=1, color=colors.HexColor("#90C3E8"),
spaceAfter=8, spaceBefore=4, hAlign="CENTER"))
elems.append(p("Prepared by Orris AI Study Assistant", "cover_meta"))
return elems
# ─── Table of Contents ────────────────────────────────────────────────────────
def toc_page():
elems = []
elems.append(sp(10))
elems.append(p("<b>TABLE OF CONTENTS</b>",
ParagraphStyle("toch", parent=S["sub_header"],
fontSize=16, textColor=DARK_BLUE, alignment=TA_CENTER)))
elems.append(hr())
elems.append(sp(6))
toc = [
("Q1(a)", "In Silico, In Vitro & In Vivo Studies with Examples"),
("Q1(b)", "First Dose Estimation in Humans"),
("Q2(a)", "Carcinogenicity Studies & Genotoxicity Studies"),
("Q2(b)", "Transgenic Animals in Experimental Research"),
("Q3(a)", "Short Note on OECD"),
("Q3(b)", "Handling & Care of Lab Animals – CPCSEA Guidelines"),
("Q4(a)", "Validation of Animal Models"),
("Q4(b)", "Euthanasia in Animals in Experimental Studies"),
("Q5(a)", "High Performance Liquid Chromatography (HPLC)"),
("Q5(b)", "Limitations of Animal Testing"),
("Q6(a)", "Langendorff Apparatus & Its Applications"),
("Q6(b)", "Principle of PCR & Its Applications"),
]
colors_cycle = [LIGHT_BLUE, LIGHT_GRAY]
toc_data = []
for i, (qno, qtitle) in enumerate(toc):
bg = colors_cycle[i % 2]
toc_data.append([
Paragraph(f"<b>{qno}</b>", ParagraphStyle("tcq", parent=S["body"],
textColor=DARK_BLUE, fontName="Helvetica-Bold", fontSize=10)),
Paragraph(qtitle, ParagraphStyle("tct", parent=S["body"], fontSize=10))
])
tbl = Table(toc_data, colWidths=[2.5*cm, 14.5*cm])
tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), colors_cycle),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LINEBELOW", (0,0), (-1,-1), 0.3, colors.HexColor("#CCCCCC")),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
elems.append(tbl)
return elems
# ─── Q1(a): In Silico / In Vitro / In Vivo ────────────────────────────────────
def q1a():
e = []
e.append(q_banner("Q1(a) — In Silico, In Vitro & In Vivo Studies with Examples", DARK_BLUE))
e.append(sp(6))
# In Silico
e.append(p("1. IN SILICO STUDIES", "sub_header"))
e.append(info_box("<b>Definition:</b> Studies conducted entirely on computers using mathematical models, "
"algorithms, and simulations. 'In silico' = 'in silicon (computer chip).'"))
e.append(sp(3))
e.append(p("Key Methods:", "sub_header2"))
for item in [
"<b>Molecular Docking</b> – Predicts how a drug fits into a receptor's binding site",
"<b>QSAR</b> (Quantitative Structure–Activity Relationship) – Predicts activity from chemical structure",
"<b>Virtual Screening</b> – Computational scanning of compound libraries against a drug target",
"<b>ADME/Tox Modeling</b> – Predicts absorption, distribution, metabolism, excretion & toxicity",
"<b>PBPK Modeling</b> – Physiologically-based pharmacokinetic prediction in humans",
]:
e.append(b(item))
e.append(sp(3))
e.append(p("<b>Examples:</b> Designing HIV protease inhibitors | Virtual screening of COVID-19 "
"main protease inhibitors | Lemborexant (dual orexin receptor antagonist) characterized "
"in silico before in vitro/in vivo studies", "note"))
e.append(sp(6))
# In Vitro
e.append(p("2. IN VITRO STUDIES", "sub_header"))
e.append(info_box("<b>Definition:</b> Experiments performed outside a living organism in a controlled "
"environment (test tube, culture dish). 'In vitro' = 'in glass.'"))
e.append(p("Key Methods:", "sub_header2"))
for item in [
"<b>Cell Culture</b> – MCF-7 (breast cancer), HeLa cells, primary hepatocytes",
"<b>Ames Test</b> – Bacterial reverse mutation (Salmonella typhimurium) for mutagenicity",
"<b>Enzyme Assays</b> – IC50, Ki determination for enzyme inhibition",
"<b>Receptor Binding Assays</b> – Radioligand binding (Kd, Bmax)",
"<b>MTT Assay</b> – Cell viability / cytotoxicity",
"<b>Microsomal Incubation</b> – Metabolic stability using liver microsomes",
]:
e.append(b(item))
e.append(p("<b>Examples:</b> MIC testing of antimicrobials | Ames test showing isoflurane/desflurane "
"are not mutagenic | Cytotoxicity of anticancer drugs on cancer cell lines", "note"))
e.append(sp(6))
# In Vivo
e.append(p("3. IN VIVO STUDIES", "sub_header"))
e.append(info_box("<b>Definition:</b> Studies in intact living organisms (animals or humans). "
"'In vivo' = 'within the living.' Represents physiologically complete systems."))
e.append(p("Key Methods:", "sub_header2"))
for item in [
"<b>Acute Toxicity</b> – Single dose, LD50 in rodents",
"<b>Subacute / Subchronic</b> – 28–90 days repeated dosing",
"<b>Chronic Toxicity</b> – 6 months to 2 years",
"<b>Efficacy Models</b> – Carrageenan paw edema (anti-inflammatory), STZ-diabetic rats",
"<b>Pharmacokinetic Studies</b> – Blood sampling, bioavailability measurement",
]:
e.append(b(item))
e.append(p("<b>Examples:</b> Carrageenan paw edema (anti-inflammatory) | Forced swim test "
"(antidepressants) | Pentylenetetrazol-induced seizures (anticonvulsants)", "note"))
e.append(sp(6))
# Comparison table
e.append(p("Comparison Table", "sub_header2"))
headers = [p("<b>Parameter</b>"), p("<b>In Silico</b>"), p("<b>In Vitro</b>"), p("<b>In Vivo</b>")]
rows = [
[p("System"), p("Computer model"), p("Cells/tissues/enzymes"), p("Whole organism")],
[p("Cost"), p("Lowest"), p("Moderate"), p("Highest")],
[p("Ethics"), p("No concern"), p("Minimal"), p("Major concern")],
[p("Relevance"), p("Lowest"), p("Moderate"), p("Highest")],
[p("Speed"), p("Fastest"), p("Moderate"), p("Slowest")],
[p("Regulation"), p("Not required"), p("ICH S7A/B"), p("ICH S1-S6")],
]
e.append(make_table(headers, rows, [3.5*cm, 4.5*cm, 4.5*cm, 4.5*cm]))
return e
# ─── Q1(b): First Dose Estimation ─────────────────────────────────────────────
def q1b():
e = []
e.append(q_banner("Q1(b) — First Dose Estimation in Humans (MRSD)", ACCENT_TEAL))
e.append(sp(6))
e.append(p("<b>Definition:</b> The Maximum Recommended Starting Dose (MRSD) is the safest initial dose "
"for Phase I clinical trials, calculated from preclinical animal toxicity data. "
"Governed by <b>FDA Guidance (2005)</b> and <b>ICH M3(R2)</b>.", "body"))
e.append(sp(4))
e.append(p("Key Preclinical Parameters", "sub_header"))
for item in [
"<b>NOAEL</b> (No Observed Adverse Effect Level) – Highest dose with no statistically significant adverse effects",
"<b>LOAEL</b> (Lowest Observed Adverse Effect Level) – Lowest dose causing significant toxicity",
"<b>MTD</b> (Maximum Tolerated Dose) – Used for carcinogenicity high-dose selection",
]:
e.append(b(item))
e.append(sp(4))
e.append(p("Step-by-Step MRSD Calculation (FDA Method)", "sub_header"))
steps = [
("Step 1", "Determine NOAEL from the most sensitive animal species across all preclinical studies"),
("Step 2", "Convert animal NOAEL to Human Equivalent Dose (HED) using Body Surface Area normalization"),
("Step 3", "Divide HED by safety factor (minimum 10) to get MRSD"),
("Step 4", "Select the lowest MRSD obtained from all species tested"),
]
for step, desc in steps:
e.append(b(f"<b>{step}:</b> {desc}"))
e.append(sp(4))
e.append(p("HED Conversion Formula:", "sub_header2"))
e.append(p("HED (mg/kg) = Animal NOAEL (mg/kg) × [Animal Km ÷ Human Km]", "formula"))
e.append(sp(3))
e.append(p("Km Factors by Species:", "sub_header2"))
headers = [p("<b>Species</b>"), p("<b>Km Factor</b>"), p("<b>Example NOAEL (mg/kg)</b>"), p("<b>HED (mg/kg)</b>")]
rows = [
[p("Mouse"), p("3"), p("100"), p("100 × 3/37 = 8.1")],
[p("Rat"), p("6"), p("50"), p("50 × 6/37 = 8.1")],
[p("Rabbit"), p("12"), p("25"), p("25 × 12/37 = 8.1")],
[p("Dog"), p("20"), p("15"), p("15 × 20/37 = 8.1")],
[p("<b>Human</b>"), p("<b>37</b>"), p("—"), p("Reference")],
]
e.append(make_table(headers, rows, [3.5*cm, 3.5*cm, 5*cm, 5*cm]))
e.append(sp(4))
e.append(p("MRSD = HED ÷ Safety Factor (≥10)", "formula"))
e.append(p("Reference Dose (RfD) = NOAEL ÷ 100 [10× interspecies + 10× interindividual variability]",
"formula"))
e.append(sp(4))
e.append(p("Special Method – MABEL (Minimal Anticipated Biological Effect Level)", "sub_header2"))
e.append(p("Used for high-risk immunomodulatory biologics (e.g., monoclonal antibodies). "
"More conservative than NOAEL-based approach. Based on receptor occupancy and "
"pharmacodynamic data. Required after the TGN1412 tragedy (2006).", "body"))
return e
# ─── Q2(a): Carcinogenicity & Genotoxicity ────────────────────────────────────
def q2a():
e = []
e.append(q_banner("Q2(a) — Carcinogenicity Studies & Genotoxicity Studies", MID_BLUE))
e.append(sp(6))
e.append(p("PART A: CARCINOGENICITY STUDIES", "sub_header"))
e.append(p("<b>Definition:</b> Studies designed to determine whether a compound can cause cancer "
"(malignant tumors) in animals with long-term exposure. Governed by <b>ICH S1A/S1B</b>.", "body"))
e.append(p("Study Design (ICH S1B):", "sub_header2"))
for item in [
"<b>Species:</b> Two rodent species – rat (24 months) and mouse (18–24 months)",
"<b>Dose Groups:</b> High (MTD), Mid, Low dose + Control",
"<b>High Dose:</b> Must not reduce lifespan (except by tumors), ≤10% body weight loss",
"<b>Endpoints:</b> Tumor incidence, multiplicity, latency period, histopathology of all organs",
]:
e.append(b(item))
e.append(p("Types of Carcinogenicity Models:", "sub_header2"))
headers = [p("<b>Model</b>"), p("<b>Duration</b>"), p("<b>Advantage</b>")]
rows = [
[p("Long-term rodent bioassay"), p("24 months (rat)"), p("Gold standard")],
[p("Trp53+/- (p53 knockout) mouse"), p("6 months"), p("Tumor suppressor deleted – faster")],
[p("rasH2 transgenic mouse"), p("6 months"), p("Activated Ha-ras – responds to carcinogens faster")],
[p("Neonatal mouse assay"), p("Variable"), p("Detects genotoxic carcinogens in neonates")],
]
e.append(make_table(headers, rows, [5*cm, 3*cm, 9*cm]))
e.append(sp(8))
e.append(p("PART B: GENOTOXICITY STUDIES", "sub_header"))
e.append(p("<b>Definition:</b> Studies assessing a compound's ability to damage DNA (mutations, "
"chromosomal aberrations, strand breaks) that may cause heritable changes or cancer. "
"Governed by <b>ICH S2(R1)</b>.", "body"))
e.append(p("Standard Battery of Tests (ICH S2R1):", "sub_header2"))
headers = [p("<b>Test</b>"), p("<b>System</b>"), p("<b>Detects</b>"), p("<b>Notes</b>")]
rows = [
[p("Ames Test (TG 471)"), p("Salmonella typhimurium, E. coli"), p("Point mutations"),
p("±S9 metabolic activation")],
[p("In Vitro Chromosomal Aberration (TG 473)"), p("Human lymphocytes / CHO cells"),
p("Chromosomal breaks, translocations"), p("±S9 activation")],
[p("Mouse Lymphoma Assay (MLA)"), p("L5178Y cells"), p("Gene mutations, small deletions"),
p("Alternative to TG 473")],
[p("In Vivo Micronucleus Test (TG 474)"), p("Mice/rat bone marrow"),
p("Chromosome damage in vivo"), p("Most important in vivo test")],
[p("Comet Assay (SCGE)"), p("Any cell type"), p("DNA strand breaks"),
p("Additional/confirmatory")],
]
e.append(make_table(headers, rows, [4.5*cm, 3.5*cm, 4*cm, 5*cm]))
e.append(sp(4))
e.append(p("Key Note – Ames Test Principle:", "sub_header2"))
e.append(info_box("Mutant Salmonella (his⁻) cannot grow without histidine. A mutagenic compound "
"causes REVERSION → bacteria become his⁺ and form colonies. Colony count ∝ "
"mutagenic potency. S9 fraction (rat liver microsomes) added to test pro-mutagens."))
return e
# ─── Q2(b): Transgenic Animals ────────────────────────────────────────────────
def q2b():
e = []
e.append(q_banner("Q2(b) — Transgenic Animals in Experimental Research", DARK_BLUE))
e.append(sp(6))
e.append(p("<b>Definition:</b> Animals whose genome has been artificially altered by introducing, "
"deleting, or modifying a specific gene using recombinant DNA technology.", "body"))
e.append(p("Methods of Creating Transgenic Animals:", "sub_header"))
for item in [
"<b>Microinjection:</b> Foreign DNA injected into pronucleus of fertilized ovum – classic method",
"<b>ES Cell Method:</b> Homologous recombination in embryonic stem cells – creates knockout/knockin",
"<b>CRISPR-Cas9:</b> Precise targeted genome editing – most modern method",
"<b>Retroviral Vectors:</b> Used to introduce foreign genes into early embryos",
]:
e.append(b(item))
e.append(p("Types of Transgenic Animals:", "sub_header"))
headers = [p("<b>Type</b>"), p("<b>Description</b>"), p("<b>Example</b>")]
rows = [
[p("Knockout (KO)"), p("Target gene deleted/inactivated"), p("ApoE-/- mice → atherosclerosis model")],
[p("Knockin"), p("Normal gene replaced by mutant version"), p("KRAS knockin → cancer model")],
[p("Overexpression"), p("Extra copies of gene added"), p("HER2-overexpressing mice")],
[p("Conditional KO"), p("Tissue-specific / time-specific deletion"), p("CRE-lox system")],
[p("Reporter"), p("Reporter gene (GFP/luciferase) driven by promoter"), p("Tissue-specific expression tracking")],
]
e.append(make_table(headers, rows, [3*cm, 6.5*cm, 7.5*cm]))
e.append(p("Applications:", "sub_header"))
apps = [
("Disease Modeling", "APP/PS1 mice for Alzheimer's; NOD mouse for Type 1 diabetes; RAS/MYC mice develop spontaneous tumors"),
("Drug Target Validation", "Knock out suspected target gene → if disease improves, target is validated"),
("Carcinogenicity Testing", "Trp53+/- and rasH2 mice replace 2-year rodent bioassay with 6-month study"),
("Genetic Deficiency Correction", "GnRH gene injected into GnRH-deficient mice → normal offspring (Harper's Biochemistry)"),
("Pharming", "Transgenic goats/cows produce human therapeutic proteins in milk (e.g., antithrombin III)"),
("Immunology", "Mice with specific TCRs/BCRs for studying antigen-specific immune responses"),
("Neuroscience", "Channelrhodopsin-2 (ChR2) transgenic mice for optogenetics – switch neurons on/off"),
]
for title, detail in apps:
e.append(b(f"<b>{title}:</b> {detail}"))
e.append(sp(4))
e.append(p("Advantages vs. Limitations:", "sub_header2"))
headers = [p("<b>Advantages</b>"), p("<b>Limitations</b>")]
rows = [
[p("Precise genetic manipulation"), p("Expensive and time-consuming to generate")],
[p("Models closely mimic human monogenic diseases"), p("Compensatory gene expression may mask phenotype")],
[p("Can study gene function in intact physiological context"), p("Species differences limit translatability")],
[p("Heritable – maintained as stable colonies"), p("Off-target effects with CRISPR possible")],
]
e.append(make_table(headers, rows, [8.5*cm, 8.5*cm]))
return e
# ─── Q3(a): OECD ──────────────────────────────────────────────────────────────
def q3a():
e = []
e.append(q_banner("Q3(a) — Short Note on OECD", ACCENT_GREEN))
e.append(sp(6))
e.append(info_box("<b>OECD</b> = Organisation for Economic Co-operation and Development | "
"Founded: 1961 | HQ: Paris, France | Members: 38 countries"))
e.append(sp(4))
e.append(p("<b>Relevance in Pharmacology/Toxicology:</b> OECD Guidelines for the Testing of "
"Chemicals are the internationally recognized standard for non-clinical safety testing, "
"used by FDA, EMA, CDSCO, PMDA worldwide.", "body"))
e.append(p("Key OECD Test Guidelines (TGs):", "sub_header"))
headers = [p("<b>TG No.</b>"), p("<b>Test</b>"), p("<b>Section</b>")]
rows = [
[p("TG 420"), p("Fixed Dose Procedure (acute oral toxicity)"), p("Health Effects")],
[p("TG 423"), p("Acute Toxic Class Method"), p("Health Effects")],
[p("TG 425"), p("Up-and-Down Procedure (LD50 estimation)"), p("Health Effects")],
[p("TG 451-453"), p("Combined Chronic Toxicity/Carcinogenicity"), p("Carcinogenicity")],
[p("TG 471"), p("Ames Test (bacterial reverse mutation)"), p("Genetic Toxicology")],
[p("TG 473"), p("In Vitro Chromosomal Aberration"), p("Genetic Toxicology")],
[p("TG 474"), p("Micronucleus Test (in vivo)"), p("Genetic Toxicology")],
[p("TG 476"), p("Mouse Lymphoma Assay"), p("Genetic Toxicology")],
[p("TG 414"), p("Prenatal Developmental Toxicity"), p("Reproductive Toxicity")],
[p("TG 416"), p("Two-Generation Reproductive Toxicity"), p("Reproductive Toxicity")],
]
e.append(make_table(headers, rows, [2.5*cm, 10*cm, 4.5*cm]))
e.append(sp(4))
e.append(p("Core Principles:", "sub_header"))
for item in [
"<b>Mutual Acceptance of Data (MAD):</b> Data from one OECD member accepted by all others – avoids duplication of animal testing",
"<b>Good Laboratory Practice (GLP):</b> OECD sets GLP principles ensuring quality and integrity of non-clinical safety studies",
"<b>3Rs Promotion:</b> Encourages Replace, Reduce, Refine in animal testing",
"<b>Harmonization:</b> Creates uniform global standards for drug/chemical safety submissions",
]:
e.append(b(item))
return e
# ─── Q3(b): CPCSEA ────────────────────────────────────────────────────────────
def q3b():
e = []
e.append(q_banner("Q3(b) — Handling & Care of Lab Animals – CPCSEA Guidelines", MID_BLUE))
e.append(sp(6))
e.append(info_box("<b>CPCSEA</b> = Committee for the Purpose of Control and Supervision of "
"Experiments on Animals | Under: Prevention of Cruelty to Animals Act, 1960 | "
"Ministry of Fisheries, Animal Husbandry and Dairying, Govt. of India"))
e.append(sp(4))
e.append(p("1. The Three Rs (Mandatory Framework)", "sub_header"))
for item in [
"<b>Replacement:</b> Use alternatives (cell cultures, in silico, in vitro) wherever possible",
"<b>Reduction:</b> Minimize animal numbers while maintaining statistical validity",
"<b>Refinement:</b> Modify procedures to minimize pain, suffering, and distress",
]:
e.append(b(item))
e.append(p("2. Housing Requirements (CPCSEA Standards):", "sub_header"))
headers = [p("<b>Parameter</b>"), p("<b>Standard</b>")]
rows = [
[p("Temperature"), p("22 ± 3°C")],
[p("Relative Humidity"), p("30–70%")],
[p("Light–Dark Cycle"), p("12:12 hours")],
[p("Ventilation"), p("10–20 air changes per hour")],
[p("Noise"), p("Kept to minimum")],
]
e.append(make_table(headers, rows, [5*cm, 12*cm]))
e.append(sp(4))
e.append(p("3. Space Requirements:", "sub_header"))
headers = [p("<b>Species</b>"), p("<b>Floor Area (cm²)</b>"), p("<b>Cage Height (cm)</b>")]
rows = [
[p("Mouse"), p("150"), p("12.5")],
[p("Rat"), p("350"), p("15")],
[p("Guinea Pig"), p("650"), p("18")],
[p("Rabbit"), p("1800"), p("40")],
]
e.append(make_table(headers, rows, [5*cm, 6*cm, 6*cm]))
e.append(p("4. Handling Techniques:", "sub_header"))
for item in [
"<b>Mice/Rats:</b> Grasp at base of tail (not tip); support body weight; use gloves",
"<b>Guinea Pigs:</b> Support body from below; never grasp by loose skin",
"<b>Rabbits:</b> Always support hindquarters; prevent kicking (can cause spinal fracture)",
"Trained personnel only; animals must be acclimatized before experiments",
]:
e.append(b(item))
e.append(p("5. Other Requirements:", "sub_header"))
for item in [
"<b>Diet & Water:</b> Nutritionally adequate, sterilized diet; clean water ad libitum",
"<b>Health Monitoring:</b> Regular veterinary supervision; sick animals isolated; quarantine 5–7 days",
"<b>Anesthesia & Analgesia:</b> Mandatory for all painful procedures; post-op analgesia required",
"<b>Identification:</b> Ear notching, tattooing, microchip; toe clipping only in neonates with justification",
"<b>IAEC:</b> Every registered institution must have an Institutional Animal Ethics Committee (7 members)",
"<b>Records:</b> Complete documentation of animals purchased, used, and disposed",
]:
e.append(b(item))
return e
# ─── Q4(a): Validation of Animal Models ───────────────────────────────────────
def q4a():
e = []
e.append(q_banner("Q4(a) — Validation of Animal Models", DARK_BLUE))
e.append(sp(6))
e.append(p("<b>Definition:</b> Validation is the process of establishing that an animal model "
"reliably represents, predicts, or mimics the human disease or pharmacological response "
"being studied.", "body"))
e.append(p("Three Core Validity Criteria:", "sub_header"))
criteria = [
("Face Validity (Phenomenological)", LIGHT_BLUE, MID_BLUE,
"Model resembles the human condition superficially – similar symptoms/signs.",
"STZ-diabetic rat: elevated blood glucose mimics human type 1 diabetes"),
("Construct Validity (Etiological)", colors.HexColor("#E8F5E9"), ACCENT_GREEN,
"Same underlying mechanism/etiology as human disease – similar pathophysiology.",
"ApoE-/- mice develop atherosclerosis via similar lipid dysregulation as humans"),
("Predictive Validity", LIGHT_GOLD, GOLD,
"MOST IMPORTANT – model predicts what will happen in humans. If drug works in model → works in humans.",
"Carrageenan paw edema: NSAIDs reduce edema → predicts clinical anti-inflammatory activity"),
]
for title, bg, border, defn, ex in criteria:
data = [[Paragraph(f"<b>{title}</b>",
ParagraphStyle("vt", parent=S["sub_header2"], textColor=border, fontSize=11)),
Paragraph(f"{defn}<br/><br/><b>Example:</b> {ex}", S["body"])]]
tbl = Table(data, colWidths=[5*cm, 12*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), bg),
("BOX", (0,0), (-1,-1), 1.5, border),
("LINERIGHT", (0,0), (0,-1), 1.5, border),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
e.append(tbl)
e.append(sp(4))
e.append(p("Validated Animal Models – Summary:", "sub_header"))
headers = [p("<b>Model</b>"), p("<b>Disease</b>"), p("<b>Validated By</b>"), p("<b>Predicts</b>")]
rows = [
[p("Carrageenan Paw Edema"), p("Inflammation"), p("NSAIDs, corticosteroids"), p("Anti-inflammatory activity")],
[p("Forced Swim Test"), p("Depression"), p("TCAs, SSRIs"), p("Antidepressant activity")],
[p("STZ-Diabetic Rat"), p("Type 1 Diabetes"), p("Insulin, antidiabetics"), p("Antidiabetic activity")],
[p("DOCA-Salt Rat"), p("Hypertension"), p("ACE inhibitors, diuretics"), p("Antihypertensive activity")],
[p("PTZ Seizure Model"), p("Epilepsy"), p("Valproate, phenytoin"), p("Anticonvulsant activity")],
]
e.append(make_table(headers, rows, [4*cm, 3.5*cm, 4.5*cm, 5*cm]))
return e
# ─── Q4(b): Euthanasia ────────────────────────────────────────────────────────
def q4b():
e = []
e.append(q_banner("Q4(b) — Euthanasia in Animals in Experimental Studies", ACCENT_TEAL))
e.append(sp(6))
e.append(info_box("<b>Euthanasia</b> (Greek: eu = good + thanatos = death) = Deliberate, humane "
"killing of an animal minimizing pain, distress, and anxiety. Governed by "
"<b>CPCSEA guidelines</b>, <b>IAEC approval</b>, and <b>AVMA Guidelines</b>."))
e.append(sp(4))
e.append(p("Criteria for Acceptable Euthanasia Method:", "sub_header"))
for item in [
"Causes rapid loss of consciousness followed by death",
"Minimizes pain, distress, and anxiety",
"Reliable and reproducible",
"Safe for the personnel performing it",
"Compatible with research objectives (e.g., tissue integrity preserved)",
"Appropriate for the species, age, and size",
]:
e.append(b(item))
e.append(p("Physical Methods:", "sub_header"))
headers = [p("<b>Method</b>"), p("<b>Species</b>"), p("<b>Notes</b>")]
rows = [
[p("CO₂ Inhalation"), p("Mice, rats"), p("Most common in rodents; fill at 30–70% chamber vol/min; NOT for neonates")],
[p("Cervical Dislocation"), p("Mice, small rats"), p("Rapid; requires skill; manual or mechanical")],
[p("Decapitation"), p("Rodents, fish"), p("Requires guillotine; preserves fresh tissue/blood")],
[p("Pithing"), p("Frogs, fish"), p("Physical destruction of brain/spinal cord")],
]
e.append(make_table(headers, rows, [4*cm, 3.5*cm, 9.5*cm]))
e.append(p("Chemical Methods:", "sub_header"))
headers = [p("<b>Agent</b>"), p("<b>Dose / Route</b>"), p("<b>Species</b>")]
rows = [
[p("Sodium pentobarbital"), p("100 mg/kg IV (overdose)"), p("Dogs, cats, rabbits, monkeys – GOLD STANDARD")],
[p("Ketamine + Xylazine"), p("Anesthetic overdose"), p("Multiple species")],
[p("Tricaine (MS-222)"), p("0.5 g/L in water"), p("Fish, amphibians")],
[p("KCl IV"), p("Cardiac arrest dose"), p("ONLY under deep general anesthesia")],
[p("Isoflurane overdose"), p("High concentration"), p("Rodents, birds, reptiles")],
]
e.append(make_table(headers, rows, [5*cm, 4*cm, 8*cm]))
e.append(sp(4))
e.append(p("Humane Endpoints (Mandatory in IAEC Protocol):", "sub_header2"))
e.append(p("Animals showing severe suffering MUST be euthanized before experimental endpoint. "
"Pre-defined criteria include: maximum allowable tumor size (≤20 mm diameter), "
"body weight loss >20%, severe distress scoring, inability to reach food/water.", "body"))
e.append(sp(4))
e.append(p("Verification of Death (Mandatory):", "sub_header2"))
for item in ["No heartbeat on auscultation", "No respiratory movement",
"Fixed, dilated pupils", "Loss of colour in mucous membranes"]:
e.append(b(item))
return e
# ─── Q5(a): HPLC ──────────────────────────────────────────────────────────────
def q5a():
e = []
e.append(q_banner("Q5(a) — High Performance Liquid Chromatography (HPLC)", MID_BLUE))
e.append(sp(6))
e.append(p("<b>Definition:</b> HPLC is an advanced form of column chromatography that uses high "
"pressure to force a liquid mobile phase through a stationary-phase packed column to "
"separate, identify, and quantify compounds in a mixture.", "body"))
e.append(p("Principle:", "sub_header"))
e.append(info_box("Based on <b>differential partitioning</b> of analyte molecules between mobile "
"and stationary phases. Components with higher affinity for stationary phase → "
"longer retention time. Differential migration → separation.<br/><br/>"
"<b>Retention Factor:</b> k = (tR – t₀) / t₀ where tR = retention time, "
"t₀ = dead time"))
e.append(p("Components of HPLC System:", "sub_header"))
headers = [p("<b>Component</b>"), p("<b>Function</b>"), p("<b>Details</b>")]
rows = [
[p("Solvent Reservoir"), p("Holds mobile phase"), p("Must be degassed to prevent bubbles")],
[p("High-Pressure Pump"), p("Delivers mobile phase"), p("0.5–2 mL/min; 50–400 bar pressure")],
[p("Sample Injector"), p("Introduces sample"), p("1–100 µL; manual or autosampler")],
[p("Column"), p("Separation"), p("15–25 cm × 4.6 mm; 3–5 µm silica particles")],
[p("Detector"), p("Detects analyte"), p("UV/Vis, Fluorescence, Electrochemical, LC-MS")],
[p("Data System"), p("Records/integrates"), p("Retention time, peak area, quantification")],
]
e.append(make_table(headers, rows, [3.5*cm, 4*cm, 9.5*cm]))
e.append(p("Types of HPLC:", "sub_header"))
headers = [p("<b>Type</b>"), p("<b>Stationary Phase</b>"), p("<b>Mobile Phase</b>"), p("<b>Applications</b>")]
rows = [
[p("Reversed-Phase (RP-HPLC)"), p("Non-polar (C18, C8)"), p("Polar (water + ACN/MeOH)"),
p("Most drugs – MOST COMMON")],
[p("Normal Phase"), p("Polar (silica)"), p("Non-polar (hexane)"),
p("Fat-soluble vitamins, lipids")],
[p("Ion Exchange"), p("Ionic resin"), p("Aqueous buffer"),
p("Hemoglobin variants (HbA2, HbF)")],
[p("Size Exclusion (SEC)"), p("Porous gel"), p("Aqueous buffer"),
p("Proteins, polymers")],
[p("Affinity HPLC"), p("Bioligand (antibody)"), p("Buffer"),
p("Purification of biologics")],
]
e.append(make_table(headers, rows, [4*cm, 3.5*cm, 3.5*cm, 6*cm]))
e.append(p("Pharmaceutical Applications:", "sub_header"))
for item in [
"<b>Drug assay:</b> Content, purity, dissolution testing of formulations",
"<b>Bioavailability studies:</b> Plasma drug concentration measurement in PK studies",
"<b>Hemoglobin analysis:</b> HbA2/HbF quantification for thalassemia diagnosis (cation-exchange HPLC)",
"<b>Antimicrobial assay:</b> Chloramphenicol determination in blood serum",
"<b>Vitamin assay:</b> Vitamins A (0.5–2.0 mg/L), D, E, K by RP-HPLC",
"<b>Mycobacteria identification:</b> Mycolic acid profiling by HPLC",
"<b>Toxicology:</b> Detection of drugs of abuse, pesticide residues, heavy metals",
]:
e.append(b(item))
return e
# ─── Q5(b): Limitations of Animal Testing ────────────────────────────────────
def q5b():
e = []
e.append(q_banner("Q5(b) — Limitations of Animal Testing", RED_ACCENT))
e.append(sp(6))
limitations = [
("1. Species Differences (Most Critical)", [
"CYP450 isoforms vary between species → different drug metabolism",
"Aspirin is hepatotoxic in cats (lack glucuronidation); safe in humans",
"Thalidomide: teratogenic in humans but not in rats in initial testing",
"Penicillin: lethal to guinea pigs but safe in humans",
]),
("2. Inability to Model Complex Human Diseases", [
"Human diseases are multifactorial (genetic + environmental + psychological)",
"Animal models of depression, schizophrenia, Alzheimer's – poor translatability",
"No single animal model of arthritis truly represents human disease",
"Immune system significantly different (rodents: more NK cells proportionally)",
]),
("3. Ethical Concerns", [
"Animals experience pain, fear, and suffering – moral obligation to minimize",
"3Rs framework mandatory; growing public and legislative pressure",
"Some models inherently distressing (forced swim test, hot plate test)",
]),
("4. High Failure Rate", [
"~90% of drugs that pass animal testing FAIL in human clinical trials",
"Only ~1 in 10,000 pre-clinical compounds reaches the market",
"2-year carcinogenicity study costs $2–4 million",
]),
("5. Genetic Homogeneity", [
"Inbred lab strains are genetically homogeneous",
"Real human populations are genetically diverse",
"Results may not reflect pharmacogenomic variability in humans",
]),
("6. Biologics & Immunogenicity", [
"Immunogenicity of biologics cannot be properly evaluated in animals",
"Human-specific antigens not expressed in animals",
"TGN1412 (anti-CD28 mAb): no toxicity in monkeys → cytokine storm in humans",
]),
("7. Specific Test Limitations", [
"Ames test: prokaryotic bacteria ≠ eukaryotic human cells",
"LD50: poor reproducibility; affected by strain, diet, season",
"MTD-based carcinogenicity may produce tumors via cytotoxicity, not intrinsic carcinogenicity",
]),
]
for title, bullets in limitations:
e.append(p(title, "sub_header"))
for item in bullets:
e.append(b(item))
e.append(sp(6))
e.append(p("Alternatives to Animal Testing (3Rs):", "sub_header"))
headers = [p("<b>Alternative</b>"), p("<b>Replaces</b>")]
rows = [
[p("In silico ADME/Tox prediction"), p("Early toxicity screening")],
[p("Organoids / 3D tissue models"), p("Organ-level in vivo studies")],
[p("Organ-on-a-chip (microfluidics)"), p("Multi-organ interactions")],
[p("Human cell-based HTS"), p("Primary screening in animals")],
[p("Microdosing (Phase 0)"), p("PK studies in animals")],
[p("Microphysiological systems (MPS)"), p("Complex organ models")],
]
e.append(make_table(headers, rows, [8.5*cm, 8.5*cm]))
return e
# ─── Q6(a): Langendorff ───────────────────────────────────────────────────────
def q6a():
e = []
e.append(q_banner("Q6(a) — Langendorff Apparatus & Its Applications", DARK_BLUE))
e.append(sp(6))
e.append(info_box("Developed by <b>Oscar Langendorff (1895)</b>. The isolated perfused heart is "
"one of the most important ex vivo cardiac pharmacological preparations."))
e.append(sp(4))
e.append(p("Principle:", "sub_header"))
e.append(p("The isolated heart is perfused <b>retrogradely (backward) through the aorta</b> with "
"oxygenated, warmed Krebs-Henseleit buffer. Perfusion pressure keeps the aortic valve "
"closed → fluid enters coronary ostia → retrograde coronary perfusion → myocardium "
"receives nutrients → heart beats spontaneously.", "body"))
e.append(p("Krebs-Henseleit Solution Composition:", "sub_header2"))
headers = [p("<b>Component</b>"), p("<b>Concentration (mM)</b>"),
p("<b>Component</b>"), p("<b>Concentration (mM)</b>")]
rows = [
[p("NaCl"), p("118.5"), p("KH₂PO₄"), p("1.2")],
[p("KCl"), p("4.7"), p("NaHCO₃"), p("25.0")],
[p("MgSO₄"), p("1.2"), p("Glucose"), p("11.1")],
[p("CaCl₂"), p("2.5"), p("Gas: 95% O₂ + 5% CO₂"), p("pH 7.35–7.45")],
]
e.append(make_table(headers, rows, [3.5*cm, 3*cm, 4.5*cm, 6*cm]))
e.append(p("Components of the Apparatus:", "sub_header"))
for item in [
"<b>Perfusion Buffer Reservoir</b> – KH buffer at constant height (60–80 cmH₂O) for constant pressure mode",
"<b>Water Jacket/Thermostatic Bath</b> – Maintains 37°C throughout circuit",
"<b>Bubble Trap</b> – Prevents air emboli in coronary circulation",
"<b>Aortic Cannula</b> – Stainless steel; tied into ascending aorta",
"<b>Intraventricular Balloon</b> – Latex balloon in LV for pressure measurement",
"<b>Transducer & ECG</b> – Force, pressure, rate measurement",
]:
e.append(b(item))
e.append(p("Parameters Measured:", "sub_header"))
headers = [p("<b>Parameter</b>"), p("<b>Method</b>"), p("<b>Clinical Relevance</b>")]
rows = [
[p("Heart Rate (HR)"), p("ECG / force transducer"), p("Chronotropy")],
[p("LVDP (LV Developed Pressure)"), p("Intraventricular balloon"), p("Inotropy")],
[p("dP/dt max"), p("Derivative of LV pressure"), p("Myocardial contractility")],
[p("Coronary Flow Rate"), p("Effluent collection"), p("Coronary vasomotor tone")],
[p("Arrhythmia detection"), p("ECG recording"), p("Antiarrhythmic efficacy")],
[p("CK / LDH in effluent"), p("Enzyme assay"), p("Myocardial injury/necrosis")],
]
e.append(make_table(headers, rows, [4.5*cm, 5*cm, 7.5*cm]))
e.append(p("Applications:", "sub_header"))
for item in [
"<b>Antiarrhythmic Drug Screening:</b> Aconitine-induced, CaCl₂-adrenaline, ouabain-induced, or ischemia-reperfusion arrhythmias",
"<b>Ischemia-Reperfusion Studies:</b> LCA ligation → reperfusion; study cardioprotective drugs, preconditioning",
"<b>Cardiotoxicity Assessment:</b> Negative inotropic effects of TCAs, anthracyclines, Ca²⁺ channel blockers",
"<b>Coronary Vasomotor Studies:</b> Effects of nitrates, endothelin, adenosine on coronary vessels",
"<b>Cardiac Metabolism:</b> O₂ consumption, energy substrate utilization (glucose vs. fatty acids)",
"<b>Working Heart Mode:</b> Modified preparation where LA is also perfused – measures cardiac output",
]:
e.append(b(item))
e.append(p("Advantages vs. Limitations:", "sub_header2"))
headers = [p("<b>Advantages</b>"), p("<b>Limitations</b>")]
rows = [
[p("Controlled, reproducible conditions"), p("Ex vivo – no neural (vagal/sympathetic) control")],
[p("Eliminates systemic neurohumoral effects"), p("No haemoglobin in perfusate – limited O₂ carrying")],
[p("Multiple parameters simultaneously"), p("Short viability (3–5 hours)")],
[p("Direct drug access to myocardium"), p("Limited to small animals (rat, guinea pig, rabbit)")],
]
e.append(make_table(headers, rows, [8.5*cm, 8.5*cm]))
return e
# ─── Q6(b): PCR ───────────────────────────────────────────────────────────────
def q6b():
e = []
e.append(q_banner("Q6(b) — Principle of PCR & Its Applications", ACCENT_GREEN))
e.append(sp(6))
e.append(info_box("<b>PCR</b> = Polymerase Chain Reaction | Developed by: <b>Kary Mullis (1983)</b> "
"| Nobel Prize in Chemistry: <b>1993</b> | An in vitro technique for exponential "
"amplification of specific DNA sequences."))
e.append(sp(4))
e.append(p("Principle:", "sub_header"))
e.append(p("PCR is based on the <b>cyclic polymerization of DNA copies</b> using a heat-stable "
"<b>Taq polymerase</b> (from Thermus aquaticus). Each cycle doubles the DNA copies: "
"<b>2ⁿ copies</b> after n cycles. 30–40 cycles → ~10⁹ copies from a single template molecule.", "body"))
e.append(p("Components Required:", "sub_header"))
for item in [
"<b>DNA Template</b> – Target DNA sequence to be amplified",
"<b>Primers</b> – Two synthetic oligonucleotides (15–30 bases) flanking the target",
"<b>dNTPs</b> – dATP, dGTP, dCTP, dTTP (DNA building blocks)",
"<b>Taq Polymerase</b> – Heat-stable DNA polymerase (survives 95°C denaturation)",
"<b>Mg²⁺ ions</b> – Essential cofactor for Taq polymerase activity",
"<b>Thermocycler</b> – Instrument that precisely controls temperature cycling",
]:
e.append(b(item))
e.append(p("Three Steps of Each PCR Cycle:", "sub_header"))
steps = [
("Step 1: Denaturation", "94–95°C, 30–60 sec",
"High temperature breaks H-bonds between complementary bases → 2 single-stranded templates. "
"Taq polymerase is thermostable and survives this step."),
("Step 2: Annealing", "50–65°C, 20–40 sec",
"Temperature lowered → primers hybridize to complementary sequences on each template. "
"Temperature = Tm – 5°C. Primers must not self-complement (causes primer-dimer formation)."),
("Step 3: Extension", "72°C, 30–60 sec/kb",
"Taq polymerase synthesizes new DNA from 3' end of primer. Reads template 3'→5'; "
"synthesizes 5'→3'. Optimal temperature for Taq activity."),
]
for title, temp, desc in steps:
data = [[Paragraph(f"<b>{title}</b><br/>{temp}",
ParagraphStyle("pst", parent=S["body"], textColor=DARK_BLUE,
fontName="Helvetica-Bold", backColor=LIGHT_BLUE)),
Paragraph(desc, S["body"])]]
tbl = Table(data, colWidths=[4.5*cm, 12.5*cm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), LIGHT_BLUE),
("BOX", (0,0), (-1,-1), 0.8, MID_BLUE),
("LINERIGHT", (0,0), (0,-1), 1.5, MID_BLUE),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
e.append(tbl)
e.append(sp(3))
e.append(p("PCR Variants:", "sub_header"))
headers = [p("<b>Type</b>"), p("<b>Principle</b>"), p("<b>Application</b>")]
rows = [
[p("RT-PCR"), p("RNA → cDNA (reverse transcriptase) → PCR"), p("RNA viruses (COVID-19, HIV), gene expression")],
[p("Real-Time PCR (qPCR)"), p("Fluorescent dye detects product in real time"), p("Viral load quantification, gene expression profiling")],
[p("Nested PCR"), p("Two sequential primer sets – inner and outer"), p("Highly sensitive pathogen detection")],
[p("Multiplex PCR"), p("Multiple primer pairs in one reaction"), p("Simultaneous detection of multiple pathogens")],
[p("Allele-Specific PCR"), p("Primer matches specific mutation site"), p("SNP genotyping, mutation detection")],
[p("Digital PCR"), p("Single molecule amplification in droplets"), p("Absolute quantification")],
]
e.append(make_table(headers, rows, [3.5*cm, 6*cm, 7.5*cm]))
e.append(p("Applications:", "sub_header"))
for item in [
"<b>Genetic Disease Diagnosis:</b> Sickle cell disease, cystic fibrosis, thalassemia, prenatal diagnosis",
"<b>Infectious Disease:</b> COVID-19 (RT-PCR gold standard), HIV viral load, TB DNA detection, Hepatitis B/C",
"<b>Oncology:</b> BCR-ABL in CML, KRAS/BRAF mutations, HER2 amplification, MRD monitoring in leukemia",
"<b>Forensic Medicine:</b> DNA fingerprinting from blood/semen/hair; paternity testing",
"<b>Microbiology:</b> 16S rRNA amplification for species identification; MRSA/VRE detection",
"<b>HLA Typing:</b> Organ transplant compatibility assessment",
"<b>Research:</b> Cloning, site-directed mutagenesis, gene expression profiling",
]:
e.append(b(item))
return e
# ─── Main PDF Builder ─────────────────────────────────────────────────────────
def build_pdf(output_path):
doc = BaseDocTemplate(
output_path,
pagesize=A4,
leftMargin=1.5*cm, rightMargin=1.5*cm,
topMargin=2.5*cm, bottomMargin=1.8*cm,
title="CMD Pharmacology Study Guide",
author="Orris AI",
subject="Non-Clinical Pharmacology & Analytical Biochemical Assay",
)
cover_frame = Frame(0, 0, PAGE_W, PAGE_H, leftPadding=2*cm, rightPadding=2*cm,
topPadding=0, bottomPadding=0)
body_frame = Frame(1.5*cm, 1.8*cm, PAGE_W - 3*cm, PAGE_H - 4.3*cm,
leftPadding=0, rightPadding=0, topPadding=0, bottomPadding=0)
cover_tmpl = PageTemplate(id="Cover", frames=[cover_frame], onPage=on_cover)
body_tmpl = PageTemplate(id="Body", frames=[body_frame], onPage=on_page)
doc.addPageTemplates([cover_tmpl, body_tmpl])
from reportlab.platypus import NextPageTemplate
story = []
# Cover
story += cover_page()
story.append(NextPageTemplate("Body"))
story.append(PageBreak())
# TOC
story += toc_page()
story.append(PageBreak())
# Questions
sections = [
(q1a, "Q1(a)"), (q1b, "Q1(b)"),
(q2a, "Q2(a)"), (q2b, "Q2(b)"),
(q3a, "Q3(a)"), (q3b, "Q3(b)"),
(q4a, "Q4(a)"), (q4b, "Q4(b)"),
(q5a, "Q5(a)"), (q5b, "Q5(b)"),
(q6a, "Q6(a)"), (q6b, "Q6(b)"),
]
for i, (fn, label) in enumerate(sections):
story += fn()
if i < len(sections) - 1:
story.append(PageBreak())
doc.build(story)
print(f"PDF saved to: {output_path}")
if __name__ == "__main__":
build_pdf("/home/daytona/workspace/cmd-pharmacology/CMD_Pharmacology_Study_Guide.pdf")