using the three files make a power point presentation on topic Colorimeter. the presentation should have a good background and have it include diagrams from the internet related to the topic.
cd /home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/ && python3 -c " import pdfplumber for fname in ['color.pdf', 'colr1.pdf', 'colorimetry.pdf']: print(f'\n\n===== {fname} =====') with pdfplumber.open(fname) as pdf: for i, page in enumerate(pdf.pages): text = page.extract_text() if text: print(f'--- Page {i+1} ---') print(text[:3000]) " 2>&1 | head -400
cd /home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/ && python3 -m markitdown color.pdf 2>&1 | head -200
cd /home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/ && python3 -c " from pypdf import PdfReader for fname in ['color.pdf', 'colr1.pdf', 'colorimetry.pdf']: print(f'\n\n===== {fname} =====') reader = PdfReader(fname) print(f'Pages: {len(reader.pages)}') for i, page in enumerate(reader.pages[:3]): text = page.extract_text() print(f'Page {i+1}: {repr(text[:500]) if text else \"EMPTY\"}') " 2>&1
cd /home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/ && python3 -c " import subprocess, os # Convert PDFs to images then OCR for fname in ['color.pdf', 'colr1.pdf', 'colorimetry.pdf']: base = fname.replace('.pdf','') result = subprocess.run(['pdftoppm', '-r', '200', fname, f'/tmp/{base}'], capture_output=True, text=True) print(f'{fname} conversion: {result.returncode} {result.stderr[:100]}') import glob files = glob.glob('/tmp/color*.ppm') + glob.glob('/tmp/colr1*.ppm') + glob.glob('/tmp/colorimetry*.ppm') print('PPM files:', sorted(files)) " 2>&1
python3 -c " import subprocess, glob files = sorted(set(['/tmp/color-1.ppm', '/tmp/color-2.ppm', '/tmp/colorimetry-1.ppm', '/tmp/colorimetry-2.ppm', '/tmp/colr1-1.ppm', '/tmp/colr1-2.ppm'])) for f in files: result = subprocess.run(['tesseract', f, 'stdout', '--psm', '3'], capture_output=True, text=True) print(f'\n===== {f} =====') print(result.stdout[:2500]) if result.stderr: print('ERR:', result.stderr[:100]) " 2>&1
colorimeter diagram components Beer Lambert law instrument labeled diagram
mkdir -p /home/daytona/workspace/colorimeter-ppt && ls /home/daytona/workspace/colorimeter-ppt/
# First download images using the helper script node /home/daytona/skills/shared/scripts/fetch_images.js \ "https://microbenotes.com/wp-content/uploads/2022/12/Parts-of-Colorimeter.jpg" \ "https://laboratorytests.org/wp-content/uploads/2022/06/Colorimeter-principle-instrumentation-scaled.jpg" \ "https://cdn1.byjus.com/wp-content/uploads/2019/08/colorimeter-instrument.png" \ "https://laboratorytests.org/wp-content/uploads/2022/06/Colorimeter-scaled.jpg" \ "https://microbenotes.com/wp-content/uploads/2022/12/Colorimeter.jpg" \ 2>&1 | head -5
~/colorimeter-ppt
~/colorimeter-ppt/create_presentation.js
const pptxgen = require("pptxgenjs");
const { execSync } = require("child_process");
const path = require("path");
// ─── Fetch images as base64 ───────────────────────────────────────────────────
const IMAGE_URLS = [
"https://microbenotes.com/wp-content/uploads/2019/10/Parts-of-Colorimeter.jpg",
"https://laboratorytests.org/wp-content/uploads/2022/08/Colorimeter-principle-instrumentation-scaled.jpg",
"https://cdn1.byjus.com/wp-content/uploads/2022/02/colorimeter-instrument.png",
"https://laboratorytests.org/wp-content/uploads/2022/08/Colorimeter-scaled.jpg",
"https://microbenotes.com/wp-content/uploads/2019/10/Colorimeter.jpg"
];
console.log("Fetching images...");
let images = [];
try {
const raw = execSync(
`node /home/daytona/skills/shared/scripts/fetch_images.js ${IMAGE_URLS.map(u => `"${u}"`).join(" ")}`,
{ maxBuffer: 100 * 1024 * 1024 }
).toString();
images = JSON.parse(raw);
images.forEach((img, i) => {
if (img.error) console.warn(` [WARN] Image ${i} failed: ${img.error}`);
else console.log(` [OK] Image ${i}: ${img.url.split("/").pop()}`);
});
} catch (e) {
console.error("Image fetch error:", e.message);
}
// helper: return base64 data or null
function img(index) {
if (!images[index] || images[index].error) return null;
return images[index].base64;
}
// ─── Theme constants ──────────────────────────────────────────────────────────
const BG_DARK = "0D1B4B"; // deep navy
const BG_MID = "0F2167"; // slightly lighter navy
const BG_CARD = "162458"; // card background
const GOLD = "F5A623"; // amber/gold accent
const GOLD_LIGHT = "FFD580"; // light gold
const WHITE = "FFFFFF";
const LIGHT_BLUE = "90CAF9";
const TEAL = "26C6DA";
const GREEN = "66BB6A";
const RED_SOFT = "EF5350";
const SLIDE_W = 13.3;
const SLIDE_H = 7.5;
// ─── Slide helpers ────────────────────────────────────────────────────────────
// Full-slide dark navy background
function addBg(slide, color = BG_DARK) {
slide.addShape("rect", { x: 0, y: 0, w: SLIDE_W, h: SLIDE_H, fill: { color } });
}
// Top accent bar
function addTopBar(slide, accentColor = GOLD) {
slide.addShape("rect", { x: 0, y: 0, w: SLIDE_W, h: 0.08, fill: { color: accentColor } });
}
// Bottom accent bar
function addBottomBar(slide, accentColor = GOLD) {
slide.addShape("rect", { x: 0, y: SLIDE_H - 0.08, w: SLIDE_W, h: 0.08, fill: { color: accentColor } });
}
// Section title strip
function addTitleStrip(slide, title, y = 0.28, bgColor = BG_MID, textColor = GOLD) {
slide.addShape("rect", { x: 0, y, w: SLIDE_W, h: 0.72, fill: { color: bgColor } });
slide.addText(title, {
x: 0.4, y, w: SLIDE_W - 0.8, h: 0.72,
fontSize: 22, bold: true, color: textColor,
fontFace: "Calibri", valign: "middle", margin: 0
});
}
// Decorative side strip
function addSideStrip(slide, x, color = GOLD, opacity = 0.3) {
slide.addShape("rect", { x, y: 0, w: 0.06, h: SLIDE_H, fill: { color, transparency: Math.round(opacity * 100) } });
}
// Small dot decorations (top-right corner)
function addCornerDots(slide) {
const positions = [[12.7, 0.3], [12.9, 0.5], [12.5, 0.55]];
positions.forEach(([cx, cy]) => {
slide.addShape("ellipse", { x: cx, y: cy, w: 0.15, h: 0.15, fill: { color: GOLD, transparency: 60 } });
});
}
// Card / info box
function addCard(slide, x, y, w, h, fillColor = BG_CARD, borderColor = GOLD) {
slide.addShape("rect", {
x, y, w, h,
fill: { color: fillColor },
line: { color: borderColor, width: 1 }
});
}
// Slide number
function addSlideNum(slide, num, total) {
slide.addText(`${num} / ${total}`, {
x: SLIDE_W - 1.2, y: SLIDE_H - 0.38, w: 1.0, h: 0.3,
fontSize: 9, color: GOLD_LIGHT, align: "right", fontFace: "Calibri", margin: 0
});
}
// ─── Create Presentation ─────────────────────────────────────────────────────
const pres = new pptxgen();
pres.layout = "LAYOUT_WIDE";
pres.title = "Colorimeter";
pres.author = "Generated by Orris";
const TOTAL = 10;
// ════════════════════════════════════════════════════════════
// SLIDE 1 – Title slide
// ════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
addBg(s, BG_DARK);
// Bold gold vertical stripe left
s.addShape("rect", { x: 0, y: 0, w: 0.45, h: SLIDE_H, fill: { color: GOLD } });
// Diagonal accent shape
s.addShape("rect", {
x: 0.45, y: 0, w: 0.25, h: SLIDE_H,
fill: { color: GOLD_LIGHT, transparency: 60 }
});
// Right image panel
const imgData = img(2);
if (imgData) {
s.addImage({ data: imgData, x: 7.8, y: 1.0, w: 5.0, h: 5.0 });
// overlay tint over image
s.addShape("rect", { x: 7.8, y: 1.0, w: 5.0, h: 5.0, fill: { color: BG_DARK, transparency: 40 } });
}
// Main title
s.addText("COLORIMETER", {
x: 0.9, y: 1.6, w: 7.0, h: 1.2,
fontSize: 54, bold: true, color: WHITE,
fontFace: "Calibri", charSpacing: 8, margin: 0
});
// Gold underline bar
s.addShape("rect", { x: 0.9, y: 2.9, w: 5.5, h: 0.06, fill: { color: GOLD } });
// Subtitle
s.addText("Principle, Components & Clinical Applications", {
x: 0.9, y: 3.1, w: 7.0, h: 0.6,
fontSize: 18, color: GOLD_LIGHT, italic: true,
fontFace: "Calibri", margin: 0
});
// Tag line
s.addText("A fundamental tool in clinical biochemistry", {
x: 0.9, y: 3.85, w: 7.0, h: 0.4,
fontSize: 13, color: LIGHT_BLUE, fontFace: "Calibri", margin: 0
});
// Bottom ribbon
s.addShape("rect", { x: 0, y: SLIDE_H - 0.7, w: SLIDE_W, h: 0.7, fill: { color: BG_MID } });
s.addText("Clinical Biochemistry | Analytical Instruments", {
x: 0.9, y: SLIDE_H - 0.65, w: 9, h: 0.6,
fontSize: 11, color: GOLD_LIGHT, fontFace: "Calibri", valign: "middle", margin: 0
});
addSlideNum(s, 1, TOTAL);
}
// ════════════════════════════════════════════════════════════
// SLIDE 2 – Introduction & History
// ════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
addBg(s);
addTopBar(s);
addBottomBar(s);
addSideStrip(s, 0, GOLD, 0.4);
addCornerDots(s);
addTitleStrip(s, "Introduction & History", 0.25);
addSlideNum(s, 2, TOTAL);
// Definition card
addCard(s, 0.5, 1.15, 8.0, 1.15);
s.addText([
{ text: "COLORIMETER", options: { bold: true, color: GOLD } },
{ text: " — An instrument that measures the ", options: { color: WHITE } },
{ text: "absorbance", options: { bold: true, color: TEAL } },
{ text: " or ", options: { color: WHITE } },
{ text: "transmittance", options: { bold: true, color: TEAL } },
{ text: " of light through a colored solution to determine its ", options: { color: WHITE } },
{ text: "concentration.", options: { bold: true, color: GOLD_LIGHT } }
], { x: 0.65, y: 1.2, w: 7.7, h: 1.05, fontSize: 15, fontFace: "Calibri", valign: "middle" });
// Timeline
const timeline = [
{ year: "1728", name: "Johann Heinrich Lambert", fact: "Described how absorbance is proportional to path length (Lambert's Law)", color: TEAL },
{ year: "1825", name: "August Beer", fact: "Showed absorbance is proportional to concentration (Beer's Law)", color: GREEN },
{ year: "1852", name: "Beer-Lambert Law", fact: "Combined law: A = εcl — foundation of colorimetry", color: GOLD }
];
timeline.forEach((item, i) => {
const yy = 2.5 + i * 1.45;
// connector dot
s.addShape("ellipse", { x: 0.55, y: yy + 0.25, w: 0.3, h: 0.3, fill: { color: item.color } });
// line
if (i < 2) s.addShape("rect", { x: 0.67, y: yy + 0.55, w: 0.06, h: 0.9, fill: { color: item.color, transparency: 50 } });
// year badge
addCard(s, 1.0, yy, 1.0, 0.5, item.color, item.color);
s.addText(item.year, { x: 1.0, y: yy, w: 1.0, h: 0.5, fontSize: 13, bold: true, color: BG_DARK, align: "center", valign: "middle", margin: 0 });
// content
s.addText(item.name, { x: 2.2, y: yy + 0.0, w: 8.5, h: 0.28, fontSize: 13, bold: true, color: WHITE, fontFace: "Calibri", margin: 0 });
s.addText(item.fact, { x: 2.2, y: yy + 0.28, w: 8.5, h: 0.28, fontSize: 11, color: LIGHT_BLUE, fontFace: "Calibri", italic: true, margin: 0 });
});
}
// ════════════════════════════════════════════════════════════
// SLIDE 3 – Beer-Lambert Law (Principle)
// ════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
addBg(s);
addTopBar(s);
addBottomBar(s);
addSideStrip(s, 0, GOLD, 0.4);
addCornerDots(s);
addTitleStrip(s, "Principle: Beer-Lambert Law", 0.25);
addSlideNum(s, 3, TOTAL);
// Law formula box – centered
addCard(s, 2.2, 1.15, 8.9, 1.1, "102040", GOLD);
s.addText("A = ε × c × l", {
x: 2.2, y: 1.15, w: 8.9, h: 1.1,
fontSize: 38, bold: true, color: GOLD, align: "center", valign: "middle",
fontFace: "Courier New", margin: 0
});
// Legend
const legend = [
{ sym: "A", desc: "Absorbance (dimensionless)", color: GOLD },
{ sym: "ε", desc: "Molar absorptivity (L·mol⁻¹·cm⁻¹)", color: TEAL },
{ sym: "c", desc: "Concentration (mol/L)", color: GREEN },
{ sym: "l", desc: "Path length (cm) — fixed by cuvette", color: LIGHT_BLUE }
];
legend.forEach((item, i) => {
const xx = 0.5 + (i % 2) * 6.4;
const yy = 2.55 + Math.floor(i / 2) * 0.75;
addCard(s, xx, yy, 6.0, 0.6, BG_CARD, item.color);
s.addText(item.sym, { x: xx + 0.1, y: yy, w: 0.5, h: 0.6, fontSize: 20, bold: true, color: item.color, align: "center", valign: "middle", fontFace: "Courier New", margin: 0 });
s.addText(item.desc, { x: xx + 0.7, y: yy, w: 5.1, h: 0.6, fontSize: 13, color: WHITE, valign: "middle", fontFace: "Calibri", margin: 0 });
});
// Two laws boxes
const laws = [
{ title: "Beer's Law", text: "Absorbance is DIRECTLY proportional to the CONCENTRATION of the solution\n(A ∝ c)", color: TEAL },
{ title: "Lambert's Law", text: "Absorbance is DIRECTLY proportional to the PATH LENGTH of the solution\n(A ∝ l)", color: GREEN }
];
laws.forEach((law, i) => {
const xx = 0.5 + i * 6.4;
addCard(s, xx, 4.25, 6.2, 2.9, BG_CARD, law.color);
s.addShape("rect", { x: xx, y: 4.25, w: 6.2, h: 0.45, fill: { color: law.color } });
s.addText(law.title, { x: xx + 0.1, y: 4.25, w: 6.0, h: 0.45, fontSize: 14, bold: true, color: BG_DARK, align: "center", valign: "middle", margin: 0 });
s.addText(law.text, { x: xx + 0.2, y: 4.75, w: 5.8, h: 2.3, fontSize: 13, color: WHITE, fontFace: "Calibri", valign: "middle" });
});
}
// ════════════════════════════════════════════════════════════
// SLIDE 4 – Components / Parts
// ════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
addBg(s);
addTopBar(s);
addBottomBar(s);
addSideStrip(s, 0, GOLD, 0.4);
addCornerDots(s);
addTitleStrip(s, "Components of a Colorimeter", 0.25);
addSlideNum(s, 4, TOTAL);
const partsImg = img(0);
if (partsImg) {
s.addImage({ data: partsImg, x: 7.1, y: 1.15, w: 5.9, h: 6.0 });
s.addShape("rect", { x: 7.1, y: 1.15, w: 5.9, h: 6.0, fill: { color: BG_DARK, transparency: 20 } });
}
const parts = [
{ n: "01", name: "Light Source", desc: "Tungsten lamp (400–760 nm visible range)", color: GOLD },
{ n: "02", name: "Adjustable Slit", desc: "Controls beam width entering the system", color: TEAL },
{ n: "03", name: "Condensing Lens", desc: "Focuses light into a parallel beam", color: GREEN },
{ n: "04", name: "Color Filter", desc: "Selects wavelength complementary to solution color", color: LIGHT_BLUE },
{ n: "05", name: "Cuvette / Sample Holder", desc: "Fixed diameter; quartz for UV range measurements", color: RED_SOFT },
{ n: "06", name: "Photodetector", desc: "Photocell converts transmitted light to electrical signal", color: "CE93D8" },
{ n: "07", name: "Display / Galvanometer", desc: "Shows absorbance or % transmittance value", color: GOLD_LIGHT }
];
parts.forEach((p, i) => {
const yy = 1.2 + i * 0.82;
s.addShape("ellipse", { x: 0.45, y: yy + 0.1, w: 0.4, h: 0.4, fill: { color: p.color } });
s.addText(p.n, { x: 0.45, y: yy + 0.1, w: 0.4, h: 0.4, fontSize: 9, bold: true, color: BG_DARK, align: "center", valign: "middle", margin: 0 });
s.addText(p.name, { x: 1.0, y: yy, w: 5.9, h: 0.28, fontSize: 13, bold: true, color: p.color, fontFace: "Calibri", margin: 0 });
s.addText(p.desc, { x: 1.0, y: yy + 0.28, w: 5.9, h: 0.28, fontSize: 11, color: LIGHT_BLUE, fontFace: "Calibri", italic: true, margin: 0 });
});
}
// ════════════════════════════════════════════════════════════
// SLIDE 5 – How it Works (Operation)
// ════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
addBg(s);
addTopBar(s);
addBottomBar(s);
addSideStrip(s, 0, GOLD, 0.4);
addCornerDots(s);
addTitleStrip(s, "How a Colorimeter Works", 0.25);
addSlideNum(s, 5, TOTAL);
// Diagram image
const diaImg = img(1);
if (diaImg) {
s.addImage({ data: diaImg, x: 0.5, y: 1.1, w: 5.5, h: 3.3 });
}
// Flow steps on right
const steps = [
{ n: 1, text: "Tungsten lamp emits white light (400–760 nm)", color: GOLD },
{ n: 2, text: "Slit narrows beam; lens collimates it", color: TEAL },
{ n: 3, text: "Color filter isolates desired wavelength", color: GREEN },
{ n: 4, text: "Monochromatic beam passes through cuvette", color: LIGHT_BLUE },
{ n: 5, text: "Colored solution absorbs part of the light", color: RED_SOFT },
{ n: 6, text: "Transmitted light hits photocell (detector)", color: "CE93D8" },
{ n: 7, text: "Electrical signal displayed as A or %T", color: GOLD_LIGHT }
];
steps.forEach((st, i) => {
const yy = 1.15 + i * 0.85;
addCard(s, 6.3, yy, 6.6, 0.72, BG_CARD, st.color);
s.addShape("ellipse", { x: 6.35, y: yy + 0.18, w: 0.36, h: 0.36, fill: { color: st.color } });
s.addText(String(st.n), { x: 6.35, y: yy + 0.18, w: 0.36, h: 0.36, fontSize: 11, bold: true, color: BG_DARK, align: "center", valign: "middle", margin: 0 });
s.addText(st.text, { x: 6.85, y: yy, w: 5.9, h: 0.72, fontSize: 12, color: WHITE, fontFace: "Calibri", valign: "middle" });
});
// Formula label below image
addCard(s, 0.5, 4.6, 5.5, 1.2, "102040", GOLD);
s.addText("Key Formula:", { x: 0.65, y: 4.65, w: 5.1, h: 0.35, fontSize: 12, bold: true, color: GOLD, fontFace: "Calibri", margin: 0 });
s.addText("C(unknown) = (OD Test − OD Blank) × C(standard)\n (OD Standard − OD Blank)", {
x: 0.65, y: 5.0, w: 5.3, h: 0.75, fontSize: 10.5, color: WHITE, fontFace: "Courier New"
});
}
// ════════════════════════════════════════════════════════════
// SLIDE 6 – Cuvette Details
// ════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
addBg(s);
addTopBar(s);
addBottomBar(s);
addSideStrip(s, 0, GOLD, 0.4);
addCornerDots(s);
addTitleStrip(s, "Cuvette — Sample Holder", 0.25);
addSlideNum(s, 6, TOTAL);
const cuvImg = img(4);
if (cuvImg) {
s.addImage({ data: cuvImg, x: 8.5, y: 1.2, w: 4.3, h: 5.8 });
s.addShape("rect", { x: 8.5, y: 1.2, w: 4.3, h: 5.8, fill: { color: BG_DARK, transparency: 30 } });
}
const props = [
{ label: "Shape", value: "Usually rectangular or cylindrical", color: GOLD },
{ label: "Diameter", value: "Fixed — ensures constant path length (l)", color: TEAL },
{ label: "Material (Visible)", value: "Borosilicate glass or plastic", color: GREEN },
{ label: "Material (UV range)", value: "Quartz (transparent to UV light)", color: LIGHT_BLUE },
{ label: "Volume", value: "Typically 1–4 mL capacity", color: RED_SOFT },
{ label: "Cleaning", value: "Must be spotless — smudges cause error", color: "CE93D8" }
];
props.forEach((p, i) => {
const yy = 1.25 + i * 0.95;
addCard(s, 0.5, yy, 7.8, 0.82, BG_CARD, p.color);
s.addShape("rect", { x: 0.5, y: yy, w: 1.8, h: 0.82, fill: { color: p.color } });
s.addText(p.label, { x: 0.5, y: yy, w: 1.8, h: 0.82, fontSize: 12, bold: true, color: BG_DARK, align: "center", valign: "middle", margin: 0 });
s.addText(p.value, { x: 2.45, y: yy, w: 5.7, h: 0.82, fontSize: 13, color: WHITE, fontFace: "Calibri", valign: "middle" });
});
// Note
addCard(s, 0.5, 7.0, 7.8, 0.35, "102040", GOLD);
s.addText("Note: The blank/reagent blank is always measured first to zero out background absorption.", {
x: 0.6, y: 7.0, w: 7.6, h: 0.35, fontSize: 10.5, color: GOLD_LIGHT, fontFace: "Calibri", italic: true, valign: "middle"
});
}
// ════════════════════════════════════════════════════════════
// SLIDE 7 – Types of Analysis
// ════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
addBg(s);
addTopBar(s);
addBottomBar(s);
addSideStrip(s, 0, GOLD, 0.4);
addCornerDots(s);
addTitleStrip(s, "Types of Colorimetric Analysis", 0.25);
addSlideNum(s, 7, TOTAL);
// End-point card
addCard(s, 0.5, 1.15, 5.9, 5.7, BG_CARD, TEAL);
s.addShape("rect", { x: 0.5, y: 1.15, w: 5.9, h: 0.52, fill: { color: TEAL } });
s.addText("1. End-Point Analysis", { x: 0.6, y: 1.15, w: 5.7, h: 0.52, fontSize: 15, bold: true, color: BG_DARK, valign: "middle", margin: 0 });
const epPoints = [
"Reaction allowed to go to COMPLETION before reading",
"Incubation at 37°C for 10 minutes",
"Single absorbance reading taken",
"Used for: Glucose, Urea, Creatinine, Bilirubin, Proteins",
"Simple, fast, widely used in clinical labs",
"Result compared to blank and standard"
];
epPoints.forEach((pt, i) => {
s.addText([
{ text: "• ", options: { color: TEAL, bold: true } },
{ text: pt, options: { color: WHITE } }
], { x: 0.7, y: 1.75 + i * 0.73, w: 5.5, h: 0.65, fontSize: 12, fontFace: "Calibri", valign: "middle" });
});
// Kinetic card
addCard(s, 6.9, 1.15, 5.9, 5.7, BG_CARD, GREEN);
s.addShape("rect", { x: 6.9, y: 1.15, w: 5.9, h: 0.52, fill: { color: GREEN } });
s.addText("2. Kinetic Analysis", { x: 7.0, y: 1.15, w: 5.7, h: 0.52, fontSize: 15, bold: true, color: BG_DARK, valign: "middle", margin: 0 });
const kinPoints = [
"Measures RATE of change in absorbance over time",
"Readings taken at 2 and 3 minutes after mixing",
"Delta OD (ΔOD) per minute is calculated",
"Used for: Enzymes — AST/SGOT, ALT/SGPT",
"Reflects enzyme catalytic activity directly",
"More sensitive to reaction dynamics"
];
kinPoints.forEach((pt, i) => {
s.addText([
{ text: "• ", options: { color: GREEN, bold: true } },
{ text: pt, options: { color: WHITE } }
], { x: 7.1, y: 1.75 + i * 0.73, w: 5.5, h: 0.65, fontSize: 12, fontFace: "Calibri", valign: "middle" });
});
// Bottom note
addCard(s, 0.5, 7.0, 12.3, 0.35, "102040", GOLD);
s.addText("Both methods use the same Beer-Lambert principle — they differ only in WHEN the measurement is taken.", {
x: 0.65, y: 7.0, w: 12.0, h: 0.35, fontSize: 11, color: GOLD_LIGHT, italic: true, fontFace: "Calibri", valign: "middle"
});
}
// ════════════════════════════════════════════════════════════
// SLIDE 8 – Clinical Applications
// ════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
addBg(s);
addTopBar(s);
addBottomBar(s);
addSideStrip(s, 0, GOLD, 0.4);
addCornerDots(s);
addTitleStrip(s, "Clinical Applications", 0.25);
addSlideNum(s, 8, TOTAL);
const categories = [
{
title: "Carbohydrates",
items: ["Glucose (fasting/PP/RBS)", "HbA1c (glycated Hb)"],
color: GOLD, x: 0.5, y: 1.15
},
{
title: "Renal Function",
items: ["Urea (BUN)", "Creatinine", "Uric Acid"],
color: TEAL, x: 4.7, y: 1.15
},
{
title: "Liver Function",
items: ["Total Bilirubin", "Direct Bilirubin", "Serum Proteins"],
color: GREEN, x: 9.0, y: 1.15
},
{
title: "Lipid Profile",
items: ["Total Cholesterol", "Triglycerides", "HDL/LDL (calc)"],
color: LIGHT_BLUE, x: 0.5, y: 4.0
},
{
title: "Enzymes",
items: ["AST / SGOT", "ALT / SGPT", "ALP, LDH"],
color: RED_SOFT, x: 4.7, y: 4.0
},
{
title: "Others",
items: ["Serum Albumin", "Minerals (Ca, Mg, Fe)", "Total Proteins"],
color: "CE93D8", x: 9.0, y: 4.0
}
];
categories.forEach(cat => {
const cardH = 2.6;
addCard(s, cat.x, cat.y, 3.9, cardH, BG_CARD, cat.color);
s.addShape("rect", { x: cat.x, y: cat.y, w: 3.9, h: 0.48, fill: { color: cat.color } });
s.addText(cat.title, {
x: cat.x + 0.1, y: cat.y, w: 3.7, h: 0.48,
fontSize: 13, bold: true, color: BG_DARK, align: "center", valign: "middle", margin: 0
});
cat.items.forEach((item, i) => {
s.addText([
{ text: "▸ ", options: { color: cat.color, bold: true } },
{ text: item, options: { color: WHITE } }
], {
x: cat.x + 0.2, y: cat.y + 0.56 + i * 0.6, w: 3.5, h: 0.52,
fontSize: 12, fontFace: "Calibri", valign: "middle"
});
});
});
}
// ════════════════════════════════════════════════════════════
// SLIDE 9 – Colorimeter vs Spectrophotometer
// ════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
addBg(s);
addTopBar(s);
addBottomBar(s);
addSideStrip(s, 0, GOLD, 0.4);
addCornerDots(s);
addTitleStrip(s, "Colorimeter vs Spectrophotometer", 0.25);
addSlideNum(s, 9, TOTAL);
// Column headers
const headers = ["Feature", "Colorimeter", "Spectrophotometer"];
const colW = [3.4, 4.5, 4.5];
const colX = [0.5, 3.95, 8.5];
const headerColors = [BG_MID, TEAL, GOLD];
headers.forEach((h, i) => {
addCard(s, colX[i], 1.15, colW[i], 0.55, headerColors[i], headerColors[i]);
s.addText(h, {
x: colX[i] + 0.1, y: 1.15, w: colW[i] - 0.2, h: 0.55,
fontSize: 13, bold: true, color: i === 0 ? GOLD_LIGHT : BG_DARK,
align: "center", valign: "middle", margin: 0
});
});
const rows = [
["Light source", "Tungsten lamp", "Tungsten / Deuterium / Xenon"],
["Wavelength sel.", "Glass / Gelatin filters", "Diffraction gratings (prism)"],
["Wavelength range","Visible only (400–760 nm)", "UV + Visible + IR (200–900+ nm)"],
["Cuvettes", "Glass or plastic", "Quartz (mandatory for UV)"],
["Sensitivity", "Standard", "~1000× more sensitive"],
["Cost", "Low", "~100× more expensive"],
["Applications", "Routine clinical tests", "Research, specialized assays"]
];
rows.forEach((row, ri) => {
const yy = 1.75 + ri * 0.75;
const rowBg = ri % 2 === 0 ? BG_CARD : BG_MID;
row.forEach((cell, ci) => {
addCard(s, colX[ci], yy, colW[ci], 0.7, rowBg, rowBg);
const cellColor = ci === 0 ? GOLD_LIGHT : ci === 1 ? TEAL : WHITE;
s.addText(cell, {
x: colX[ci] + 0.15, y: yy, w: colW[ci] - 0.3, h: 0.7,
fontSize: 11.5, color: cellColor, fontFace: "Calibri", valign: "middle"
});
});
});
}
// ════════════════════════════════════════════════════════════
// SLIDE 10 – Summary / Thank You
// ════════════════════════════════════════════════════════════
{
const s = pres.addSlide();
addBg(s, BG_DARK);
// Left gold stripe
s.addShape("rect", { x: 0, y: 0, w: 0.45, h: SLIDE_H, fill: { color: GOLD } });
// Right image
const finalImg = img(3);
if (finalImg) {
s.addImage({ data: finalImg, x: 7.5, y: 0.5, w: 5.5, h: 6.5 });
s.addShape("rect", { x: 7.5, y: 0.5, w: 5.5, h: 6.5, fill: { color: BG_DARK, transparency: 45 } });
}
// Title
s.addText("Key Takeaways", {
x: 0.8, y: 0.4, w: 6.5, h: 0.7,
fontSize: 28, bold: true, color: GOLD, fontFace: "Calibri", charSpacing: 4, margin: 0
});
s.addShape("rect", { x: 0.8, y: 1.15, w: 4.5, h: 0.05, fill: { color: GOLD } });
const takeaways = [
{ icon: "A = εcl", text: "Beer-Lambert Law: Absorbance ∝ Concentration × Path Length", color: GOLD },
{ icon: "⚙", text: "Key parts: Lamp → Slit → Lens → Filter → Cuvette → Detector → Display", color: TEAL },
{ icon: "🔬", text: "End-point analysis (37°C, 10 min) for metabolites; kinetic for enzymes", color: GREEN },
{ icon: "🏥", text: "Measures glucose, urea, creatinine, bilirubin, lipids, enzymes and more", color: LIGHT_BLUE },
{ icon: "📊", text: "Spectrophotometer is 1000× more sensitive but 100× more costly", color: RED_SOFT }
];
takeaways.forEach((t, i) => {
const yy = 1.35 + i * 1.12;
addCard(s, 0.8, yy, 6.5, 0.95, BG_CARD, t.color);
addCard(s, 0.8, yy, 1.0, 0.95, t.color, t.color);
s.addText(t.icon, { x: 0.8, y: yy, w: 1.0, h: 0.95, fontSize: t.icon.length > 3 ? 9 : 14, bold: true, color: BG_DARK, align: "center", valign: "middle", margin: 0, fontFace: "Courier New" });
s.addText(t.text, { x: 1.95, y: yy, w: 5.2, h: 0.95, fontSize: 12, color: WHITE, fontFace: "Calibri", valign: "middle" });
});
// Thank you ribbon
s.addShape("rect", { x: 0, y: SLIDE_H - 0.75, w: SLIDE_W, h: 0.75, fill: { color: BG_MID } });
s.addText("Thank You", {
x: 0.8, y: SLIDE_H - 0.72, w: 5, h: 0.68,
fontSize: 22, bold: true, color: GOLD, fontFace: "Calibri", valign: "middle", charSpacing: 5, margin: 0
});
s.addText("Clinical Biochemistry | Colorimetry & Spectrophotometry", {
x: 5.5, y: SLIDE_H - 0.72, w: 7.3, h: 0.68,
fontSize: 12, color: LIGHT_BLUE, fontFace: "Calibri", align: "right", valign: "middle", margin: 0
});
addSlideNum(s, 10, TOTAL);
}
// ─── Write File ───────────────────────────────────────────────────────────────
const outPath = path.resolve(__dirname, "Colorimeter.pptx");
pres.writeFile({ fileName: outPath })
.then(() => console.log(`\n✅ Saved: ${outPath}`))
.catch(err => { console.error("Write error:", err); process.exit(1); });
cd /home/daytona/workspace/colorimeter-ppt && node create_presentation.js 2>&1
cd /home/daytona/workspace/colorimeter-ppt && node -e " const { execSync } = require('child_process'); const fs = require('fs'); const urls = [ 'https://microbenotes.com/wp-content/uploads/2019/10/Parts-of-Colorimeter.jpg', 'https://laboratorytests.org/wp-content/uploads/2022/08/Colorimeter-principle-instrumentation-scaled.jpg', 'https://cdn1.byjus.com/wp-content/uploads/2022/02/colorimeter-instrument.png', 'https://laboratorytests.org/wp-content/uploads/2022/08/Colorimeter-scaled.jpg', 'https://microbenotes.com/wp-content/uploads/2019/10/Colorimeter.jpg' ]; try { const raw = execSync('node /home/daytona/skills/shared/scripts/fetch_images.js ' + urls.map(u => '\"' + u + '\"').join(' '), { maxBuffer: 100*1024*1024, timeout: 90000 }).toString(); const images = JSON.parse(raw); images.forEach((img, i) => { if (!img.error && img.base64) { const b64 = img.base64.replace(/^data:[^;]+;base64,/, ''); const ext = img.base64.startsWith('data:image/png') ? 'png' : 'jpg'; fs.writeFileSync('img_' + i + '.' + ext, Buffer.from(b64, 'base64')); console.log('Saved img_' + i + '.' + ext); } else { console.log('Error img ' + i + ': ' + img.error); } }); } catch(e) { console.error('FAILED:', e.message); } " 2>&1
using the three files as source make a power point presentation on topic Colorimeter. the presentation should have a good background.
python3 -c " import pdfplumber, json paths = [ '/home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/colr1 (1).pdf', '/home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/color (1).pdf', '/home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/colorimetry (1).pdf' ] for p in paths: print('==='*20) print('FILE:', p.split('/')[-1]) print('==='*20) with pdfplumber.open(p) as pdf: for i, page in enumerate(pdf.pages): t = page.extract_text() if t: print(f'--- Page {i+1} ---') print(t) " 2>&1 | head -500
python3 -c " from pypdf import PdfReader paths = [ '/home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/colr1 (1).pdf', '/home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/color (1).pdf', '/home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/colorimetry (1).pdf' ] for p in paths: r = PdfReader(p) print(f'{p.split(\"/\")[-1]}: {len(r.pages)} pages') for i, pg in enumerate(r.pages): t = pg.extract_text() if t and t.strip(): print(f' Page {i+1} text preview: {t[:300]}') else: print(f' Page {i+1}: (no text layer)') " 2>&1
python3 -c " import subprocess, os # Convert all PDFs to images using pdftoppm pdfs = [ ('/home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/colr1 (1).pdf', 'colr1'), ('/home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/color (1).pdf', 'color1'), ('/home/daytona/workspace/attachments/b4b3b354-f077-47e4-92b8-32698d85bec7/colorimetry (1).pdf', 'colorimetry1'), ] os.makedirs('/home/daytona/workspace/colorimeter-ppt/ocr_imgs', exist_ok=True) for pdf_path, name in pdfs: out = subprocess.run(['pdftoppm', '-r', '200', '-png', pdf_path, f'/home/daytona/workspace/colorimeter-ppt/ocr_imgs/{name}'], capture_output=True, text=True) print(f'{name}: returncode={out.returncode} {out.stderr[:100]}') import os files = sorted(os.listdir('/home/daytona/workspace/colorimeter-ppt/ocr_imgs')) print('Images:', files) " 2>&1
python3 -c " import pytesseract from PIL import Image import os img_dir = '/home/daytona/workspace/colorimeter-ppt/ocr_imgs' files = sorted(os.listdir(img_dir)) for f in files: path = os.path.join(img_dir, f) img = Image.open(path) text = pytesseract.image_to_string(img) print(f'=== {f} ===') print(text[:3000]) print() " 2>&1
~/colorimeter-ppt/create_ppt.js
/**
* Colorimeter Presentation — PptxGenJS
* Source: 3 PDF files (OCR extracted)
* Theme: Dark navy / teal / gold scientific design
*/
const pptxgen = require("pptxgenjs");
const path = require("path");
// ─── Theme ────────────────────────────────────────────────────────────────────
const C = {
navyDeep: "0A1628",
navy: "0D1F3C",
navyMid: "122B52",
navyCard: "1A3A6B",
teal: "00B4D8",
tealDark: "0096B7",
gold: "F4A429",
goldLight: "FFD580",
green: "52C98D",
red: "F07070",
purple: "B39DDB",
white: "FFFFFF",
grey: "B0C4DE",
lightBlue: "90CAF9",
orange: "FF9800",
};
const W = 13.3; // slide width (LAYOUT_WIDE)
const H = 7.5; // slide height
// ─── Helpers ──────────────────────────────────────────────────────────────────
function bg(s, color = C.navyDeep) {
s.addShape("rect", { x:0, y:0, w:W, h:H, fill:{ color } });
}
function topBar(s, col = C.gold, thick = 0.07) {
s.addShape("rect", { x:0, y:0, w:W, h:thick, fill:{ color:col } });
}
function botBar(s, col = C.teal, thick = 0.07) {
s.addShape("rect", { x:0, y:H-thick, w:W, h:thick, fill:{ color:col } });
}
function titleStrip(s, text, y=0.22, stripH=0.68, bgCol=C.navyMid, textCol=C.gold) {
s.addShape("rect", { x:0, y, w:W, h:stripH, fill:{ color:bgCol } });
// Left accent notch
s.addShape("rect", { x:0, y, w:0.35, h:stripH, fill:{ color:C.gold } });
s.addText(text, {
x:0.55, y, w:W-0.7, h:stripH,
fontSize:21, bold:true, color:textCol,
fontFace:"Calibri", valign:"middle", margin:0
});
}
function card(s, x, y, w, h, fill=C.navyCard, border=C.teal, borderW=0.8) {
s.addShape("rect", { x, y, w, h, fill:{ color:fill }, line:{ color:border, width:borderW } });
}
function dotDeco(s) {
// Decorative circles top-right
[[12.55,0.22,0.18],[12.80,0.45,0.13],[12.45,0.50,0.10]].forEach(([cx,cy,r]) => {
s.addShape("ellipse", { x:cx, y:cy, w:r, h:r, fill:{ color:C.gold, transparency:55 } });
});
}
function slideNum(s, n, total) {
s.addText(`${n} / ${total}`, {
x:W-1.4, y:H-0.38, w:1.2, h:0.3,
fontSize:9, color:C.goldLight, align:"right",
fontFace:"Calibri", margin:0
});
}
function leftStripe(s, col=C.teal, w=0.07) {
s.addShape("rect", { x:0, y:0, w, h:H, fill:{ color:col, transparency:30 } });
}
// ─── Presentation ─────────────────────────────────────────────────────────────
const pres = new pptxgen();
pres.layout = "LAYOUT_WIDE";
pres.title = "Colorimeter";
pres.author = "Orris AI";
pres.subject = "Clinical Biochemistry";
const TOTAL = 11;
// ══════════════════════════════════════════════════
// SLIDE 1 — Title
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s, C.navyDeep);
// Large left gold band
s.addShape("rect", { x:0, y:0, w:0.55, h:H, fill:{ color:C.gold } });
s.addShape("rect", { x:0.55, y:0, w:0.18, h:H, fill:{ color:C.goldLight, transparency:60 } });
// Background teal splash (right side)
s.addShape("ellipse", { x:8.0, y:-1.5, w:6.5, h:6.5, fill:{ color:C.teal, transparency:88 } });
s.addShape("ellipse", { x:9.5, y:3.5, w:5.0, h:5.0, fill:{ color:C.navyCard, transparency:30 } });
// Main title
s.addText("COLORIMETER", {
x:1.0, y:1.3, w:9.5, h:1.5,
fontSize:62, bold:true, color:C.white,
fontFace:"Calibri", charSpacing:10, margin:0
});
// Gold underline
s.addShape("rect", { x:1.0, y:2.95, w:6.5, h:0.07, fill:{ color:C.gold } });
// Subtitle
s.addText("Principle · Instrumentation · Applications", {
x:1.0, y:3.1, w:9.5, h:0.7,
fontSize:20, color:C.teal, italic:true,
fontFace:"Calibri", charSpacing:2, margin:0
});
// Tag
s.addText("A fundamental analytical instrument in Clinical Biochemistry", {
x:1.0, y:3.9, w:9.0, h:0.5,
fontSize:14, color:C.grey,
fontFace:"Calibri", margin:0
});
// Bottom ribbon
s.addShape("rect", { x:0, y:H-0.72, w:W, h:0.72, fill:{ color:C.navyMid } });
s.addText("Clinical Biochemistry | Analytical Instruments | Beer-Lambert Law", {
x:0.9, y:H-0.68, w:10, h:0.62,
fontSize:12, color:C.goldLight,
fontFace:"Calibri", valign:"middle", margin:0
});
// Source note
s.addText("Sources: Textbook of Biochemistry · Essentials of Biochemistry", {
x:W-5.5, y:H-0.68, w:5.0, h:0.62,
fontSize:9.5, color:C.grey, align:"right",
fontFace:"Calibri", italic:true, valign:"middle", margin:0
});
slideNum(s, 1, TOTAL);
}
// ══════════════════════════════════════════════════
// SLIDE 2 — Introduction & Historical Background
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s);
topBar(s, C.gold);
botBar(s, C.teal);
leftStripe(s, C.gold);
dotDeco(s);
titleStrip(s, "Introduction & Historical Background");
slideNum(s, 2, TOTAL);
// Definition box
card(s, 0.5, 1.1, 12.3, 1.2, "0D2A4A", C.gold, 1.2);
s.addShape("rect", { x:0.5, y:1.1, w:0.32, h:1.2, fill:{ color:C.gold } });
s.addText([
{ text:"COLORIMETER ", options:{ bold:true, color:C.gold } },
{ text:"— An instrument that measures the ", options:{ color:C.white } },
{ text:"absorbance", options:{ bold:true, color:C.teal } },
{ text:" or ", options:{ color:C.white } },
{ text:"transmittance", options:{ bold:true, color:C.teal } },
{ text:" of light through a colored solution to determine its ", options:{ color:C.white } },
{ text:"concentration.", options:{ bold:true, color:C.goldLight } },
], { x:1.05, y:1.15, w:11.5, h:1.1, fontSize:15, fontFace:"Calibri", valign:"middle" });
// Principle summary
s.addText("Core Principle:", {
x:0.5, y:2.55, w:4, h:0.4,
fontSize:14, bold:true, color:C.teal, fontFace:"Calibri", margin:0
});
s.addText(
"Colored solutions absorb light at specific wavelengths. The amount of light absorbed " +
"or transmitted is governed by the Beer-Lambert Law. The color intensity is DIRECTLY " +
"PROPORTIONAL to the concentration of the colored substance in solution.",
{ x:0.5, y:2.95, w:12.3, h:1.05, fontSize:13.5, color:C.grey, fontFace:"Calibri" }
);
// Timeline cards
const timeline = [
{ year:"1728–1777", name:"Johann Heinrich Lambert", contrib:"Lambert's Law — Absorbance ∝ Path Length", col:C.teal },
{ year:"1825–1863", name:"August Beer", contrib:"Beer's Law — Absorbance ∝ Concentration", col:C.green },
{ year:"1852", name:"Beer-Lambert Law", contrib:"Combined Law: A = ε · c · l (foundation of colorimetry)", col:C.gold },
];
timeline.forEach((item, i) => {
const xx = 0.5 + i * 4.3;
card(s, xx, 4.15, 4.0, 2.85, C.navyCard, item.col, 1.0);
s.addShape("rect", { x:xx, y:4.15, w:4.0, h:0.48, fill:{ color:item.col } });
s.addText(item.year, {
x:xx+0.05, y:4.15, w:3.9, h:0.48,
fontSize:13, bold:true, color:C.navyDeep,
align:"center", valign:"middle", fontFace:"Calibri", margin:0
});
s.addText(item.name, {
x:xx+0.12, y:4.7, w:3.76, h:0.55,
fontSize:13, bold:true, color:C.white, fontFace:"Calibri"
});
s.addText(item.contrib, {
x:xx+0.12, y:5.25, w:3.76, h:1.6,
fontSize:12, color:C.grey, fontFace:"Calibri"
});
});
}
// ══════════════════════════════════════════════════
// SLIDE 3 — Beer's Law
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s);
topBar(s, C.gold);
botBar(s, C.teal);
leftStripe(s, C.teal);
dotDeco(s);
titleStrip(s, "Beer's Law");
slideNum(s, 3, TOTAL);
// Formula
card(s, 1.8, 1.1, 9.7, 1.15, "081830", C.gold, 1.5);
s.addText("A ∝ C", {
x:1.8, y:1.1, w:9.7, h:1.15,
fontSize:44, bold:true, color:C.gold,
align:"center", valign:"middle", fontFace:"Courier New", margin:0
});
// Statement box
card(s, 0.5, 2.55, 12.3, 1.3, C.navyCard, C.teal);
s.addText([
{ text:"Statement: ", options:{ bold:true, color:C.teal } },
{ text:"When a ray of monochromatic light passes through an absorbing medium, its intensity decreases ", options:{ color:C.white } },
{ text:"exponentially", options:{ bold:true, color:C.goldLight } },
{ text:" as the ", options:{ color:C.white } },
{ text:"concentration", options:{ bold:true, color:C.gold } },
{ text:" of the light-absorbing material increases.", options:{ color:C.white } },
], { x:0.65, y:2.6, w:12.0, h:1.2, fontSize:14, fontFace:"Calibri", valign:"middle" });
// Details
const details = [
{ label:"Symbol A", val:"Absorbance (also called Optical Density, OD)", col:C.gold },
{ label:"Symbol C", val:"Concentration of the colored solution (mol/L)", col:C.teal },
{ label:"Relation", val:"If C doubles → A doubles (direct linear relationship)", col:C.green },
{ label:"Graph", val:"Plot of Concentration vs OD gives a STRAIGHT LINE", col:C.lightBlue },
{ label:"Valid range",val:"OD values between 0.1 – 0.6 give most accurate results", col:C.orange },
{ label:"Note", val:"Plot of Concentration vs %Transmittance is NOT linear", col:C.red },
];
details.forEach((d, i) => {
const xx = 0.5 + (i % 2) * 6.4;
const yy = 4.1 + Math.floor(i / 2) * 0.95;
card(s, xx, yy, 6.1, 0.82, C.navyCard, d.col, 0.8);
s.addShape("rect", { x:xx, y:yy, w:1.6, h:0.82, fill:{ color:d.col } });
s.addText(d.label, { x:xx+0.05, y:yy, w:1.5, h:0.82, fontSize:11, bold:true, color:C.navyDeep, align:"center", valign:"middle", margin:0 });
s.addText(d.val, { x:xx+1.75, y:yy, w:4.2, h:0.82, fontSize:12, color:C.white, fontFace:"Calibri", valign:"middle" });
});
}
// ══════════════════════════════════════════════════
// SLIDE 4 — Lambert's Law
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s);
topBar(s, C.gold);
botBar(s, C.teal);
leftStripe(s, C.green);
dotDeco(s);
titleStrip(s, "Lambert's Law");
slideNum(s, 4, TOTAL);
card(s, 1.8, 1.1, 9.7, 1.15, "081830", C.green, 1.5);
s.addText("A ∝ L", {
x:1.8, y:1.1, w:9.7, h:1.15,
fontSize:44, bold:true, color:C.green,
align:"center", valign:"middle", fontFace:"Courier New", margin:0
});
card(s, 0.5, 2.55, 12.3, 1.3, C.navyCard, C.green);
s.addText([
{ text:"Statement: ", options:{ bold:true, color:C.green } },
{ text:"When a ray of monochromatic light passes through an absorbing medium, its intensity decreases ", options:{ color:C.white } },
{ text:"exponentially", options:{ bold:true, color:C.goldLight } },
{ text:" as the ", options:{ color:C.white } },
{ text:"path length", options:{ bold:true, color:C.gold } },
{ text:" through the light-absorbing material increases.", options:{ color:C.white } },
], { x:0.65, y:2.6, w:12.0, h:1.2, fontSize:14, fontFace:"Calibri", valign:"middle" });
const details = [
{ label:"Symbol L", val:"Path length = distance light travels through solution (cm)", col:C.green },
{ label:"Fixed L", val:"In colorimeter, path length is kept CONSTANT (same cuvette)", col:C.teal },
{ label:"Relation", val:"Longer path → more absorption (direct proportionality)", col:C.gold },
{ label:"Cuvette role", val:"Cuvette diameter fixed → ensures constant path length (L)", col:C.lightBlue },
{ label:"Combined", val:"Beer-Lambert: A = ε × c × L (when both laws are combined)", col:C.orange },
{ label:"Transmittance",val:"T = I(transmitted)/I(incident); A = −log T = −log(E/i)", col:C.purple },
];
details.forEach((d, i) => {
const xx = 0.5 + (i % 2) * 6.4;
const yy = 4.1 + Math.floor(i / 2) * 0.95;
card(s, xx, yy, 6.1, 0.82, C.navyCard, d.col, 0.8);
s.addShape("rect", { x:xx, y:yy, w:1.6, h:0.82, fill:{ color:d.col } });
s.addText(d.label, { x:xx+0.05, y:yy, w:1.5, h:0.82, fontSize:11, bold:true, color:C.navyDeep, align:"center", valign:"middle", margin:0 });
s.addText(d.val, { x:xx+1.75, y:yy, w:4.2, h:0.82, fontSize:12, color:C.white, fontFace:"Calibri", valign:"middle" });
});
}
// ══════════════════════════════════════════════════
// SLIDE 5 — Beer-Lambert Combined Law
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s);
topBar(s, C.gold);
botBar(s, C.teal);
leftStripe(s, C.gold);
dotDeco(s);
titleStrip(s, "The Beer-Lambert Law — Combined");
slideNum(s, 5, TOTAL);
// Central formula box
card(s, 1.2, 1.1, 10.9, 1.5, "061525", C.gold, 2.0);
s.addText("A = ε × c × l", {
x:1.2, y:1.1, w:10.9, h:1.5,
fontSize:50, bold:true, color:C.gold,
align:"center", valign:"middle", fontFace:"Courier New", charSpacing:4, margin:0
});
// Symbol legend 2x2 grid
const legend = [
{ sym:"A", full:"Absorbance (Optical Density)", detail:"Dimensionless; also written as OD", col:C.gold },
{ sym:"ε", full:"Molar Absorptivity", detail:"Units: L · mol⁻¹ · cm⁻¹ (property of substance)", col:C.teal },
{ sym:"c", full:"Concentration", detail:"Molar concentration of solution (mol/L)", col:C.green },
{ sym:"l", full:"Path Length", detail:"Distance light travels through cuvette (cm)", col:C.lightBlue },
];
legend.forEach((item, i) => {
const xx = 0.5 + (i % 2) * 6.4;
const yy = 2.9 + Math.floor(i / 2) * 1.55;
card(s, xx, yy, 6.1, 1.35, C.navyCard, item.col, 1.0);
s.addShape("rect", { x:xx, y:yy, w:1.0, h:1.35, fill:{ color:item.col } });
s.addText(item.sym, { x:xx, y:yy, w:1.0, h:1.35, fontSize:34, bold:true, color:C.navyDeep, align:"center", valign:"middle", fontFace:"Courier New", margin:0 });
s.addText(item.full, { x:xx+1.1, y:yy+0.12, w:4.85, h:0.48, fontSize:14, bold:true, color:C.white, fontFace:"Calibri" });
s.addText(item.detail, { x:xx+1.1, y:yy+0.65, w:4.85, h:0.58, fontSize:12, color:C.grey, fontFace:"Calibri", italic:true });
});
// Footer note
card(s, 0.5, 6.9, 12.3, 0.45, "061525", C.gold, 0.8);
s.addText(
"Key insight: In colorimetry, path length (l) is held CONSTANT by using cuvettes of the same diameter — so only concentration (c) varies.",
{ x:0.65, y:6.9, w:12.0, h:0.45, fontSize:11.5, color:C.goldLight, italic:true, fontFace:"Calibri", valign:"middle" }
);
}
// ══════════════════════════════════════════════════
// SLIDE 6 — Components of a Colorimeter
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s);
topBar(s, C.gold);
botBar(s, C.teal);
leftStripe(s, C.teal);
dotDeco(s);
titleStrip(s, "Components of a Colorimeter");
slideNum(s, 6, TOTAL);
// Flow diagram row (simplified schematic)
const flowItems = [
{ label:"Light\nSource", sub:"Tungsten Lamp\n400–760 nm (visible)", col:C.gold },
{ label:"Adjustable\nSlit", sub:"Narrows and\ncontrols beam width", col:C.teal },
{ label:"Condensing\nLens", sub:"Produces parallel\nbeam of light", col:C.green },
{ label:"Color\nFilter", sub:"Selects complementary\nwavelength", col:C.orange },
{ label:"Cuvette\n(Sample)", sub:"Fixed diameter\nglass tube", col:C.lightBlue },
{ label:"Photocell\nDetector",sub:"Converts light\nto electrical signal",col:C.purple },
{ label:"Galvano-\nmeter", sub:"Displays OD\nor %Transmittance", col:C.red },
];
const boxW = 1.68, boxH = 1.55, startX = 0.38, y = 1.12;
flowItems.forEach((item, i) => {
const xx = startX + i * (boxW + 0.14);
card(s, xx, y, boxW, boxH, C.navyCard, item.col, 0.9);
s.addShape("rect", { x:xx, y, w:boxW, h:0.35, fill:{ color:item.col } });
s.addText(String(i+1), { x:xx, y, w:0.35, h:0.35, fontSize:10, bold:true, color:C.navyDeep, align:"center", valign:"middle", margin:0 });
s.addText(item.label, {
x:xx+0.05, y:y+0.38, w:boxW-0.1, h:0.6,
fontSize:11, bold:true, color:C.white, align:"center", fontFace:"Calibri"
});
s.addText(item.sub, {
x:xx+0.05, y:y+1.0, w:boxW-0.1, h:0.55,
fontSize:9, color:C.grey, align:"center", fontFace:"Calibri", italic:true
});
// Arrow (except after last)
if (i < flowItems.length - 1) {
s.addShape("rect", { x:xx+boxW, y:y+0.65, w:0.12, h:0.15, fill:{ color:C.gold } });
s.addText("▶", { x:xx+boxW, y:y+0.58, w:0.14, h:0.3, fontSize:10, color:C.gold, align:"center", valign:"middle", margin:0 });
}
});
// Detailed descriptions below
const descs = [
{ n:"Light Source", t:"Tungsten lamp is the standard light source. Emits white light in the visible spectrum (400–760 nm range)." },
{ n:"Slit & Lens", t:"Adjustable slit controls beam width. Condensing lens converts diverging light into a parallel (collimated) beam." },
{ n:"Filter", t:"The filter transmits only the wavelength complementary to the solution color, providing monochromatic light." },
{ n:"Cuvette", t:"Special glass tube with uniform inner diameter. The fixed diameter keeps path length (L) constant for all measurements." },
{ n:"Photocell", t:"Photoelectric detector converts transmitted light intensity into proportional electrical impulse (current)." },
{ n:"Display", t:"Galvanometer/digital meter shows the reading as Absorbance (OD) or percent Transmittance (%T)." },
];
descs.forEach((d, i) => {
const xx = 0.5 + (i % 3) * 4.3;
const yy = 2.95 + Math.floor(i / 3) * 1.68;
card(s, xx, yy, 4.0, 1.48, "0E2440", C.teal, 0.7);
s.addText(d.n, { x:xx+0.12, y:yy+0.08, w:3.76, h:0.35, fontSize:12.5, bold:true, color:C.teal, fontFace:"Calibri", margin:0 });
s.addText(d.t, { x:xx+0.12, y:yy+0.45, w:3.76, h:0.95, fontSize:11.5, color:C.white, fontFace:"Calibri" });
});
}
// ══════════════════════════════════════════════════
// SLIDE 7 — Operation (How it Works)
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s);
topBar(s, C.gold);
botBar(s, C.teal);
leftStripe(s, C.gold);
dotDeco(s);
titleStrip(s, "How a Colorimeter Works");
slideNum(s, 7, TOTAL);
const steps = [
{ n:"01", txt:"Tungsten lamp emits white light across the visible spectrum (400–760 nm).", col:C.gold },
{ n:"02", txt:"Light passes through an adjustable slit — beam width is controlled.", col:C.teal },
{ n:"03", txt:"Condensing lens converts diverging rays into a parallel (collimated) beam.", col:C.green },
{ n:"04", txt:"Color filter selects the wavelength complementary to the solution color — monochromatic light is produced.", col:C.orange },
{ n:"05", txt:"Monochromatic light enters the cuvette (fixed-diameter tube) containing the colored solution.", col:C.lightBlue },
{ n:"06", txt:"The solution absorbs part of the light proportional to its concentration (Beer-Lambert Law).", col:C.purple },
{ n:"07", txt:"Remaining transmitted light hits the photocell, generating an electrical impulse.", col:C.red },
{ n:"08", txt:"Galvanometer / digital meter displays the reading as Absorbance (OD) or %Transmittance.", col:C.goldLight },
];
steps.forEach((st, i) => {
const xx = 0.5 + (i % 2) * 6.4;
const yy = 1.1 + Math.floor(i / 2) * 1.5;
card(s, xx, yy, 6.1, 1.3, C.navyCard, st.col, 0.8);
s.addShape("ellipse", { x:xx+0.08, y:yy+0.42, w:0.48, h:0.48, fill:{ color:st.col } });
s.addText(st.n, { x:xx+0.08, y:yy+0.42, w:0.48, h:0.48, fontSize:10, bold:true, color:C.navyDeep, align:"center", valign:"middle", fontFace:"Courier New", margin:0 });
s.addText(st.txt, { x:xx+0.65, y:yy, w:5.3, h:1.3, fontSize:12, color:C.white, fontFace:"Calibri", valign:"middle" });
});
}
// ══════════════════════════════════════════════════
// SLIDE 8 — Types of Analysis
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s);
topBar(s, C.gold);
botBar(s, C.teal);
leftStripe(s, C.teal);
dotDeco(s);
titleStrip(s, "Types of Colorimetric Analysis");
slideNum(s, 8, TOTAL);
// ---- End-point Analysis card ----
card(s, 0.5, 1.1, 5.9, 5.9, C.navyCard, C.teal, 1.2);
s.addShape("rect", { x:0.5, y:1.1, w:5.9, h:0.55, fill:{ color:C.teal } });
s.addText("1. End-Point Analysis", { x:0.6, y:1.1, w:5.7, h:0.55, fontSize:15, bold:true, color:C.navyDeep, valign:"middle", margin:0 });
const epPoints = [
"Serum + reagents are mixed and incubated",
"Incubated at 37°C for a FIXED TIME (10 min)",
"Color is allowed to develop to COMPLETION",
"Single OD reading is taken after incubation",
"Concentration is calculated using:\n C(unknown) = [(OD Test − OD Blank) / (OD Std − OD Blank)] × C(std)",
"Used for: Glucose, Urea, Creatinine, Uric Acid,\n Bilirubin, Lipids, Total Proteins"
];
epPoints.forEach((pt, i) => {
s.addText([
{ text:"▸ ", options:{ bold:true, color:C.teal } },
{ text:pt, options:{ color:C.white } }
], { x:0.7, y:1.78 + i*0.73, w:5.55, h:0.65, fontSize:11.5, fontFace:"Calibri", valign:"middle" });
});
// ---- Kinetic Analysis card ----
card(s, 6.9, 1.1, 5.9, 5.9, C.navyCard, C.green, 1.2);
s.addShape("rect", { x:6.9, y:1.1, w:5.9, h:0.55, fill:{ color:C.green } });
s.addText("2. Kinetic Analysis", { x:7.0, y:1.1, w:5.7, h:0.55, fontSize:15, bold:true, color:C.navyDeep, valign:"middle", margin:0 });
const kinPoints = [
"Measures RATE of change in absorbance over time",
"Optimum color is NOT waited for",
"Readings taken at EXACTLY 2 and 3 minutes",
"ΔOD per minute is used for calculation",
"Faster than end-point — used in autoanalyzers",
"Used for ENZYMES:\n AST (SGOT), ALT (SGPT), ALP, LDH"
];
kinPoints.forEach((pt, i) => {
s.addText([
{ text:"▸ ", options:{ bold:true, color:C.green } },
{ text:pt, options:{ color:C.white } }
], { x:7.1, y:1.78 + i*0.73, w:5.55, h:0.65, fontSize:11.5, fontFace:"Calibri", valign:"middle" });
});
// Bottom comparison note
card(s, 0.5, 7.1, 12.3, 0.28, "061525", C.gold, 0.7);
s.addText("Both methods obey Beer-Lambert Law — the ONLY difference is WHEN the OD reading is taken.", {
x:0.65, y:7.1, w:12.0, h:0.28, fontSize:11, color:C.goldLight, italic:true, fontFace:"Calibri", valign:"middle"
});
}
// ══════════════════════════════════════════════════
// SLIDE 9 — Calculations
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s);
topBar(s, C.gold);
botBar(s, C.teal);
leftStripe(s, C.gold);
dotDeco(s);
titleStrip(s, "Calculations in Colorimetry");
slideNum(s, 9, TOTAL);
// Main formula block
card(s, 0.8, 1.1, 11.7, 1.6, "061525", C.gold, 1.5);
s.addText("C(unknown) = [ (OD Test − OD Blank) / (OD Standard − OD Blank) ] × C(Standard)", {
x:0.9, y:1.1, w:11.5, h:1.6,
fontSize:20, bold:true, color:C.gold,
align:"center", valign:"middle", fontFace:"Courier New", margin:0
});
// Term definitions
const terms = [
{ term:"OD Test", def:"Optical density (absorbance) of the TEST sample", col:C.gold },
{ term:"OD Blank", def:"OD of the Reagent Blank (subtracts reagent color)", col:C.teal },
{ term:"OD Standard", def:"OD of a solution with KNOWN concentration", col:C.green },
{ term:"C(Standard)", def:"Known concentration of the standard solution", col:C.orange },
{ term:"C(Unknown)", def:"Calculated concentration of the test sample", col:C.lightBlue },
{ term:"Reagent Blank","def":"Reagent without sample — zeros out background color", col:C.purple },
];
terms.forEach((t, i) => {
const xx = 0.5 + (i % 2) * 6.4;
const yy = 3.0 + Math.floor(i / 2) * 0.92;
card(s, xx, yy, 6.1, 0.78, C.navyCard, t.col, 0.8);
s.addShape("rect", { x:xx, y:yy, w:1.9, h:0.78, fill:{ color:t.col } });
s.addText(t.term, { x:xx+0.05, y:yy, w:1.8, h:0.78, fontSize:11, bold:true, color:C.navyDeep, align:"center", valign:"middle", margin:0 });
s.addText(t.def, { x:xx+2.05, y:yy, w:3.9, h:0.78, fontSize:12, color:C.white, fontFace:"Calibri", valign:"middle" });
});
// Extended formula from source 2
card(s, 0.5, 5.85, 12.3, 1.45, "0E2440", C.orange, 0.9);
s.addText("Extended formula (from Essentials of Biochemistry):", { x:0.65, y:5.88, w:12.0, h:0.35, fontSize:12, bold:true, color:C.orange, fontFace:"Calibri", margin:0 });
s.addText("% Concentration of test = [ (OD Test − OD Blank) / (OD Standard − OD Blank) ] × (Conc. of Std / Volume of test) × 100", {
x:0.65, y:6.25, w:12.0, h:0.95, fontSize:13, color:C.white, fontFace:"Courier New", valign:"middle"
});
}
// ══════════════════════════════════════════════════
// SLIDE 10 — Clinical Applications
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s);
topBar(s, C.gold);
botBar(s, C.teal);
leftStripe(s, C.teal);
dotDeco(s);
titleStrip(s, "Clinical Applications of Colorimeter");
slideNum(s, 10, TOTAL);
// Intro sentence
s.addText(
"Colorimetric procedures are widely used in clinical laboratories to estimate biochemical compounds in blood, plasma, serum, CSF, urine and other body fluids.",
{ x:0.5, y:1.1, w:12.3, h:0.7, fontSize:13, color:C.grey, fontFace:"Calibri" }
);
const cats = [
{ title:"Carbohydrates", items:["Glucose (Fasting/PP/RBS)", "HbA1c (Glycated Haemoglobin)"], col:C.gold, x:0.5, y:2.0 },
{ title:"Renal Function", items:["Urea (Blood Urea Nitrogen)", "Creatinine", "Uric Acid"], col:C.teal, x:4.55, y:2.0 },
{ title:"Liver Function", items:["Total Bilirubin", "Direct Bilirubin", "Serum Proteins"], col:C.green, x:8.65, y:2.0 },
{ title:"Lipid Profile", items:["Total Cholesterol", "Triglycerides", "HDL / LDL (calc)"], col:C.orange, x:0.5, y:4.35 },
{ title:"Enzymes (Kinetic)", items:["AST / SGOT", "ALT / SGPT", "ALP, LDH (liver enzymes)"], col:C.red, x:4.55, y:4.35 },
{ title:"Minerals & Others", items:["Calcium (Ca)", "Phosphorus (P)", "Total Protein, Albumin"], col:C.purple, x:8.65, y:4.35 },
];
cats.forEach(cat => {
const cH = 2.15;
card(s, cat.x, cat.y, 3.85, cH, C.navyCard, cat.col, 1.0);
s.addShape("rect", { x:cat.x, y:cat.y, w:3.85, h:0.45, fill:{ color:cat.col } });
s.addText(cat.title, { x:cat.x+0.08, y:cat.y, w:3.69, h:0.45, fontSize:13, bold:true, color:C.navyDeep, align:"center", valign:"middle", margin:0 });
cat.items.forEach((item, idx) => {
s.addText([
{ text:"● ", options:{ color:cat.col, bold:true } },
{ text:item, options:{ color:C.white } }
], { x:cat.x+0.15, y:cat.y+0.52 + idx*0.52, w:3.55, h:0.48, fontSize:12, fontFace:"Calibri", valign:"middle" });
});
});
// Bottom info strip
card(s, 0.5, 6.62, 12.3, 0.72, "0E2440", C.gold, 0.8);
s.addText("Biological samples used: Blood · Plasma · Serum · Cerebrospinal fluid (CSF) · Urine · Other body fluids", {
x:0.65, y:6.65, w:12.0, h:0.65, fontSize:13, color:C.goldLight, fontFace:"Calibri", valign:"middle"
});
}
// ══════════════════════════════════════════════════
// SLIDE 11 — Colorimeter vs Spectrophotometer
// ══════════════════════════════════════════════════
{
const s = pres.addSlide();
bg(s);
topBar(s, C.gold);
botBar(s, C.teal);
leftStripe(s, C.gold);
dotDeco(s);
titleStrip(s, "Colorimeter vs Spectrophotometer");
slideNum(s, 11, TOTAL);
// Table headers
const colX = [0.5, 4.2, 8.8];
const colW = [3.5, 4.35, 4.35];
const hdrs = ["Feature", "Colorimeter", "Spectrophotometer"];
const hdrCols = [C.navyMid, C.teal, C.gold];
hdrs.forEach((h, i) => {
card(s, colX[i], 1.1, colW[i], 0.58, hdrCols[i], hdrCols[i]);
s.addText(h, { x:colX[i]+0.08, y:1.1, w:colW[i]-0.16, h:0.58, fontSize:14, bold:true, color: i===0 ? C.goldLight : C.navyDeep, align:"center", valign:"middle", margin:0 });
});
const rows = [
["Light Source", "Tungsten lamp", "Tungsten + Deuterium / Xenon"],
["Wavelength Sel.", "Glass/gelatin color filters", "Diffraction gratings (prism)"],
["Range", "Visible only: 400–760 nm", "UV + Visible + IR: ~200–900 nm"],
["Cuvettes", "Glass or plastic cuvettes", "Quartz cuvettes (UV transparent)"],
["Sensitivity", "Standard sensitivity", "~1000× MORE sensitive"],
["Cost", "Low cost — routine labs", "~100× more expensive"],
["Applications", "Routine clinical biochemistry", "Research & specialized assays"],
];
rows.forEach((row, ri) => {
const yy = 1.72 + ri * 0.74;
const rowBg = ri % 2 === 0 ? C.navyCard : C.navyMid;
row.forEach((cell, ci) => {
card(s, colX[ci], yy, colW[ci], 0.7, rowBg, rowBg);
const textCol = ci===0 ? C.goldLight : ci===1 ? C.teal : C.white;
s.addText(cell, { x:colX[ci]+0.12, y:yy, w:colW[ci]-0.24, h:0.7, fontSize:12, color:textCol, fontFace:"Calibri", valign:"middle" });
});
});
// Key differentiator box
card(s, 0.5, 7.04, 12.3, 0.36, "061525", C.orange, 0.9);
s.addText(
"Key difference: Spectrophotometer is 1000× more sensitive but 100× more expensive — uses diffraction gratings & quartz cuvettes for UV range.",
{ x:0.65, y:7.04, w:12.0, h:0.36, fontSize:11, color:C.goldLight, italic:true, fontFace:"Calibri", valign:"middle" }
);
}
// ─── Write file ───────────────────────────────────────────────────────────────
const outFile = path.resolve(__dirname, "Colorimeter.pptx");
pres.writeFile({ fileName: outFile })
.then(() => console.log("\n✅ Created: " + outFile))
.catch(err => { console.error("ERROR:", err); process.exit(1); });
cd /home/daytona/workspace/colorimeter-ppt && node create_ppt.js 2>&1
ls -lh /home/daytona/workspace/colorimeter-ppt/Colorimeter.pptx
Colorimeter
Presentation · PPTX
| Slide | Title |
|---|---|
| 1 | Title Slide — "COLORIMETER" with dark navy + gold design |
| 2 | Introduction & Historical Background — Lambert (1728-1777), Beer (1825-1863), combined law |
| 3 | Beer's Law — A ∝ C, statement, formula details, valid OD range (0.1–0.6) |
| 4 | Lambert's Law — A ∝ L, path length, transmittance formula |
| 5 | Beer-Lambert Combined Law — A = ε × c × l with full legend |
| 6 | Components — Flow diagram of all 7 parts (Lamp → Slit → Lens → Filter → Cuvette → Photocell → Display) |
| 7 | How it Works — 8-step operation walkthrough |
| 8 | Types of Analysis — End-point (37°C, 10 min) vs Kinetic (2 & 3 min readings) |
| 9 | Calculations — Full formula with all OD terms, extended % concentration formula |
| 10 | Clinical Applications — 6 categories: carbohydrates, renal, liver, lipids, enzymes, minerals |
| 11 | Colorimeter vs Spectrophotometer — comparison table (sensitivity, cost, wavelength range, cuvettes) |