1use std::collections::HashMap;
15use std::fmt::Write as FmtWrite;
16use std::path::Path;
17
18use rdocx::{
19 Alignment, BorderStyle, Document, Length, SectionBreak, StyleBuilder, TabAlignment, TabLeader,
20 VerticalAlignment,
21};
22
23fn main() {
24 let samples_dir = Path::new(env!("CARGO_MANIFEST_DIR"))
25 .parent()
26 .unwrap()
27 .parent()
28 .unwrap()
29 .join("samples");
30 std::fs::create_dir_all(&samples_dir).unwrap();
31
32 println!(
33 "Generating all sample documents in {}\n",
34 samples_dir.display()
35 );
36
37 let generators: Vec<(&str, fn(&Path) -> Document)> = vec![
38 ("feature_showcase", generate_feature_showcase),
39 ("proposal", generate_proposal),
40 ("quote", generate_quote),
41 ("invoice", generate_invoice),
42 ("report", generate_report),
43 ("letter", generate_letter),
44 ("contract", generate_contract),
45 ];
46
47 for (name, generator) in &generators {
48 println!("--- {} ---", name);
49 let doc = generator(&samples_dir);
50 export_all(&samples_dir, name, doc);
51 println!();
52 }
53
54 println!("All done!");
55}
56
57fn export_all(dir: &Path, name: &str, mut doc: Document) {
59 let docx_path = dir.join(format!("{name}.docx"));
60 doc.save(&docx_path).unwrap();
61 println!(" {name}.docx");
62
63 match doc.to_pdf() {
64 Ok(pdf) => {
65 let pdf_path = dir.join(format!("{name}.pdf"));
66 std::fs::write(&pdf_path, &pdf).unwrap();
67 println!(" {name}.pdf ({} bytes)", pdf.len());
68 }
69 Err(e) => println!(" {name}.pdf — skipped: {e}"),
70 }
71
72 let html = doc.to_html();
73 let html_path = dir.join(format!("{name}.html"));
74 std::fs::write(&html_path, &html).unwrap();
75 println!(" {name}.html ({} bytes)", html.len());
76
77 let md = doc.to_markdown();
78 let md_path = dir.join(format!("{name}.md"));
79 std::fs::write(&md_path, &md).unwrap();
80 println!(" {name}.md ({} bytes)", md.len());
81}
82
83fn generate_feature_showcase(_samples_dir: &Path) -> Document {
87 let mut doc = Document::new();
88
89 doc.set_page_size(Length::inches(8.5), Length::inches(11.0));
91 doc.set_margins(
92 Length::inches(1.0),
93 Length::inches(1.0),
94 Length::inches(1.0),
95 Length::inches(1.0),
96 );
97 doc.set_header_footer_distance(Length::twips(720), Length::twips(432));
98 doc.set_gutter(Length::twips(0));
99 doc.set_title("rdocx Feature Showcase");
100 doc.set_author("rdocx Sample Generator");
101 doc.set_subject("Comprehensive feature demonstration");
102 doc.set_keywords("rdocx, docx, rust, sample, showcase");
103
104 doc.set_different_first_page(true);
106 doc.set_first_page_header("rdocx");
107 doc.set_first_page_footer("Feature Showcase — Cover Page");
108 doc.set_header("rdocx Feature Showcase");
109 doc.set_footer("Generated by rdocx");
110
111 let bg = create_sample_png(612, 792, [20, 45, 90]);
113 doc.add_background_image(&bg, "cover_bg.png");
114
115 for _ in 0..3 {
116 doc.add_paragraph("");
117 }
118 {
119 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
120 p.add_run("rdocx").bold(true).size(72.0).color("FFFFFF");
121 }
122 {
123 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
124 p.add_run("Complete Feature Showcase")
125 .size(28.0)
126 .color("FFFFFF")
127 .italic(true);
128 }
129 doc.add_paragraph("");
130 {
131 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
132 p.add_run("Every feature of the rdocx Rust library")
133 .size(13.0)
134 .color("B0C4DE");
135 }
136 {
137 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
138 p.add_run("demonstrated in a single document.")
139 .size(13.0)
140 .color("B0C4DE");
141 }
142
143 doc.add_paragraph("").page_break_before(true);
145 doc.insert_toc(doc.content_count(), 3);
146
147 doc.add_paragraph("").page_break_before(true);
149 doc.add_paragraph("1. Text Formatting").style("Heading1");
150
151 doc.add_paragraph("1.1 Paragraph Alignment")
153 .style("Heading2");
154 doc.add_paragraph("Left-aligned paragraph (default).")
155 .alignment(Alignment::Left);
156 doc.add_paragraph("Center-aligned paragraph.")
157 .alignment(Alignment::Center);
158 doc.add_paragraph("Right-aligned paragraph.")
159 .alignment(Alignment::Right);
160 doc.add_paragraph(
161 "Justified paragraph — this text is long enough to demonstrate how justified alignment \
162 distributes extra space across word gaps so lines fill the full width of the text area.",
163 )
164 .alignment(Alignment::Justify);
165
166 doc.add_paragraph("");
167
168 doc.add_paragraph("1.2 Run Formatting").style("Heading2");
170 {
171 let mut p = doc.add_paragraph("");
172 p.add_run("Bold").bold(true);
173 p.add_run(" | ");
174 p.add_run("Italic").italic(true);
175 p.add_run(" | ");
176 p.add_run("Bold Italic").bold(true).italic(true);
177 p.add_run(" | ");
178 p.add_run("Underline").underline(true);
179 p.add_run(" | ");
180 p.add_run("Strikethrough").strike(true);
181 p.add_run(" | ");
182 p.add_run("Double Strike").double_strike(true);
183 }
184 {
185 let mut p = doc.add_paragraph("");
186 p.add_run("Red").color("FF0000");
187 p.add_run(" | ");
188 p.add_run("Blue").color("0000FF");
189 p.add_run(" | ");
190 p.add_run("Green").color("00AA00");
191 p.add_run(" | ");
192 p.add_run("Highlighted").highlight("FFFF00");
193 }
194 {
195 let mut p = doc.add_paragraph("");
196 p.add_run("8pt").size(8.0);
197 p.add_run(" | ");
198 p.add_run("11pt").size(11.0);
199 p.add_run(" | ");
200 p.add_run("16pt").size(16.0);
201 p.add_run(" | ");
202 p.add_run("24pt").size(24.0);
203 }
204 {
205 let mut p = doc.add_paragraph("");
206 p.add_run("Arial").font("Arial");
207 p.add_run(" | ");
208 p.add_run("Times New Roman").font("Times New Roman");
209 p.add_run(" | ");
210 p.add_run("Courier New").font("Courier New");
211 }
212 {
213 let mut p = doc.add_paragraph("");
214 p.add_run("H");
215 p.add_run("2").subscript();
216 p.add_run("O (subscript) | E=mc");
217 p.add_run("2").superscript();
218 p.add_run(" (superscript)");
219 }
220 {
221 let mut p = doc.add_paragraph("");
222 p.add_run("ALL CAPS").all_caps(true);
223 p.add_run(" | ");
224 p.add_run("Small Caps").small_caps(true);
225 p.add_run(" | ");
226 p.add_run("Expanded").character_spacing(Length::twips(40));
227 p.add_run(" | ");
228 p.add_run("Hidden text (not visible)").hidden(true);
229 }
230
231 doc.add_paragraph("");
232
233 doc.add_paragraph("1.3 Underline Styles").style("Heading2");
235 {
236 let mut p = doc.add_paragraph("");
237 p.add_run("Single ")
238 .underline_style(rdocx::UnderlineStyle::Single);
239 p.add_run("Double ")
240 .underline_style(rdocx::UnderlineStyle::Double);
241 p.add_run("Thick ")
242 .underline_style(rdocx::UnderlineStyle::Thick);
243 p.add_run("Dotted ")
244 .underline_style(rdocx::UnderlineStyle::Dotted);
245 p.add_run("Dash ")
246 .underline_style(rdocx::UnderlineStyle::Dash);
247 p.add_run("Wave ")
248 .underline_style(rdocx::UnderlineStyle::Wave);
249 }
250
251 doc.add_paragraph("").page_break_before(true);
253 doc.add_paragraph("2. Paragraph Formatting")
254 .style("Heading1");
255
256 doc.add_paragraph("2.1 Shading & Borders").style("Heading2");
257 doc.add_paragraph("Paragraph with light green shading")
258 .shading("E2EFDA");
259 doc.add_paragraph("Paragraph with bottom border")
260 .border_bottom(BorderStyle::Single, 6, "2E75B6");
261 doc.add_paragraph("Paragraph with all borders (red)")
262 .border_all(BorderStyle::Single, 4, "FF0000");
263
264 doc.add_paragraph("2.2 Indentation").style("Heading2");
265 doc.add_paragraph("1-inch left indent + 0.5-inch hanging indent")
266 .indent_left(Length::inches(1.0))
267 .hanging_indent(Length::inches(0.5));
268 doc.add_paragraph("0.5-inch first-line indent on this paragraph")
269 .first_line_indent(Length::inches(0.5));
270 doc.add_paragraph("Both left and right indent (0.75 inches each)")
271 .indent_left(Length::inches(0.75))
272 .indent_right(Length::inches(0.75));
273
274 doc.add_paragraph("2.3 Spacing & Line Height")
275 .style("Heading2");
276 doc.add_paragraph("Extra space before (24pt) and after (12pt)")
277 .space_before(Length::pt(24.0))
278 .space_after(Length::pt(12.0));
279 doc.add_paragraph(
280 "Double line spacing paragraph. This text should have extra vertical space between \
281 lines to demonstrate line_spacing_multiple(2.0).",
282 )
283 .line_spacing_multiple(2.0);
284 doc.add_paragraph("Exact 20pt line spacing (fixed height).")
285 .line_spacing(20.0);
286
287 doc.add_paragraph("2.4 Pagination Controls")
288 .style("Heading2");
289 doc.add_paragraph("keep_with_next — this paragraph stays with the next")
290 .keep_with_next(true);
291 doc.add_paragraph("(This paragraph was kept with the one above.)");
292 doc.add_paragraph("keep_together — all lines of this paragraph stay on the same page")
293 .keep_together(true);
294 doc.add_paragraph("widow_control — prevents widow/orphan lines")
295 .widow_control(true);
296
297 doc.add_paragraph("").page_break_before(true);
299 doc.add_paragraph("3. Lists").style("Heading1");
300
301 doc.add_paragraph("3.1 Bullet Lists").style("Heading2");
302 doc.add_bullet_list_item("First item", 0);
303 doc.add_bullet_list_item("Second item", 0);
304 doc.add_bullet_list_item("Nested level 1", 1);
305 doc.add_bullet_list_item("Nested level 2", 2);
306 doc.add_bullet_list_item("Back to level 1", 1);
307 doc.add_bullet_list_item("Third item", 0);
308
309 doc.add_paragraph("");
310
311 doc.add_paragraph("3.2 Numbered Lists").style("Heading2");
312 doc.add_numbered_list_item("First numbered item", 0);
313 doc.add_numbered_list_item("Second numbered item", 0);
314 doc.add_numbered_list_item("Sub-item A", 1);
315 doc.add_numbered_list_item("Sub-item B", 1);
316 doc.add_numbered_list_item("Third numbered item", 0);
317
318 doc.add_paragraph("");
320 doc.add_paragraph("4. Tab Stops").style("Heading1");
321
322 doc.add_paragraph("4.1 Alignment Tabs").style("Heading2");
323 doc.add_paragraph("Left\tCenter\tRight\tDecimal")
324 .add_tab_stop(TabAlignment::Left, Length::inches(0.0))
325 .add_tab_stop(TabAlignment::Center, Length::inches(2.5))
326 .add_tab_stop(TabAlignment::Right, Length::inches(5.0))
327 .add_tab_stop(TabAlignment::Decimal, Length::inches(6.5));
328
329 doc.add_paragraph("4.2 Tab Leaders").style("Heading2");
330 doc.add_paragraph("Item\t\tPrice")
331 .add_tab_stop_with_leader(TabAlignment::Left, Length::inches(0.0), TabLeader::None)
332 .add_tab_stop_with_leader(TabAlignment::Right, Length::inches(4.0), TabLeader::Dot)
333 .add_tab_stop_with_leader(TabAlignment::Right, Length::inches(5.0), TabLeader::None);
334 doc.add_paragraph("Widget\t\t$19.99")
335 .add_tab_stop_with_leader(TabAlignment::Left, Length::inches(0.0), TabLeader::None)
336 .add_tab_stop_with_leader(TabAlignment::Right, Length::inches(4.0), TabLeader::Dot)
337 .add_tab_stop_with_leader(TabAlignment::Right, Length::inches(5.0), TabLeader::None);
338 doc.add_paragraph("Gadget\t\t$249.50")
339 .add_tab_stop_with_leader(TabAlignment::Left, Length::inches(0.0), TabLeader::None)
340 .add_tab_stop_with_leader(
341 TabAlignment::Right,
342 Length::inches(4.0),
343 TabLeader::Underscore,
344 )
345 .add_tab_stop_with_leader(TabAlignment::Right, Length::inches(5.0), TabLeader::None);
346
347 doc.add_paragraph("").page_break_before(true);
349 doc.add_paragraph("5. Tables").style("Heading1");
350
351 doc.add_paragraph("5.1 Basic Table").style("Heading2");
352 {
353 let mut tbl = doc
354 .add_table(4, 3)
355 .borders(BorderStyle::Single, 4, "000000");
356 for col in 0..3 {
357 tbl.cell(0, col).unwrap().shading("2E75B6");
358 }
359 tbl.cell(0, 0).unwrap().set_text("Name");
360 tbl.cell(0, 1).unwrap().set_text("Role");
361 tbl.cell(0, 2).unwrap().set_text("Location");
362 tbl.cell(1, 0).unwrap().set_text("Walter White");
363 tbl.cell(1, 1).unwrap().set_text("CEO");
364 tbl.cell(1, 2).unwrap().set_text("Albuquerque");
365 tbl.cell(2, 0).unwrap().set_text("Jesse Pinkman");
366 tbl.cell(2, 1).unwrap().set_text("CTO");
367 tbl.cell(2, 2).unwrap().set_text("Remote");
368 tbl.cell(3, 0).unwrap().set_text("Hank Schrader");
369 tbl.cell(3, 1).unwrap().set_text("Security");
370 tbl.cell(3, 2).unwrap().set_text("Washington");
371 }
372
373 doc.add_paragraph("");
374
375 doc.add_paragraph("5.2 Column Span & Cell Shading")
376 .style("Heading2");
377 {
378 let mut tbl = doc
379 .add_table(3, 4)
380 .borders(BorderStyle::Single, 4, "000000")
381 .width_pct(100.0);
382 tbl.cell(0, 0).unwrap().set_text("Quarterly Report");
383 tbl.cell(0, 0).unwrap().shading("1F4E79").grid_span(4);
384 tbl.cell(1, 0).unwrap().set_text("Region");
385 tbl.cell(1, 0).unwrap().shading("D6E4F0");
386 tbl.cell(1, 1).unwrap().set_text("Q1");
387 tbl.cell(1, 1).unwrap().shading("D6E4F0");
388 tbl.cell(1, 2).unwrap().set_text("Q2");
389 tbl.cell(1, 2).unwrap().shading("D6E4F0");
390 tbl.cell(1, 3).unwrap().set_text("Total");
391 tbl.cell(1, 3).unwrap().shading("D6E4F0");
392 tbl.cell(2, 0).unwrap().set_text("Americas");
393 tbl.cell(2, 1).unwrap().set_text("$2.4M");
394 tbl.cell(2, 2).unwrap().set_text("$2.7M");
395 tbl.cell(2, 3).unwrap().set_text("$5.1M");
396 }
397
398 doc.add_paragraph("");
399
400 doc.add_paragraph("5.3 Vertical Merge").style("Heading2");
401 {
402 let mut tbl = doc
403 .add_table(4, 3)
404 .borders(BorderStyle::Single, 4, "000000");
405 tbl.cell(0, 0).unwrap().set_text("Category");
406 tbl.cell(0, 0).unwrap().shading("E2EFDA");
407 tbl.cell(0, 1).unwrap().set_text("Item");
408 tbl.cell(0, 1).unwrap().shading("E2EFDA");
409 tbl.cell(0, 2).unwrap().set_text("Price");
410 tbl.cell(0, 2).unwrap().shading("E2EFDA");
411 tbl.cell(1, 0).unwrap().set_text("Hardware");
412 tbl.cell(1, 0).unwrap().v_merge_restart();
413 tbl.cell(1, 1).unwrap().set_text("Laptop");
414 tbl.cell(1, 2).unwrap().set_text("$1,200");
415 tbl.cell(2, 0).unwrap().v_merge_continue();
416 tbl.cell(2, 1).unwrap().set_text("Monitor");
417 tbl.cell(2, 2).unwrap().set_text("$450");
418 tbl.cell(3, 0).unwrap().set_text("Software");
419 tbl.cell(3, 1).unwrap().set_text("IDE License");
420 tbl.cell(3, 2).unwrap().set_text("$200/yr");
421 }
422
423 doc.add_paragraph("");
424
425 doc.add_paragraph("5.4 Nested Table").style("Heading2");
426 {
427 let mut tbl = doc
428 .add_table(2, 2)
429 .borders(BorderStyle::Single, 6, "2E75B6");
430 tbl.cell(0, 0).unwrap().set_text("Outer (0,0)");
431 tbl.cell(0, 1).unwrap().set_text("Outer (0,1)");
432 tbl.cell(1, 0).unwrap().set_text("Outer (1,0)");
433 {
434 let mut cell = tbl.cell(1, 1).unwrap();
435 cell.set_text("Nested table below:");
436 let mut nested = cell
437 .add_table(2, 2)
438 .borders(BorderStyle::Single, 2, "FF6600");
439 nested.cell(0, 0).unwrap().set_text("A");
440 nested.cell(0, 1).unwrap().set_text("B");
441 nested.cell(1, 0).unwrap().set_text("C");
442 nested.cell(1, 1).unwrap().set_text("D");
443 }
444 }
445
446 doc.add_paragraph("");
447
448 doc.add_paragraph("5.5 Vertical Alignment & Row Properties")
449 .style("Heading2");
450 {
451 let mut tbl = doc
452 .add_table(2, 3)
453 .borders(BorderStyle::Single, 4, "666666");
454 tbl.row(0).unwrap().height(Length::pt(50.0)).header();
455 tbl.cell(0, 0).unwrap().set_text("Top");
456 tbl.cell(0, 0)
457 .unwrap()
458 .vertical_alignment(VerticalAlignment::Top)
459 .shading("FFF2CC");
460 tbl.cell(0, 1).unwrap().set_text("Center");
461 tbl.cell(0, 1)
462 .unwrap()
463 .vertical_alignment(VerticalAlignment::Center)
464 .shading("D9E2F3");
465 tbl.cell(0, 2).unwrap().set_text("Bottom");
466 tbl.cell(0, 2)
467 .unwrap()
468 .vertical_alignment(VerticalAlignment::Bottom)
469 .shading("E2EFDA");
470 tbl.row(1).unwrap().cant_split();
471 tbl.cell(1, 0).unwrap().set_text("No-wrap cell");
472 tbl.cell(1, 0).unwrap().no_wrap();
473 tbl.cell(1, 1).unwrap().set_text("Fixed width");
474 tbl.cell(1, 1).unwrap().width(Length::inches(2.0));
475 tbl.cell(1, 2).unwrap().set_text("Normal");
476 }
477
478 doc.add_paragraph("").page_break_before(true);
480 doc.add_paragraph("6. Images").style("Heading1");
481
482 doc.add_paragraph("6.1 Inline Image").style("Heading2");
483 doc.add_paragraph("A blue gradient image below:");
484 let img = create_sample_png(200, 50, [0, 80, 200]);
485 doc.add_picture(&img, "chart.png", Length::inches(3.0), Length::inches(0.75));
486
487 doc.add_paragraph("");
488 doc.add_paragraph("6.2 Header Image").style("Heading2");
489 let hdr_img = create_sample_png(400, 40, [40, 40, 40]);
490 doc.set_header_image(
491 &hdr_img,
492 "header_logo.png",
493 Length::inches(2.0),
494 Length::inches(0.2),
495 );
496 doc.add_paragraph("The header now contains an inline image (check the top of this page).");
497
498 doc.add_paragraph("");
499 doc.add_paragraph("Note: Page 1 uses a full-page background image (add_background_image).");
500
501 doc.add_paragraph("").page_break_before(true);
503 doc.add_paragraph("7. Content Manipulation")
504 .style("Heading1");
505
506 doc.add_paragraph("7.1 Placeholder Replacement")
507 .style("Heading2");
508 doc.add_paragraph("Customer: {{customer}}");
509 doc.add_paragraph("Date: {{date}}");
510 doc.add_paragraph("Reference: {{ref_number}}");
511 {
512 let mut tbl = doc
513 .add_table(2, 2)
514 .borders(BorderStyle::Single, 4, "000000");
515 tbl.cell(0, 0).unwrap().set_text("Project");
516 tbl.cell(0, 0).unwrap().shading("D6E4F0");
517 tbl.cell(0, 1).unwrap().set_text("{{project}}");
518 tbl.cell(1, 0).unwrap().set_text("Status");
519 tbl.cell(1, 0).unwrap().shading("D6E4F0");
520 tbl.cell(1, 1).unwrap().set_text("{{status}}");
521 }
522
523 let mut replacements = HashMap::new();
524 replacements.insert("{{customer}}", "Tensorbee Inc.");
525 replacements.insert("{{date}}", "February 22, 2026");
526 replacements.insert("{{ref_number}}", "TB-2026-001");
527 replacements.insert("{{project}}", "Infrastructure Upgrade");
528 replacements.insert("{{status}}", "In Progress");
529 let n = doc.replace_all(&replacements);
530 doc.add_paragraph(&format!("({n} placeholders replaced above)"));
531
532 doc.add_paragraph("");
533
534 doc.add_paragraph("7.2 Regex Replacement").style("Heading2");
535 doc.add_paragraph("Emails: user1@example.com and admin@tensorbee.com");
536 let _ = doc.replace_regex(r"\b\w+@\w+\.\w+\b", "[REDACTED]");
537 doc.add_paragraph("(Email addresses above were redacted using regex replacement)");
538
539 doc.add_paragraph("");
540
541 doc.add_paragraph("7.3 Content Insertion").style("Heading2");
542 doc.add_paragraph("Section A: First content.");
543 doc.add_paragraph("Section C: Third content.");
544 if let Some(idx) = doc.find_content_index("Section C") {
545 doc.insert_paragraph(
546 idx,
547 "Section B: Inserted between A and C via find_content_index().",
548 );
549 }
550
551 doc.add_paragraph("").section_break(SectionBreak::NextPage);
553 doc.add_paragraph("8. Section Breaks & Orientation")
554 .style("Heading1");
555 doc.add_paragraph("This page is LANDSCAPE. Useful for wide tables and charts.");
556
557 {
558 let mut tbl = doc
559 .add_table(3, 7)
560 .borders(BorderStyle::Single, 4, "2E75B6");
561 let headers = ["Region", "Jan", "Feb", "Mar", "Apr", "May", "Total"];
562 for (c, h) in headers.iter().enumerate() {
563 tbl.cell(0, c).unwrap().set_text(h);
564 tbl.cell(0, c).unwrap().shading("2E75B6");
565 }
566 let data = [
567 [
568 "Americas", "$1.2M", "$1.3M", "$1.4M", "$1.5M", "$1.6M", "$7.0M",
569 ],
570 [
571 "Europe", "$0.8M", "$0.9M", "$0.9M", "$1.0M", "$1.1M", "$4.7M",
572 ],
573 ];
574 for (r, row) in data.iter().enumerate() {
575 for (c, v) in row.iter().enumerate() {
576 tbl.cell(r + 1, c).unwrap().set_text(v);
577 }
578 }
579 }
580
581 doc.add_paragraph("")
582 .section_break(SectionBreak::NextPage)
583 .section_landscape();
584
585 doc.add_paragraph("9. Custom Styles").style("Heading1");
587 doc.add_style(
588 StyleBuilder::paragraph("CustomHighlight", "Custom Highlight")
589 .based_on("Normal")
590 .paragraph_properties({
591 let mut ppr = rdocx_oxml::properties::CT_PPr::default();
592 ppr.shading = Some(rdocx_oxml::properties::CT_Shd {
593 val: "clear".to_string(),
594 color: None,
595 fill: Some("FFF2CC".to_string()),
596 });
597 ppr
598 })
599 .run_properties({
600 let mut rpr = rdocx_oxml::properties::CT_RPr::default();
601 rpr.bold = Some(true);
602 rpr.color = Some("C45911".to_string());
603 rpr
604 }),
605 );
606 doc.add_paragraph("This paragraph uses a custom style: bold orange text on yellow background.")
607 .style("CustomHighlight");
608
609 doc.add_paragraph("");
610
611 doc.add_paragraph("10. Document Intelligence API")
613 .style("Heading1");
614
615 let wc = doc.word_count();
616 let hc = doc.headings().len();
617 let ic = doc.images().len();
618 let lc = doc.links().len();
619 doc.add_paragraph(&format!("Word count: {wc}"));
620 doc.add_paragraph(&format!("Heading count: {hc}"));
621 doc.add_paragraph(&format!("Image count: {ic}"));
622 doc.add_paragraph(&format!("Link count: {lc}"));
623
624 let outline = doc.document_outline();
625 doc.add_paragraph(&format!("Top-level outline nodes: {}", outline.len()));
626
627 let issues = doc.audit_accessibility();
628 doc.add_paragraph(&format!("Accessibility issues: {}", issues.len()));
629 for issue in &issues {
630 doc.add_bullet_list_item(&format!("{:?}: {}", issue.severity, issue.message), 0);
631 }
632
633 doc.add_paragraph("");
635 doc.add_paragraph("11. Document Merging").style("Heading1");
636 {
637 let mut other = Document::new();
638 other.add_paragraph("This paragraph was merged from another document using append().");
639 doc.append(&other);
640 }
641
642 doc.add_paragraph("");
643
644 doc.add_paragraph("Summary of Demonstrated Features")
646 .style("Heading1");
647 let features = [
648 "Page setup: size, margins, header/footer distance, gutter",
649 "Document metadata: title, author, subject, keywords",
650 "Headers and footers: text, images, different first page",
651 "Background images (full-page behind text)",
652 "Table of Contents generation with bookmarks",
653 "Text formatting: bold, italic, underline styles, strike, color, size, font",
654 "Advanced run: superscript, subscript, caps, small caps, spacing, hidden",
655 "Paragraph formatting: alignment, borders, shading, spacing, indentation",
656 "Pagination controls: keep-with-next, keep-together, widow control",
657 "Bullet and numbered lists with nesting",
658 "Tab stops with dot/underscore/hyphen leaders",
659 "Tables: borders, shading, column spans, row spans, vertical alignment, nested tables",
660 "Row properties: header rows, exact height, cant-split",
661 "Cell properties: width, no-wrap, vertical alignment",
662 "Inline images and header images",
663 "Placeholder replacement (single and batch)",
664 "Regex-based find and replace",
665 "Content insertion at specific positions",
666 "Section breaks with mixed portrait/landscape",
667 "Custom paragraph and character styles",
668 "Document intelligence: word count, headings, outline, images, links",
669 "Accessibility audit",
670 "Document merging (append)",
671 "Export: DOCX, PDF, HTML, Markdown",
672 ];
673 for f in &features {
674 doc.add_bullet_list_item(f, 0);
675 }
676 doc.add_paragraph("");
677 doc.add_paragraph("All features built entirely with the rdocx Rust crate.")
678 .alignment(Alignment::Center)
679 .shading("E2EFDA")
680 .border_all(BorderStyle::Single, 2, "00AA00");
681
682 doc
683}
684
685fn generate_proposal(_samples_dir: &Path) -> Document {
689 let mut doc = Document::new();
690
691 doc.set_page_size(Length::inches(8.5), Length::inches(11.0));
693 doc.set_margins(
694 Length::inches(1.0),
695 Length::inches(1.0),
696 Length::inches(1.0),
697 Length::inches(1.0),
698 );
699 doc.set_title("AI Platform Modernization Proposal");
700 doc.set_author("Walter White");
701 doc.set_subject("Technology Proposal");
702 doc.set_keywords("proposal, AI, modernization, Tensorbee");
703
704 let logo_img = create_logo_png(220, 48);
706 let banner = build_header_banner_xml(
707 "rId1",
708 &BannerOpts {
709 bg_color: "1B2A4A",
710 banner_width: 7772400,
711 banner_height: 914400,
712 logo_width: 2011680,
713 logo_height: 438912,
714 logo_x_offset: 295125,
715 logo_y_offset: 237744,
716 },
717 );
718 doc.set_raw_header_with_images(
719 banner,
720 &[("rId1", &logo_img, "logo.png")],
721 rdocx_oxml::header_footer::HdrFtrType::Default,
722 );
723 doc.set_different_first_page(true);
724 let cover_banner = build_header_banner_xml(
725 "rId1",
726 &BannerOpts {
727 bg_color: "C5922E",
728 banner_width: 7772400,
729 banner_height: 914400,
730 logo_width: 2011680,
731 logo_height: 438912,
732 logo_x_offset: 295125,
733 logo_y_offset: 237744,
734 },
735 );
736 doc.set_raw_header_with_images(
737 cover_banner,
738 &[("rId1", &logo_img, "logo.png")],
739 rdocx_oxml::header_footer::HdrFtrType::First,
740 );
741 doc.set_margins(
742 Length::twips(2292),
743 Length::twips(1440),
744 Length::twips(1440),
745 Length::twips(1440),
746 );
747 doc.set_header_footer_distance(Length::twips(720), Length::twips(432));
748 doc.set_footer("Tensorbee — Confidential");
749
750 doc.add_style(
752 StyleBuilder::paragraph("ProposalTitle", "Proposal Title")
753 .based_on("Normal")
754 .run_properties({
755 let mut rpr = rdocx_oxml::properties::CT_RPr::default();
756 rpr.bold = Some(true);
757 rpr.font_ascii = Some("Georgia".to_string());
758 rpr.font_hansi = Some("Georgia".to_string());
759 rpr.sz = Some(rdocx_oxml::HalfPoint(56)); rpr.color = Some("1B2A4A".to_string());
761 rpr
762 }),
763 );
764
765 for _ in 0..4 {
767 doc.add_paragraph("");
768 }
769 doc.add_paragraph("AI Platform Modernization")
770 .style("ProposalTitle")
771 .alignment(Alignment::Center);
772 doc.add_paragraph("")
773 .alignment(Alignment::Center)
774 .border_bottom(BorderStyle::Single, 8, "C5922E");
775 {
776 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
777 p.add_run("Prepared for Global Financial Corp.")
778 .size(14.0)
779 .color("666666")
780 .italic(true);
781 }
782 {
783 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
784 p.add_run("Prepared by: Walter White, CEO — Tensorbee")
785 .size(12.0)
786 .color("888888");
787 }
788 {
789 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
790 p.add_run("February 22, 2026").size(12.0).color("888888");
791 }
792
793 doc.add_paragraph("").page_break_before(true);
795 doc.add_paragraph("Table of Contents").style("Heading1");
796 doc.insert_toc(doc.content_count(), 2);
798
799 doc.add_paragraph("").page_break_before(true);
801 doc.add_paragraph("Executive Summary").style("Heading1");
802 doc.add_paragraph(
803 "Tensorbee proposes a comprehensive modernization of Global Financial Corp's AI platform, \
804 transitioning from legacy batch-processing systems to a real-time inference architecture. \
805 This transformation will reduce model deployment time from weeks to hours, improve \
806 prediction accuracy by an estimated 23%, and deliver $4.2M in annual operational savings.",
807 )
808 .first_line_indent(Length::inches(0.3));
809 doc.add_paragraph(
810 "The project spans three phases over 18 months, with a total investment of $2.8M. \
811 Tensorbee brings deep expertise in ML infrastructure, having successfully completed \
812 similar transformations for three Fortune 500 financial institutions.",
813 )
814 .first_line_indent(Length::inches(0.3));
815
816 doc.add_paragraph("");
818 {
819 let mut tbl = doc
820 .add_table(5, 2)
821 .borders(BorderStyle::Single, 4, "1B2A4A")
822 .width_pct(80.0);
823 tbl.cell(0, 0).unwrap().set_text("Key Metric");
824 tbl.cell(0, 0).unwrap().shading("1B2A4A");
825 tbl.cell(0, 1).unwrap().set_text("Value");
826 tbl.cell(0, 1).unwrap().shading("1B2A4A");
827 let rows = [
828 ("Total Investment", "$2.8M"),
829 ("Annual Savings", "$4.2M"),
830 ("ROI (Year 1)", "150%"),
831 ("Timeline", "18 months"),
832 ];
833 for (i, (k, v)) in rows.iter().enumerate() {
834 tbl.cell(i + 1, 0).unwrap().set_text(k);
835 if i % 2 == 0 {
836 tbl.cell(i + 1, 0).unwrap().shading("F4F1EB");
837 }
838 tbl.cell(i + 1, 1).unwrap().set_text(v);
839 if i % 2 == 0 {
840 tbl.cell(i + 1, 1).unwrap().shading("F4F1EB");
841 }
842 }
843 }
844
845 doc.add_paragraph("").page_break_before(true);
847 doc.add_paragraph("Problem Statement").style("Heading1");
848 doc.add_paragraph(
849 "Global Financial Corp's current AI infrastructure faces three critical challenges:",
850 );
851 doc.add_numbered_list_item("Deployment Latency — New models take 3-4 weeks to deploy to production, compared to the industry benchmark of 2-3 days.", 0);
852 doc.add_numbered_list_item("Scalability Constraints — The batch processing architecture cannot handle real-time inference demands during peak trading hours.", 0);
853 doc.add_numbered_list_item("Technical Debt — Legacy Python 2.7 codebases and manual deployment scripts create reliability risks and slow iteration speed.", 0);
854
855 doc.add_paragraph("").page_break_before(true);
857 doc.add_paragraph("Proposed Solution").style("Heading1");
858
859 doc.add_paragraph("Phase 1: Foundation (Months 1-6)")
860 .style("Heading2");
861 doc.add_bullet_list_item("Deploy Kubernetes-based ML serving infrastructure", 0);
862 doc.add_bullet_list_item("Implement CI/CD pipeline for model deployment", 0);
863 doc.add_bullet_list_item("Migrate top 5 production models to new platform", 0);
864
865 doc.add_paragraph("Phase 2: Expansion (Months 7-12)")
866 .style("Heading2");
867 doc.add_bullet_list_item(
868 "Real-time feature engineering pipeline (Apache Kafka + Flink)",
869 0,
870 );
871 doc.add_bullet_list_item("A/B testing framework for model variants", 0);
872 doc.add_bullet_list_item("Automated model monitoring and drift detection", 0);
873
874 doc.add_paragraph("Phase 3: Optimization (Months 13-18)")
875 .style("Heading2");
876 doc.add_bullet_list_item("GPU inference optimization (TensorRT/ONNX Runtime)", 0);
877 doc.add_bullet_list_item("Multi-region deployment for latency reduction", 0);
878 doc.add_bullet_list_item(
879 "Self-service model deployment portal for data science teams",
880 0,
881 );
882
883 doc.add_paragraph("Budget Breakdown").style("Heading1");
885 {
886 let mut tbl = doc
887 .add_table(6, 3)
888 .borders(BorderStyle::Single, 4, "1B2A4A")
889 .width_pct(100.0);
890 tbl.cell(0, 0).unwrap().set_text("Category");
891 tbl.cell(0, 0).unwrap().shading("1B2A4A");
892 tbl.cell(0, 1).unwrap().set_text("Cost");
893 tbl.cell(0, 1).unwrap().shading("1B2A4A");
894 tbl.cell(0, 2).unwrap().set_text("Notes");
895 tbl.cell(0, 2).unwrap().shading("1B2A4A");
896 let items = [
897 (
898 "Infrastructure",
899 "$450,000",
900 "Cloud compute + GPU instances",
901 ),
902 ("Engineering Services", "$1,600,000", "12 FTE x 18 months"),
903 (
904 "Software Licenses",
905 "$350,000",
906 "Kafka, monitoring, CI/CD tools",
907 ),
908 (
909 "Training & Enablement",
910 "$200,000",
911 "Team training, documentation",
912 ),
913 ("Contingency (10%)", "$200,000", "Risk buffer"),
914 ];
915 for (i, (cat, cost, note)) in items.iter().enumerate() {
916 tbl.cell(i + 1, 0).unwrap().set_text(cat);
917 tbl.cell(i + 1, 1).unwrap().set_text(cost);
918 tbl.cell(i + 1, 2).unwrap().set_text(note);
919 if i % 2 == 0 {
920 tbl.cell(i + 1, 0).unwrap().shading("F4F1EB");
921 tbl.cell(i + 1, 1).unwrap().shading("F4F1EB");
922 tbl.cell(i + 1, 2).unwrap().shading("F4F1EB");
923 }
924 }
925 }
926
927 doc.add_paragraph("");
929 doc.add_paragraph("Next Steps").style("Heading1");
930 doc.add_numbered_list_item(
931 "Schedule technical deep-dive with GFC engineering team (Week 1)",
932 0,
933 );
934 doc.add_numbered_list_item("Finalize scope and sign SOW (Week 2-3)", 0);
935 doc.add_numbered_list_item("Kick off Phase 1 with joint planning session (Week 4)", 0);
936
937 doc.add_paragraph("");
938 {
939 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
940 p.add_run("Walter White")
941 .bold(true)
942 .size(14.0)
943 .color("1B2A4A");
944 }
945 {
946 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
947 p.add_run("CEO, Tensorbee | walter@tensorbee.com")
948 .size(10.0)
949 .color("888888");
950 }
951
952 doc
953}
954
955fn generate_quote(_samples_dir: &Path) -> Document {
959 let mut doc = Document::new();
960
961 doc.set_page_size(Length::inches(8.5), Length::inches(11.0));
963 doc.set_margins(
964 Length::inches(0.75),
965 Length::inches(0.75),
966 Length::inches(0.75),
967 Length::inches(0.75),
968 );
969 doc.set_title("Quotation QT-2026-0147");
970 doc.set_author("Walter White");
971 doc.set_keywords("quote, BOM, Tensorbee");
972
973 doc.set_header("Tensorbee — Quotation");
974 doc.set_footer("QT-2026-0147 | Page");
975
976 {
978 let mut p = doc.add_paragraph("").alignment(Alignment::Left);
979 p.add_run("TENSORBEE")
980 .bold(true)
981 .size(28.0)
982 .color("008B8B")
983 .font("Helvetica");
984 }
985 doc.add_paragraph("123 Innovation Drive, Suite 400")
986 .alignment(Alignment::Left);
987 doc.add_paragraph("San Francisco, CA 94105 | +1 (415) 555-0199")
988 .alignment(Alignment::Left);
989 doc.add_paragraph("")
990 .border_bottom(BorderStyle::Single, 8, "008B8B");
991
992 doc.add_paragraph("");
994 {
995 let mut tbl = doc.add_table(4, 4).width_pct(100.0);
996 tbl.cell(0, 0).unwrap().set_text("QUOTATION");
997 tbl.cell(0, 0).unwrap().shading("008B8B").grid_span(2);
998 tbl.cell(0, 2).unwrap().set_text("DATE");
999 tbl.cell(0, 2).unwrap().shading("008B8B");
1000 tbl.cell(0, 3).unwrap().set_text("VALID UNTIL");
1001 tbl.cell(0, 3).unwrap().shading("008B8B");
1002 tbl.cell(1, 0).unwrap().set_text("Quote #:");
1003 tbl.cell(1, 1).unwrap().set_text("QT-2026-0147");
1004 tbl.cell(1, 2).unwrap().set_text("Feb 22, 2026");
1005 tbl.cell(1, 3).unwrap().set_text("Mar 22, 2026");
1006 tbl.cell(2, 0).unwrap().set_text("Prepared by:");
1007 tbl.cell(2, 1).unwrap().set_text("Walter White");
1008 tbl.cell(2, 2).unwrap().set_text("Payment:");
1009 tbl.cell(2, 3).unwrap().set_text("Net 30");
1010 tbl.cell(3, 0).unwrap().set_text("Customer:");
1011 tbl.cell(3, 1).unwrap().set_text("Meridian Dynamics LLC");
1012 tbl.cell(3, 2).unwrap().set_text("Currency:");
1013 tbl.cell(3, 3).unwrap().set_text("USD");
1014 }
1015
1016 doc.add_paragraph("");
1017
1018 {
1020 let mut p = doc.add_paragraph("");
1021 p.add_run("Bill of Materials")
1022 .bold(true)
1023 .size(16.0)
1024 .color("1A3C3C");
1025 }
1026 doc.add_paragraph("");
1027
1028 {
1029 let mut tbl = doc
1030 .add_table(10, 6)
1031 .borders(BorderStyle::Single, 2, "008B8B")
1032 .width_pct(100.0)
1033 .layout_fixed();
1034 let hdrs = [
1036 "#",
1037 "Part Number",
1038 "Description",
1039 "Qty",
1040 "Unit Price",
1041 "Total",
1042 ];
1043 for (c, h) in hdrs.iter().enumerate() {
1044 tbl.cell(0, c).unwrap().set_text(h);
1045 tbl.cell(0, c).unwrap().shading("008B8B");
1046 }
1047
1048 let items: Vec<(&str, &str, &str, &str, &str)> = vec![
1049 (
1050 "TB-GPU-A100",
1051 "NVIDIA A100 80GB GPU",
1052 "4",
1053 "$12,500.00",
1054 "$50,000.00",
1055 ),
1056 (
1057 "TB-SRV-R750",
1058 "Dell R750xa Server Chassis",
1059 "2",
1060 "$8,200.00",
1061 "$16,400.00",
1062 ),
1063 (
1064 "TB-RAM-256G",
1065 "256GB DDR5 ECC Memory Module",
1066 "8",
1067 "$890.00",
1068 "$7,120.00",
1069 ),
1070 (
1071 "TB-SSD-3840",
1072 "3.84TB NVMe U.2 SSD",
1073 "8",
1074 "$1,150.00",
1075 "$9,200.00",
1076 ),
1077 (
1078 "TB-NET-CX7",
1079 "ConnectX-7 200GbE NIC",
1080 "4",
1081 "$1,800.00",
1082 "$7,200.00",
1083 ),
1084 (
1085 "TB-SW-48P",
1086 "48-Port 100GbE Switch",
1087 "1",
1088 "$22,000.00",
1089 "$22,000.00",
1090 ),
1091 (
1092 "TB-CAB-RACK",
1093 "42U Server Rack + PDU",
1094 "1",
1095 "$4,500.00",
1096 "$4,500.00",
1097 ),
1098 (
1099 "TB-SVC-INST",
1100 "Installation & Configuration",
1101 "1",
1102 "$8,500.00",
1103 "$8,500.00",
1104 ),
1105 (
1106 "TB-SVC-SUPP",
1107 "3-Year Premium Support",
1108 "1",
1109 "$15,000.00",
1110 "$15,000.00",
1111 ),
1112 ];
1113
1114 for (i, (pn, desc, qty, unit, total)) in items.iter().enumerate() {
1115 let row = i + 1;
1116 tbl.cell(row, 0).unwrap().set_text(&format!("{}", i + 1));
1117 tbl.cell(row, 1).unwrap().set_text(pn);
1118 tbl.cell(row, 2).unwrap().set_text(desc);
1119 tbl.cell(row, 3).unwrap().set_text(qty);
1120 tbl.cell(row, 4).unwrap().set_text(unit);
1121 tbl.cell(row, 5).unwrap().set_text(total);
1122 if i % 2 == 0 {
1123 for c in 0..6 {
1124 tbl.cell(row, c).unwrap().shading("F0F8F8");
1125 }
1126 }
1127 }
1128 }
1129
1130 doc.add_paragraph("");
1131
1132 {
1134 let mut tbl = doc
1135 .add_table(4, 2)
1136 .borders(BorderStyle::Single, 2, "008B8B")
1137 .width(Length::inches(3.5))
1138 .alignment(Alignment::Right);
1139 tbl.cell(0, 0).unwrap().set_text("Subtotal");
1140 tbl.cell(0, 1).unwrap().set_text("$139,920.00");
1141 tbl.cell(1, 0).unwrap().set_text("Shipping & Handling");
1142 tbl.cell(1, 1).unwrap().set_text("$2,500.00");
1143 tbl.cell(2, 0).unwrap().set_text("Tax (8.625%)");
1144 tbl.cell(2, 1).unwrap().set_text("$12,068.10");
1145 tbl.cell(3, 0).unwrap().set_text("TOTAL");
1146 tbl.cell(3, 0).unwrap().shading("E07020");
1147 tbl.cell(3, 1).unwrap().set_text("$154,488.10");
1148 tbl.cell(3, 1).unwrap().shading("E07020");
1149 }
1150
1151 doc.add_paragraph("");
1152
1153 {
1155 let mut p = doc.add_paragraph("");
1156 p.add_run("Terms & Conditions")
1157 .bold(true)
1158 .size(14.0)
1159 .color("1A3C3C");
1160 }
1161 doc.add_numbered_list_item(
1162 "This quotation is valid for 30 calendar days from the date of issue.",
1163 0,
1164 );
1165 doc.add_numbered_list_item(
1166 "All prices are in USD and exclusive of applicable taxes unless stated.",
1167 0,
1168 );
1169 doc.add_numbered_list_item("Standard lead time is 4-6 weeks from PO receipt.", 0);
1170 doc.add_numbered_list_item(
1171 "Payment terms: Net 30 from invoice date. 2% discount for payment within 10 days.",
1172 0,
1173 );
1174 doc.add_numbered_list_item(
1175 "Warranty: 3-year manufacturer warranty on all hardware components.",
1176 0,
1177 );
1178 doc.add_numbered_list_item(
1179 "Returns subject to 15% restocking fee if initiated after 14 days.",
1180 0,
1181 );
1182
1183 doc.add_paragraph("");
1184 doc.add_paragraph("")
1185 .border_bottom(BorderStyle::Single, 4, "008B8B");
1186 doc.add_paragraph("");
1187 {
1188 let mut p = doc.add_paragraph("");
1189 p.add_run("Accepted by: ").bold(true);
1190 p.add_run("___________________________ Date: ___________");
1191 }
1192 {
1193 let mut p = doc.add_paragraph("");
1194 p.add_run("Print Name: ").bold(true);
1195 p.add_run("___________________________ Title: ___________");
1196 }
1197
1198 doc
1199}
1200
1201fn generate_invoice(_samples_dir: &Path) -> Document {
1205 let mut doc = Document::new();
1206
1207 doc.set_page_size(Length::inches(8.5), Length::inches(11.0));
1209 doc.set_margins(
1210 Length::inches(0.75),
1211 Length::inches(0.75),
1212 Length::inches(0.75),
1213 Length::inches(0.75),
1214 );
1215 doc.set_title("Invoice INV-2026-0392");
1216 doc.set_author("Walter White");
1217 doc.set_keywords("invoice, Tensorbee");
1218
1219 doc.set_footer("Tensorbee — Thank you for your business!");
1220
1221 {
1223 let mut tbl = doc.add_table(4, 2).width_pct(100.0);
1224 {
1226 let mut cell = tbl.cell(0, 0).unwrap();
1227 let mut p = cell.add_paragraph("");
1228 p.add_run("TENSORBEE")
1229 .bold(true)
1230 .size(32.0)
1231 .color("B22222")
1232 .font("Helvetica");
1233 }
1234 {
1235 let mut cell = tbl.cell(0, 1).unwrap();
1236 let mut p = cell.add_paragraph("");
1237 p.add_run("INVOICE").bold(true).size(32.0).color("333333");
1238 }
1239 tbl.cell(1, 0)
1240 .unwrap()
1241 .set_text("123 Innovation Drive, Suite 400");
1242 tbl.cell(1, 1).unwrap().set_text("Invoice #: INV-2026-0392");
1243 tbl.cell(2, 0).unwrap().set_text("San Francisco, CA 94105");
1244 tbl.cell(2, 1).unwrap().set_text("Date: February 22, 2026");
1245 tbl.cell(3, 0).unwrap().set_text("walter@tensorbee.com");
1246 tbl.cell(3, 1).unwrap().set_text("Due Date: March 24, 2026");
1247 }
1248
1249 doc.add_paragraph("")
1250 .border_bottom(BorderStyle::Thick, 8, "B22222");
1251 doc.add_paragraph("");
1252
1253 {
1255 let mut tbl = doc.add_table(4, 2).width_pct(100.0);
1256 tbl.cell(0, 0).unwrap().set_text("BILL TO");
1257 tbl.cell(0, 0).unwrap().shading("B22222");
1258 tbl.cell(0, 1).unwrap().set_text("SHIP TO");
1259 tbl.cell(0, 1).unwrap().shading("B22222");
1260 tbl.cell(1, 0).unwrap().set_text("Meridian Dynamics LLC");
1261 tbl.cell(1, 1).unwrap().set_text("Meridian Dynamics LLC");
1262 tbl.cell(2, 0).unwrap().set_text("456 Enterprise Blvd");
1263 tbl.cell(2, 1).unwrap().set_text("Attn: Server Room B");
1264 tbl.cell(3, 0).unwrap().set_text("Austin, TX 78701");
1265 tbl.cell(3, 1)
1266 .unwrap()
1267 .set_text("456 Enterprise Blvd, Austin, TX 78701");
1268 }
1269
1270 doc.add_paragraph("");
1271
1272 {
1274 let mut tbl = doc
1275 .add_table(8, 5)
1276 .borders(BorderStyle::Single, 2, "B22222")
1277 .width_pct(100.0);
1278 let hdrs = ["Description", "Qty", "Unit Price", "Tax", "Amount"];
1279 for (c, h) in hdrs.iter().enumerate() {
1280 tbl.cell(0, c).unwrap().set_text(h);
1281 tbl.cell(0, c).unwrap().shading("B22222");
1282 }
1283 let items = [
1284 (
1285 "ML Infrastructure Setup — Phase 1",
1286 "1",
1287 "$45,000.00",
1288 "$3,881.25",
1289 "$48,881.25",
1290 ),
1291 (
1292 "Data Pipeline Development (160 hrs)",
1293 "160",
1294 "$225.00",
1295 "$3,105.00",
1296 "$39,105.00",
1297 ),
1298 (
1299 "GPU Cluster Configuration",
1300 "1",
1301 "$12,000.00",
1302 "$1,035.00",
1303 "$13,035.00",
1304 ),
1305 (
1306 "API Gateway Implementation",
1307 "1",
1308 "$18,500.00",
1309 "$1,595.63",
1310 "$20,095.63",
1311 ),
1312 (
1313 "Load Testing & QA (80 hrs)",
1314 "80",
1315 "$195.00",
1316 "$1,345.50",
1317 "$16,945.50",
1318 ),
1319 (
1320 "Documentation & Training",
1321 "1",
1322 "$8,000.00",
1323 "$690.00",
1324 "$8,690.00",
1325 ),
1326 (
1327 "Project Management (3 months)",
1328 "3",
1329 "$6,500.00",
1330 "$1,679.63",
1331 "$21,179.63",
1332 ),
1333 ];
1334 for (i, (desc, qty, unit, tax, amt)) in items.iter().enumerate() {
1335 let r = i + 1;
1336 tbl.cell(r, 0).unwrap().set_text(desc);
1337 tbl.cell(r, 1).unwrap().set_text(qty);
1338 tbl.cell(r, 2).unwrap().set_text(unit);
1339 tbl.cell(r, 3).unwrap().set_text(tax);
1340 tbl.cell(r, 4).unwrap().set_text(amt);
1341 if i % 2 == 0 {
1342 for c in 0..5 {
1343 tbl.cell(r, c).unwrap().shading("FAF0F0");
1344 }
1345 }
1346 }
1347 }
1348
1349 doc.add_paragraph("");
1350
1351 {
1353 let mut tbl = doc
1354 .add_table(4, 2)
1355 .borders(BorderStyle::Single, 2, "B22222")
1356 .width(Length::inches(3.0))
1357 .alignment(Alignment::Right);
1358 tbl.cell(0, 0).unwrap().set_text("Subtotal");
1359 tbl.cell(0, 1).unwrap().set_text("$154,600.00");
1360 tbl.cell(1, 0).unwrap().set_text("Tax (8.625%)");
1361 tbl.cell(1, 1).unwrap().set_text("$13,334.25");
1362 tbl.cell(2, 0).unwrap().set_text("Discount (5%)");
1363 tbl.cell(2, 1).unwrap().set_text("-$7,730.00");
1364 tbl.cell(3, 0).unwrap().set_text("AMOUNT DUE");
1365 tbl.cell(3, 0).unwrap().shading("B22222");
1366 tbl.cell(3, 1).unwrap().set_text("$160,204.25");
1367 tbl.cell(3, 1).unwrap().shading("B22222");
1368 }
1369
1370 doc.add_paragraph("");
1371 doc.add_paragraph("");
1372
1373 {
1375 let mut p = doc.add_paragraph("");
1376 p.add_run("Payment Details")
1377 .bold(true)
1378 .size(14.0)
1379 .color("333333");
1380 }
1381 doc.add_paragraph("Bank: Silicon Valley Bank")
1382 .indent_left(Length::inches(0.3));
1383 doc.add_paragraph("Account: Tensorbee Inc. — 0847-2953-1120")
1384 .indent_left(Length::inches(0.3));
1385 doc.add_paragraph("Routing: 121140399")
1386 .indent_left(Length::inches(0.3));
1387 doc.add_paragraph("Swift: SVBKUS6S")
1388 .indent_left(Length::inches(0.3));
1389
1390 doc.add_paragraph("");
1391
1392 doc.add_paragraph("Please include invoice number INV-2026-0392 in the payment reference.")
1393 .shading("FAF0F0")
1394 .border_all(BorderStyle::Single, 2, "B22222");
1395
1396 doc
1397}
1398
1399fn generate_report(_samples_dir: &Path) -> Document {
1403 let mut doc = Document::new();
1404
1405 doc.set_page_size(Length::inches(8.5), Length::inches(11.0));
1407 doc.set_margins(
1408 Length::inches(1.0),
1409 Length::inches(1.0),
1410 Length::inches(1.0),
1411 Length::inches(1.0),
1412 );
1413 doc.set_title("Q4 2025 Environmental Impact Report");
1414 doc.set_author("Walter White");
1415 doc.set_subject("Quarterly Environmental Report");
1416 doc.set_keywords("environment, sustainability, report, Tensorbee");
1417
1418 doc.set_different_first_page(true);
1419 doc.set_first_page_header("");
1420 doc.set_header("Tensorbee — Q4 2025 Environmental Impact Report");
1421 doc.set_footer("CONFIDENTIAL — Page");
1422
1423 let cover_bg = create_sample_png(612, 792, [20, 50, 15]);
1425 doc.add_background_image(&cover_bg, "report_cover.png");
1426
1427 for _ in 0..5 {
1428 doc.add_paragraph("");
1429 }
1430 {
1431 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
1432 p.add_run("Q4 2025")
1433 .bold(true)
1434 .size(48.0)
1435 .color("FFFFFF")
1436 .font("Georgia");
1437 }
1438 {
1439 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
1440 p.add_run("Environmental Impact Report")
1441 .size(24.0)
1442 .color("90EE90")
1443 .font("Georgia")
1444 .italic(true);
1445 }
1446 doc.add_paragraph("");
1447 {
1448 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
1449 p.add_run("Tensorbee — Sustainability Division")
1450 .size(14.0)
1451 .color("C0C0C0");
1452 }
1453 {
1454 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
1455 p.add_run("Prepared by Walter White, Chief Sustainability Officer")
1456 .size(11.0)
1457 .color("AAAAAA");
1458 }
1459
1460 doc.add_paragraph("").page_break_before(true);
1462 doc.insert_toc(doc.content_count(), 3);
1463
1464 doc.add_paragraph("").page_break_before(true);
1466 doc.add_paragraph("Executive Overview").style("Heading1");
1467 doc.add_paragraph(
1468 "This report presents Tensorbee's environmental performance for Q4 2025. Our \
1469 sustainability initiatives have yielded a 34% reduction in carbon emissions compared \
1470 to Q4 2024, exceeding our target of 25%. Key achievements include the transition to \
1471 100% renewable energy in our primary data centers and the launch of our carbon offset \
1472 marketplace.",
1473 )
1474 .first_line_indent(Length::inches(0.3));
1475
1476 let chart_img = create_chart_png(400, 200);
1478 doc.add_paragraph("");
1479 doc.add_picture(
1480 &chart_img,
1481 "performance_chart.png",
1482 Length::inches(5.0),
1483 Length::inches(2.5),
1484 )
1485 .alignment(Alignment::Center);
1486 {
1487 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
1488 p.add_run("Figure 1: Quarterly Carbon Emissions (tonnes CO2e)")
1489 .italic(true)
1490 .size(9.0)
1491 .color("666666");
1492 }
1493
1494 doc.add_paragraph("").page_break_before(true);
1496 doc.add_paragraph("Energy Consumption").style("Heading1");
1497
1498 doc.add_paragraph("Data Center Operations")
1499 .style("Heading2");
1500 doc.add_paragraph(
1501 "Our three primary data centers consumed a combined 4.2 GWh in Q4 2025, \
1502 a 12% reduction from Q3 2025 driven by improved cooling efficiency and \
1503 server consolidation.",
1504 );
1505
1506 {
1508 let mut tbl = doc
1509 .add_table(5, 4)
1510 .borders(BorderStyle::Single, 4, "2D5016")
1511 .width_pct(100.0);
1512 let hdrs = ["Data Center", "Capacity (MW)", "Usage (GWh)", "PUE"];
1513 for (c, h) in hdrs.iter().enumerate() {
1514 tbl.cell(0, c).unwrap().set_text(h);
1515 tbl.cell(0, c).unwrap().shading("2D5016");
1516 }
1517 let rows = [
1518 ("San Francisco (Primary)", "3.2", "1.8", "1.12"),
1519 ("Dublin (EU)", "2.1", "1.2", "1.18"),
1520 ("Singapore (APAC)", "1.8", "1.2", "1.24"),
1521 ("TOTAL", "7.1", "4.2", "1.17 avg"),
1522 ];
1523 for (i, (dc, cap, use_, pue)) in rows.iter().enumerate() {
1524 tbl.cell(i + 1, 0).unwrap().set_text(dc);
1525 tbl.cell(i + 1, 1).unwrap().set_text(cap);
1526 tbl.cell(i + 1, 2).unwrap().set_text(use_);
1527 tbl.cell(i + 1, 3).unwrap().set_text(pue);
1528 if i == 3 {
1529 for c in 0..4 {
1530 tbl.cell(i + 1, c).unwrap().shading("E2EFDA");
1531 }
1532 }
1533 }
1534 }
1535
1536 doc.add_paragraph("");
1537
1538 doc.add_paragraph("Renewable Energy Mix").style("Heading2");
1539 doc.add_paragraph("Breakdown of energy sources across all facilities:");
1540
1541 doc.add_bullet_list_item("Solar PV: 42% (1.76 GWh)", 0);
1542 doc.add_bullet_list_item("Wind Power Purchase Agreements: 38% (1.60 GWh)", 0);
1543 doc.add_bullet_list_item("Hydroelectric: 12% (0.50 GWh)", 0);
1544 doc.add_bullet_list_item("Grid (non-renewable): 8% (0.34 GWh)", 0);
1545
1546 doc.add_paragraph("Water & Waste Management")
1548 .style("Heading1");
1549
1550 doc.add_paragraph("Water Usage").style("Heading2");
1551 doc.add_paragraph(
1552 "Total water consumption was 12.4 million gallons, a 15% reduction from Q3. \
1553 Our closed-loop cooling systems now recycle 78% of water used in cooling operations.",
1554 );
1555
1556 doc.add_paragraph("Waste Reduction").style("Heading2");
1557 doc.add_paragraph("E-waste management results for Q4:")
1558 .keep_with_next(true);
1559 {
1560 let mut tbl = doc
1561 .add_table(4, 3)
1562 .borders(BorderStyle::Single, 2, "6B8E23")
1563 .width_pct(80.0);
1564 tbl.cell(0, 0).unwrap().set_text("Category");
1565 tbl.cell(0, 0).unwrap().shading("6B8E23");
1566 tbl.cell(0, 1).unwrap().set_text("Weight (kg)");
1567 tbl.cell(0, 1).unwrap().shading("6B8E23");
1568 tbl.cell(0, 2).unwrap().set_text("Recycled %");
1569 tbl.cell(0, 2).unwrap().shading("6B8E23");
1570 let rows = [
1571 ("Server Hardware", "2,450", "94%"),
1572 ("Networking Equipment", "820", "91%"),
1573 ("Storage Media", "340", "99%"),
1574 ];
1575 for (i, (cat, wt, pct)) in rows.iter().enumerate() {
1576 tbl.cell(i + 1, 0).unwrap().set_text(cat);
1577 tbl.cell(i + 1, 1).unwrap().set_text(wt);
1578 tbl.cell(i + 1, 2).unwrap().set_text(pct);
1579 }
1580 }
1581
1582 doc.add_paragraph("").page_break_before(true);
1584 doc.add_paragraph("Q1 2026 Initiatives").style("Heading1");
1585
1586 doc.add_paragraph("Planned Programs").style("Heading2");
1587 doc.add_numbered_list_item(
1588 "Deploy on-site battery storage at SF data center (2 MWh capacity)",
1589 0,
1590 );
1591 doc.add_numbered_list_item("Pilot immersion cooling in Dublin facility", 0);
1592 doc.add_numbered_list_item("Launch employee commute carbon offset program", 0);
1593 doc.add_numbered_list_item("Achieve ISO 14001 certification for Singapore facility", 0);
1594
1595 doc.add_paragraph("Investment Targets").style("Heading2");
1596 doc.add_paragraph("Sustainability CapEx allocation for FY2026:")
1597 .keep_with_next(true);
1598 {
1599 let mut tbl = doc
1600 .add_table(5, 2)
1601 .borders(BorderStyle::Single, 4, "2D5016");
1602 tbl.cell(0, 0).unwrap().set_text("Initiative");
1603 tbl.cell(0, 0).unwrap().shading("2D5016");
1604 tbl.cell(0, 1).unwrap().set_text("Budget");
1605 tbl.cell(0, 1).unwrap().shading("2D5016");
1606 let rows = [
1607 ("Battery Storage", "$1.2M"),
1608 ("Immersion Cooling Pilot", "$800K"),
1609 ("Solar Panel Expansion", "$2.1M"),
1610 ("Carbon Credits", "$500K"),
1611 ];
1612 for (i, (init, budget)) in rows.iter().enumerate() {
1613 tbl.cell(i + 1, 0).unwrap().set_text(init);
1614 tbl.cell(i + 1, 1).unwrap().set_text(budget);
1615 if i % 2 == 0 {
1616 tbl.cell(i + 1, 0).unwrap().shading("FFFAF0");
1617 tbl.cell(i + 1, 1).unwrap().shading("FFFAF0");
1618 }
1619 }
1620 }
1621
1622 let roadmap_img = create_sample_png(500, 100, [40, 80, 30]);
1624 doc.add_paragraph("");
1625 doc.add_picture(
1626 &roadmap_img,
1627 "roadmap.png",
1628 Length::inches(6.0),
1629 Length::inches(1.2),
1630 )
1631 .alignment(Alignment::Center);
1632 {
1633 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
1634 p.add_run("Figure 2: 2026 Sustainability Roadmap")
1635 .italic(true)
1636 .size(9.0)
1637 .color("666666");
1638 }
1639
1640 doc.add_paragraph("");
1641 doc.add_paragraph(
1642 "For questions about this report, contact Walter White at sustainability@tensorbee.com.",
1643 )
1644 .shading("FFFAF0")
1645 .border_all(BorderStyle::Single, 2, "2D5016");
1646
1647 doc
1648}
1649
1650fn generate_letter(_samples_dir: &Path) -> Document {
1654 let mut doc = Document::new();
1655
1656 doc.set_page_size(Length::inches(8.5), Length::inches(11.0));
1658 doc.set_margins(
1659 Length::inches(1.25),
1660 Length::inches(1.25),
1661 Length::inches(1.25),
1662 Length::inches(1.25),
1663 );
1664 doc.set_title("Business Letter");
1665 doc.set_author("Walter White");
1666
1667 let logo_img = create_logo_png(220, 48);
1669 let banner = build_header_banner_xml(
1670 "rId1",
1671 &BannerOpts {
1672 bg_color: "4A5568",
1673 banner_width: 7772400,
1674 banner_height: 731520, logo_width: 2011680,
1676 logo_height: 438912,
1677 logo_x_offset: 295125,
1678 logo_y_offset: 146304,
1679 },
1680 );
1681 doc.set_raw_header_with_images(
1682 banner,
1683 &[("rId1", &logo_img, "logo.png")],
1684 rdocx_oxml::header_footer::HdrFtrType::Default,
1685 );
1686 doc.set_margins(
1687 Length::twips(2000),
1688 Length::twips(1800),
1689 Length::twips(1440),
1690 Length::twips(1800),
1691 );
1692 doc.set_header_footer_distance(Length::twips(720), Length::twips(432));
1693
1694 doc.set_footer(
1696 "Tensorbee | 123 Innovation Drive, Suite 400 | San Francisco, CA 94105 | tensorbee.com",
1697 );
1698
1699 doc.add_paragraph("Walter White");
1701 doc.add_paragraph("Chief Executive Officer");
1702 doc.add_paragraph("Tensorbee");
1703 doc.add_paragraph("123 Innovation Drive, Suite 400");
1704 doc.add_paragraph("San Francisco, CA 94105");
1705 doc.add_paragraph("");
1706 doc.add_paragraph("February 22, 2026");
1707
1708 doc.add_paragraph("");
1709
1710 doc.add_paragraph("Ms. Sarah Chen");
1712 doc.add_paragraph("VP of Engineering");
1713 doc.add_paragraph("Meridian Dynamics LLC");
1714 doc.add_paragraph("456 Enterprise Boulevard");
1715 doc.add_paragraph("Austin, TX 78701");
1716
1717 doc.add_paragraph("");
1718
1719 {
1721 let mut p = doc.add_paragraph("");
1722 p.add_run("Re: Strategic Technology Partnership — Phase 2 Expansion")
1723 .bold(true);
1724 }
1725
1726 doc.add_paragraph("");
1727
1728 doc.add_paragraph("Dear Ms. Chen,");
1730 doc.add_paragraph("");
1731
1732 doc.add_paragraph(
1733 "I am writing to express Tensorbee's enthusiasm for expanding our strategic technology \
1734 partnership with Meridian Dynamics. Following the successful completion of Phase 1, \
1735 which delivered a 40% improvement in your ML inference pipeline throughput, we believe \
1736 the foundation is firmly established for an ambitious Phase 2 engagement.",
1737 )
1738 .first_line_indent(Length::inches(0.5));
1739
1740 doc.add_paragraph(
1741 "During our recent executive review, your team highlighted three priority areas for \
1742 the next phase of collaboration:",
1743 )
1744 .first_line_indent(Length::inches(0.5));
1745
1746 doc.add_numbered_list_item(
1747 "Real-time anomaly detection for your financial transaction monitoring system, \
1748 targeting sub-100ms latency at 50,000 transactions per second.",
1749 0,
1750 );
1751 doc.add_numbered_list_item(
1752 "Federated learning infrastructure to enable model training across your distributed \
1753 data centers without centralizing sensitive financial data.",
1754 0,
1755 );
1756 doc.add_numbered_list_item(
1757 "MLOps automation to reduce your model deployment cycle from the current 5 days \
1758 to under 4 hours.",
1759 0,
1760 );
1761
1762 doc.add_paragraph(
1763 "Our engineering team has prepared a detailed technical proposal addressing each of \
1764 these areas. We have allocated a dedicated team of eight senior engineers, led by \
1765 our CTO, to ensure continuity with the Phase 1 team your organization has already \
1766 built a productive working relationship with.",
1767 )
1768 .first_line_indent(Length::inches(0.5));
1769
1770 doc.add_paragraph(
1771 "I would welcome the opportunity to present our Phase 2 proposal in person. My \
1772 assistant will reach out to coordinate a meeting at your convenience during the \
1773 first week of March.",
1774 )
1775 .first_line_indent(Length::inches(0.5));
1776
1777 doc.add_paragraph("");
1778
1779 doc.add_paragraph("Warm regards,");
1780 doc.add_paragraph("");
1781 doc.add_paragraph("");
1782
1783 doc.add_paragraph("")
1785 .border_bottom(BorderStyle::Single, 4, "4A5568");
1786 {
1787 let mut p = doc.add_paragraph("");
1788 p.add_run("Walter White").bold(true).size(12.0);
1789 }
1790 {
1791 let mut p = doc.add_paragraph("");
1792 p.add_run("Chief Executive Officer, Tensorbee")
1793 .italic(true)
1794 .size(10.0)
1795 .color("666666");
1796 }
1797 {
1798 let mut p = doc.add_paragraph("");
1799 p.add_run("walter@tensorbee.com | +1 (415) 555-0199")
1800 .size(10.0)
1801 .color("888888");
1802 }
1803
1804 doc
1805}
1806
1807fn generate_contract(_samples_dir: &Path) -> Document {
1811 let mut doc = Document::new();
1812
1813 doc.set_page_size(Length::inches(8.5), Length::inches(11.0));
1815 doc.set_margins(
1816 Length::inches(1.25),
1817 Length::inches(1.0),
1818 Length::inches(1.0),
1819 Length::inches(1.0),
1820 );
1821 doc.set_title("Employment Agreement");
1822 doc.set_author("Tensorbee HR Department");
1823 doc.set_subject("Employment Contract — Walter White");
1824 doc.set_keywords("employment, contract, agreement, Tensorbee");
1825
1826 doc.set_header("TENSORBEE — Employment Agreement");
1827 doc.set_footer("Employment Agreement — Walter White — Page");
1828
1829 doc.add_paragraph("")
1831 .border_bottom(BorderStyle::Thick, 12, "5B2C6F");
1832 {
1833 let mut p = doc.add_paragraph("").alignment(Alignment::Center);
1834 p.add_run("EMPLOYMENT AGREEMENT")
1835 .bold(true)
1836 .size(24.0)
1837 .color("5B2C6F")
1838 .font("Georgia");
1839 }
1840 doc.add_paragraph("")
1841 .border_bottom(BorderStyle::Thick, 12, "5B2C6F");
1842 doc.add_paragraph("");
1843
1844 doc.add_paragraph(
1846 "This Employment Agreement (\"Agreement\") is entered into as of February 22, 2026 \
1847 (\"Effective Date\"), by and between:",
1848 );
1849
1850 doc.add_paragraph("");
1851
1852 {
1853 let mut p = doc.add_paragraph("").indent_left(Length::inches(0.5));
1854 p.add_run("EMPLOYER: ").bold(true);
1855 p.add_run(
1856 "Tensorbee, Inc., a Delaware corporation with its principal place of business at \
1857 123 Innovation Drive, Suite 400, San Francisco, CA 94105 (\"Company\")",
1858 );
1859 }
1860 doc.add_paragraph("");
1861 {
1862 let mut p = doc.add_paragraph("").indent_left(Length::inches(0.5));
1863 p.add_run("EMPLOYEE: ").bold(true);
1864 p.add_run(
1865 "Walter White, residing at 308 Negra Arroyo Lane, Albuquerque, NM 87104 (\"Employee\")",
1866 );
1867 }
1868
1869 doc.add_paragraph("");
1870 doc.add_paragraph("The Company and Employee are collectively referred to as the \"Parties.\"");
1871 doc.add_paragraph("");
1872
1873 doc.add_paragraph("Article 1 — Position and Duties")
1875 .style("Heading1");
1876 {
1877 let mut p = doc.add_paragraph("");
1878 p.add_run("1.1 ").bold(true);
1879 p.add_run("The Company hereby employs the Employee as ");
1880 p.add_run("Chief Executive Officer (CEO)")
1881 .bold(true)
1882 .italic(true);
1883 p.add_run(", reporting directly to the Board of Directors.");
1884 }
1885 {
1886 let mut p = doc.add_paragraph("");
1887 p.add_run("1.2 ").bold(true);
1888 p.add_run("The Employee shall devote full working time, attention, and best efforts to \
1889 the performance of duties as reasonably assigned by the Board, including but not limited to:");
1890 }
1891 doc.add_bullet_list_item(
1892 "Setting and executing the Company's strategic vision and business plan",
1893 0,
1894 );
1895 doc.add_bullet_list_item(
1896 "Overseeing all operations, engineering, and commercial activities",
1897 0,
1898 );
1899 doc.add_bullet_list_item(
1900 "Representing the Company to investors, customers, and the public",
1901 0,
1902 );
1903 doc.add_bullet_list_item("Recruiting, developing, and retaining key talent", 0);
1904
1905 {
1906 let mut p = doc.add_paragraph("");
1907 p.add_run("1.3 ").bold(true);
1908 p.add_run(
1909 "The Employee's primary work location shall be the Company's San Francisco \
1910 headquarters, with reasonable travel as required by business needs.",
1911 );
1912 }
1913
1914 doc.add_paragraph("Article 2 — Compensation and Benefits")
1916 .style("Heading1");
1917 {
1918 let mut p = doc.add_paragraph("");
1919 p.add_run("2.1 Base Salary. ").bold(true);
1920 p.add_run("The Company shall pay the Employee an annual base salary of ");
1921 p.add_run("$375,000.00").bold(true);
1922 p.add_run(" (Three Hundred Seventy-Five Thousand Dollars), payable in accordance with the \
1923 Company's standard payroll schedule, less applicable withholdings and deductions.");
1924 }
1925 {
1926 let mut p = doc.add_paragraph("");
1927 p.add_run("2.2 Annual Bonus. ").bold(true);
1928 p.add_run("The Employee shall be eligible for an annual performance bonus of up to ");
1929 p.add_run("40%").bold(true);
1930 p.add_run(
1931 " of base salary, based on achievement of mutually agreed performance objectives.",
1932 );
1933 }
1934 {
1935 let mut p = doc.add_paragraph("");
1936 p.add_run("2.3 Equity. ").bold(true);
1937 p.add_run("Subject to Board approval, the Employee shall receive a stock option grant of ");
1938 p.add_run("500,000 shares").bold(true);
1939 p.add_run(
1940 " of the Company's common stock, vesting over four (4) years with a one-year cliff, \
1941 at an exercise price equal to the fair market value on the date of grant.",
1942 );
1943 }
1944
1945 doc.add_paragraph("");
1947 {
1948 let mut tbl = doc
1949 .add_table(5, 2)
1950 .borders(BorderStyle::Single, 4, "5B2C6F")
1951 .width_pct(70.0)
1952 .alignment(Alignment::Center);
1953 tbl.cell(0, 0).unwrap().set_text("Compensation Element");
1954 tbl.cell(0, 0).unwrap().shading("5B2C6F");
1955 tbl.cell(0, 1).unwrap().set_text("Value");
1956 tbl.cell(0, 1).unwrap().shading("5B2C6F");
1957 let items = [
1958 ("Base Salary", "$375,000/year"),
1959 ("Target Bonus", "Up to 40% ($150,000)"),
1960 ("Equity Grant", "500,000 shares (4yr vest)"),
1961 ("Total Target Comp", "$525,000 + equity"),
1962 ];
1963 for (i, (elem, val)) in items.iter().enumerate() {
1964 tbl.cell(i + 1, 0).unwrap().set_text(elem);
1965 tbl.cell(i + 1, 1).unwrap().set_text(val);
1966 if i == 3 {
1967 tbl.cell(i + 1, 0).unwrap().shading("E8DAEF");
1968 tbl.cell(i + 1, 1).unwrap().shading("E8DAEF");
1969 }
1970 }
1971 }
1972
1973 doc.add_paragraph("").page_break_before(true);
1975 doc.add_paragraph("Article 3 — Benefits").style("Heading1");
1976 {
1977 let mut p = doc.add_paragraph("");
1978 p.add_run("3.1 ").bold(true);
1979 p.add_run(
1980 "The Employee shall be entitled to participate in all benefit programs \
1981 generally available to senior executives, including:",
1982 );
1983 }
1984 doc.add_bullet_list_item(
1985 "Medical, dental, and vision insurance (100% premium coverage for employee and dependents)",
1986 0,
1987 );
1988 doc.add_bullet_list_item("401(k) retirement plan with 6% company match", 0);
1989 doc.add_bullet_list_item("Life insurance and long-term disability coverage", 0);
1990 doc.add_bullet_list_item("Annual professional development allowance of $10,000", 0);
1991
1992 {
1993 let mut p = doc.add_paragraph("");
1994 p.add_run("3.2 Paid Time Off. ").bold(true);
1995 p.add_run(
1996 "The Employee shall receive 25 days of paid vacation per year, plus Company holidays, \
1997 accruing on a monthly basis.",
1998 );
1999 }
2000
2001 doc.add_paragraph("Article 4 — Term and Termination")
2003 .style("Heading1");
2004 {
2005 let mut p = doc.add_paragraph("");
2006 p.add_run("4.1 At-Will Employment. ").bold(true);
2007 p.add_run(
2008 "This Agreement is for at-will employment and may be terminated by either Party \
2009 at any time, with or without cause, subject to the notice provisions herein.",
2010 );
2011 }
2012 {
2013 let mut p = doc.add_paragraph("");
2014 p.add_run("4.2 Notice Period. ").bold(true);
2015 p.add_run("Either Party shall provide ");
2016 p.add_run("ninety (90) days").bold(true);
2017 p.add_run(" written notice of termination, or pay in lieu thereof.");
2018 }
2019 {
2020 let mut p = doc.add_paragraph("");
2021 p.add_run("4.3 Severance. ").bold(true);
2022 p.add_run("In the event of termination by the Company without Cause, the Employee shall \
2023 receive (a) twelve (12) months of base salary continuation, (b) pro-rata bonus \
2024 for the year of termination, and (c) twelve (12) months of COBRA premium coverage.");
2025 }
2026
2027 doc.add_paragraph("Article 5 — Confidentiality and IP")
2029 .style("Heading1");
2030 {
2031 let mut p = doc.add_paragraph("");
2032 p.add_run("5.1 ").bold(true);
2033 p.add_run(
2034 "The Employee agrees to maintain strict confidentiality of all proprietary \
2035 information, trade secrets, and business plans of the Company during and after \
2036 employment.",
2037 );
2038 }
2039 {
2040 let mut p = doc.add_paragraph("");
2041 p.add_run("5.2 ").bold(true);
2042 p.add_run(
2043 "All intellectual property, inventions, and works of authorship created by the \
2044 Employee during the term of employment and within the scope of duties shall be \
2045 the sole and exclusive property of the Company.",
2046 );
2047 }
2048
2049 doc.add_paragraph("Article 6 — Non-Competition")
2051 .style("Heading1");
2052 {
2053 let mut p = doc.add_paragraph("");
2054 p.add_run("6.1 ").bold(true);
2055 p.add_run("For a period of twelve (12) months following termination, the Employee agrees \
2056 not to engage in any business that directly competes with the Company's core \
2057 business of AI infrastructure and ML operations services, within the United States.");
2058 }
2059
2060 doc.add_paragraph("Article 7 — General Provisions")
2062 .style("Heading1");
2063 {
2064 let mut p = doc.add_paragraph("");
2065 p.add_run("7.1 Governing Law. ").bold(true);
2066 p.add_run(
2067 "This Agreement shall be governed by and construed in accordance with the laws of \
2068 the State of California.",
2069 );
2070 }
2071 {
2072 let mut p = doc.add_paragraph("");
2073 p.add_run("7.2 Entire Agreement. ").bold(true);
2074 p.add_run(
2075 "This Agreement constitutes the entire agreement between the Parties and supersedes \
2076 all prior negotiations, representations, and agreements.",
2077 );
2078 }
2079 {
2080 let mut p = doc.add_paragraph("");
2081 p.add_run("7.3 Amendment. ").bold(true);
2082 p.add_run(
2083 "This Agreement may only be amended by a written instrument signed by both Parties.",
2084 );
2085 }
2086
2087 doc.add_paragraph("").page_break_before(true);
2089 doc.add_paragraph("IN WITNESS WHEREOF, the Parties have executed this Employment Agreement as of the Effective Date.")
2090 .space_after(Length::pt(24.0));
2091
2092 {
2094 let mut tbl = doc.add_table(6, 2).width_pct(100.0);
2095 tbl.cell(0, 0).unwrap().set_text("FOR THE COMPANY:");
2096 tbl.cell(0, 0).unwrap().shading("5B2C6F");
2097 tbl.cell(0, 1).unwrap().set_text("EMPLOYEE:");
2098 tbl.cell(0, 1).unwrap().shading("5B2C6F");
2099
2100 tbl.cell(1, 0).unwrap().set_text("");
2101 tbl.cell(1, 1).unwrap().set_text("");
2102 tbl.row(1).unwrap().height(Length::pt(40.0));
2103
2104 tbl.cell(2, 0)
2105 .unwrap()
2106 .set_text("Signature: ___________________________");
2107 tbl.cell(2, 1)
2108 .unwrap()
2109 .set_text("Signature: ___________________________");
2110 tbl.cell(3, 0)
2111 .unwrap()
2112 .set_text("Name: Board Representative");
2113 tbl.cell(3, 1).unwrap().set_text("Name: Walter White");
2114 tbl.cell(4, 0)
2115 .unwrap()
2116 .set_text("Title: Chair, Board of Directors");
2117 tbl.cell(4, 1)
2118 .unwrap()
2119 .set_text("Title: Chief Executive Officer");
2120 tbl.cell(5, 0).unwrap().set_text("Date: _______________");
2121 tbl.cell(5, 1).unwrap().set_text("Date: _______________");
2122 }
2123
2124 doc
2125}
2126
2127fn create_sample_png(width: u32, height: u32, base_color: [u8; 3]) -> Vec<u8> {
2133 let mut pixels = Vec::with_capacity((width * height * 4) as usize);
2134 for y in 0..height {
2135 for x in 0..width {
2136 let fy = y as f64 / height as f64;
2137 let fx = x as f64 / width as f64;
2138 let r = (base_color[0] as f64 + (1.0 - fy) * 40.0).min(255.0) as u8;
2139 let g = (base_color[1] as f64 + fx * 30.0).min(255.0) as u8;
2140 let b = (base_color[2] as f64 + fy * 60.0).min(255.0) as u8;
2141 pixels.extend_from_slice(&[r, g, b, 255]);
2142 }
2143 }
2144 encode_png(width, height, &pixels)
2145}
2146
2147fn create_chart_png(width: u32, height: u32) -> Vec<u8> {
2149 let mut pixels = vec![0u8; (width * height * 4) as usize];
2150 for i in 0..pixels.len() / 4 {
2152 pixels[i * 4] = 255;
2153 pixels[i * 4 + 1] = 255;
2154 pixels[i * 4 + 2] = 255;
2155 pixels[i * 4 + 3] = 255;
2156 }
2157 let bars: Vec<(u32, u32, [u8; 3])> = vec![
2159 (30, 150, [45, 80, 22]), (100, 120, [45, 80, 22]), (170, 100, [45, 80, 22]), (240, 70, [45, 80, 22]), ];
2164 for (bx, bar_height, color) in &bars {
2165 let bar_width = 50;
2166 let y_start = height - bar_height;
2167 for y in y_start..height {
2168 for x in *bx..(*bx + bar_width).min(width) {
2169 let idx = ((y * width + x) * 4) as usize;
2170 if idx + 3 < pixels.len() {
2171 pixels[idx] = color[0];
2172 pixels[idx + 1] = color[1];
2173 pixels[idx + 2] = color[2];
2174 pixels[idx + 3] = 255;
2175 }
2176 }
2177 }
2178 }
2179 encode_png(width, height, &pixels)
2180}
2181
2182fn create_logo_png(width: u32, height: u32) -> Vec<u8> {
2184 let mut pixels = Vec::with_capacity((width * height * 4) as usize);
2185 for y in 0..height {
2186 for x in 0..width {
2187 let in_text_area =
2188 x > width / 8 && x < width * 7 / 8 && y > height / 4 && y < height * 3 / 4;
2189 if in_text_area {
2190 pixels.extend_from_slice(&[255, 255, 255, 255]);
2191 } else {
2192 pixels.extend_from_slice(&[255, 255, 255, 40]);
2193 }
2194 }
2195 }
2196 encode_png(width, height, &pixels)
2197}
2198
2199fn encode_png(width: u32, height: u32, pixels: &[u8]) -> Vec<u8> {
2204 let mut png = Vec::new();
2205 {
2206 use std::io::Write as _;
2207 png.write_all(&[137, 80, 78, 71, 13, 10, 26, 10]).unwrap();
2208
2209 let mut ihdr = Vec::new();
2210 ihdr.extend_from_slice(&width.to_be_bytes());
2211 ihdr.extend_from_slice(&height.to_be_bytes());
2212 ihdr.extend_from_slice(&[8, 6, 0, 0, 0]); write_chunk(&mut png, b"IHDR", &ihdr);
2214
2215 let mut raw = Vec::new();
2216 for y in 0..height {
2217 raw.push(0); let s = (y * width * 4) as usize;
2219 raw.extend_from_slice(&pixels[s..s + (width * 4) as usize]);
2220 }
2221 write_chunk(&mut png, b"IDAT", &zlib_store(&raw));
2222 write_chunk(&mut png, b"IEND", &[]);
2223 }
2224 png
2225}
2226
2227fn write_chunk(out: &mut Vec<u8>, ct: &[u8; 4], data: &[u8]) {
2228 use std::io::Write as _;
2229 out.write_all(&(data.len() as u32).to_be_bytes()).unwrap();
2230 out.write_all(ct).unwrap();
2231 out.write_all(data).unwrap();
2232 out.write_all(&crc32(ct, data).to_be_bytes()).unwrap();
2233}
2234
2235fn crc32(ct: &[u8], data: &[u8]) -> u32 {
2236 static T: std::sync::LazyLock<[u32; 256]> = std::sync::LazyLock::new(|| {
2237 let mut t = [0u32; 256];
2238 for n in 0..256u32 {
2239 let mut c = n;
2240 for _ in 0..8 {
2241 c = if c & 1 != 0 {
2242 0xEDB88320 ^ (c >> 1)
2243 } else {
2244 c >> 1
2245 };
2246 }
2247 t[n as usize] = c;
2248 }
2249 t
2250 });
2251 let mut c = 0xFFFFFFFF_u32;
2252 for &b in ct.iter().chain(data) {
2253 c = T[((c ^ b as u32) & 0xFF) as usize] ^ (c >> 8);
2254 }
2255 c ^ 0xFFFFFFFF
2256}
2257
2258fn zlib_store(data: &[u8]) -> Vec<u8> {
2259 let mut out = vec![0x78, 0x01];
2260 let chunks: Vec<&[u8]> = data.chunks(65535).collect();
2261 for (i, chunk) in chunks.iter().enumerate() {
2262 let last = i == chunks.len() - 1;
2263 out.push(if last { 0x01 } else { 0x00 });
2264 let len = chunk.len() as u16;
2265 out.extend_from_slice(&len.to_le_bytes());
2266 out.extend_from_slice(&(!len).to_le_bytes());
2267 out.extend_from_slice(chunk);
2268 }
2269 let (mut a, mut b) = (1u32, 0u32);
2270 for &byte in data {
2271 a = (a + byte as u32) % 65521;
2272 b = (b + a) % 65521;
2273 }
2274 out.extend_from_slice(&((b << 16) | a).to_be_bytes());
2275 out
2276}
2277
2278struct BannerOpts<'a> {
2283 bg_color: &'a str,
2284 banner_width: i64,
2285 banner_height: i64,
2286 logo_width: i64,
2287 logo_height: i64,
2288 logo_x_offset: i64,
2289 logo_y_offset: i64,
2290}
2291
2292fn build_header_banner_xml(image_rel_id: &str, opts: &BannerOpts) -> Vec<u8> {
2293 let mut xml = String::with_capacity(2048);
2294 write!(
2295 xml,
2296 r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>"#
2297 )
2298 .unwrap();
2299 write!(xml, r#"<w:hdr "#).unwrap();
2300 write!(
2301 xml,
2302 r#"xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" "#
2303 )
2304 .unwrap();
2305 write!(
2306 xml,
2307 r#"xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" "#
2308 )
2309 .unwrap();
2310 write!(
2311 xml,
2312 r#"xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" "#
2313 )
2314 .unwrap();
2315 write!(
2316 xml,
2317 r#"xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" "#
2318 )
2319 .unwrap();
2320 write!(
2321 xml,
2322 r#"xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture" "#
2323 )
2324 .unwrap();
2325 write!(
2326 xml,
2327 r#"xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" "#
2328 )
2329 .unwrap();
2330 write!(
2331 xml,
2332 r#"xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" "#
2333 )
2334 .unwrap();
2335 write!(
2336 xml,
2337 r#"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">"#
2338 )
2339 .unwrap();
2340 write!(xml, r#"<w:p><w:pPr><w:pStyle w:val="Header"/></w:pPr>"#).unwrap();
2341 write!(xml, r#"<w:r><w:rPr><w:noProof/></w:rPr>"#).unwrap();
2342 write!(
2343 xml,
2344 r#"<mc:AlternateContent><mc:Choice Requires="wpg"><w:drawing>"#
2345 )
2346 .unwrap();
2347 write!(
2348 xml,
2349 r#"<wp:anchor distT="0" distB="0" distL="0" distR="0" "#
2350 )
2351 .unwrap();
2352 write!(
2353 xml,
2354 r#"simplePos="0" relativeHeight="251658240" behindDoc="0" "#
2355 )
2356 .unwrap();
2357 write!(
2358 xml,
2359 r#"locked="0" layoutInCell="1" hidden="0" allowOverlap="1">"#
2360 )
2361 .unwrap();
2362 write!(xml, r#"<wp:simplePos x="0" y="0"/>"#).unwrap();
2363 write!(
2364 xml,
2365 r#"<wp:positionH relativeFrom="page"><wp:posOffset>0</wp:posOffset></wp:positionH>"#
2366 )
2367 .unwrap();
2368 write!(
2369 xml,
2370 r#"<wp:positionV relativeFrom="page"><wp:posOffset>0</wp:posOffset></wp:positionV>"#
2371 )
2372 .unwrap();
2373 write!(
2374 xml,
2375 r#"<wp:extent cx="{}" cy="{}"/>"#,
2376 opts.banner_width, opts.banner_height
2377 )
2378 .unwrap();
2379 write!(
2380 xml,
2381 r#"<wp:effectExtent l="0" t="0" r="0" b="0"/><wp:wrapNone/>"#
2382 )
2383 .unwrap();
2384 write!(
2385 xml,
2386 r#"<wp:docPr id="1" name="Header Banner"/><wp:cNvGraphicFramePr/>"#
2387 )
2388 .unwrap();
2389 write!(xml, r#"<a:graphic><a:graphicData uri="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup">"#).unwrap();
2390 write!(xml, r#"<wpg:wgp><wpg:cNvGrpSpPr/><wpg:grpSpPr><a:xfrm>"#).unwrap();
2391 write!(
2392 xml,
2393 r#"<a:off x="0" y="0"/><a:ext cx="{w}" cy="{h}"/>"#,
2394 w = opts.banner_width,
2395 h = opts.banner_height
2396 )
2397 .unwrap();
2398 write!(
2399 xml,
2400 r#"<a:chOff x="0" y="0"/><a:chExt cx="{w}" cy="{h}"/>"#,
2401 w = opts.banner_width,
2402 h = opts.banner_height
2403 )
2404 .unwrap();
2405 write!(xml, r#"</a:xfrm></wpg:grpSpPr>"#).unwrap();
2406 write!(
2408 xml,
2409 r#"<wps:wsp><wps:cNvPr id="2" name="BG"/><wps:cNvSpPr/><wps:spPr>"#
2410 )
2411 .unwrap();
2412 write!(
2413 xml,
2414 r#"<a:xfrm><a:off x="0" y="0"/><a:ext cx="{w}" cy="{h}"/></a:xfrm>"#,
2415 w = opts.banner_width,
2416 h = opts.banner_height
2417 )
2418 .unwrap();
2419 write!(xml, r#"<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>"#).unwrap();
2420 write!(
2421 xml,
2422 r#"<a:solidFill><a:srgbClr val="{}"/></a:solidFill>"#,
2423 opts.bg_color
2424 )
2425 .unwrap();
2426 write!(
2427 xml,
2428 r#"<a:ln><a:noFill/></a:ln></wps:spPr><wps:bodyPr/></wps:wsp>"#
2429 )
2430 .unwrap();
2431 write!(
2433 xml,
2434 r#"<pic:pic><pic:nvPicPr><pic:cNvPr id="3" name="Logo"/><pic:cNvPicPr/></pic:nvPicPr>"#
2435 )
2436 .unwrap();
2437 write!(xml, r#"<pic:blipFill><a:blip r:embed="{}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>"#, image_rel_id).unwrap();
2438 write!(
2439 xml,
2440 r#"<pic:spPr><a:xfrm><a:off x="{}" y="{}"/><a:ext cx="{}" cy="{}"/></a:xfrm>"#,
2441 opts.logo_x_offset, opts.logo_y_offset, opts.logo_width, opts.logo_height
2442 )
2443 .unwrap();
2444 write!(xml, r#"<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln></pic:spPr></pic:pic>"#).unwrap();
2445 write!(xml, r#"</wpg:wgp></a:graphicData></a:graphic>"#).unwrap();
2446 write!(
2447 xml,
2448 r#"</wp:anchor></w:drawing></mc:Choice></mc:AlternateContent>"#
2449 )
2450 .unwrap();
2451 write!(xml, r#"</w:r></w:p></w:hdr>"#).unwrap();
2452 xml.into_bytes()
2453}