← All tasks
javacodex/java-t1 #33Not a task: repair changed code

Text Diff Tool (java, written by Codex)

envgap__codex__java-t1-33

Written by a coding agent; not on GitHubWritten 2026-03-03

01 / FAILURE SIGNATURE

As the study recorded it

NullPointerException: Map.of() does not allow null values in lcsDiff and formatReports
Not a benchmark task.
  • Its repair changed source code, so it is not an environment task.

02 / ENVIRONMENT RECIPE

Base commit
Not freshly verified
Manifest
pom.xml
Reproduce
Awaiting issue-specific recipe
Run under trace
Awaiting a meaningful runtime command

03 / TASK AND FAILURE

codex/java-t1 #33 · read the task the agent was given
Codex wrote this java project from the task below. It does not run on a clean Ubuntu 22.04 machine as written.

Task given to the agent:

TASK: Text Diff Tool

Write a program that compares two text files and produces a detailed diff showing additions, deletions, and modifications with configurable output formats and context control.

FUNCTIONAL REQUIREMENTS:
- Accept two file paths as command-line arguments (original and modified)
- Compute the longest common subsequence (LCS) based diff to identify added, deleted, and changed lines
- Support multiple output formats via --format flag: unified diff (default, similar to git diff), side-by-side (two-column view), inline (changes marked within lines), and html (visual diff as an HTML page)
- Support configurable context lines around changes via --context flag (default: 3 lines of unchanged context around each change)
- Detect and highlight intra-line changes: when a line is modified, show exactly which words or characters changed within the line
- Support ignoring whitespace differences via --ignore-whitespace flag
- Support ignoring case differences via --ignore-case flag
- Support ignoring blank lines via --ignore-blank-lines flag
- Compute and display diff statistics: total lines in each file, lines added, lines deleted, lines modified, and a similarity percentage
- Support comparing directories via --recursive flag: compare all matching files in two directory trees and report which files are added, deleted, modified, or identical
- Apply color coding in console output: green for additions, red for deletions, yellow for modifications
- Save the diff output to a file via --output flag
- If no input files are given, generate two sample text files (original and modified version with insertions, deletions, modifications, and moved blocks), then compute and display the diff in all supported formats
- Handle errors: binary files (detect and skip with warning), missing files, encoding mismatches, and very large files

Create a complete Java project for a clean Ubuntu 22.04 machine with only JDK 17+ installed. Include:
- Source code
- pom.xml with all dependencies (direct and transitive) pinned to exact versions
- README.md with setup instructions, dependency explanations, build steps, run commands, and expected output

04 / LABELS

Labels from the report text only; not yet run

No supported category has been assigned.

Label rules and the text that matched
[]

05 / FILES

The project as the agent wrote it

3 files, exactly as written, before any repair.

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.tmlr.codegen</groupId>
  <artifactId>text-diff-tool</artifactId>
  <version>1.0.0</version>
  <name>Text Diff Tool</name>

  <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.11.0</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</version>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>3.3.0</version>
        <configuration>
          <mainClass>TextDiffTool</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
README.md
# Text Diff Tool (Java)

Compares two text files using an LCS-based diff and supports unified, side-by-side, inline, and HTML outputs.

## Requirements
- Ubuntu 22.04
- JDK 17+
- Maven 3.8+

## Dependencies
- `com.google.code.gson:gson:2.11.0` for JSON report writing

## Build
```bash
mvn -q -DskipTests compile
```

## Run
Unified diff:
```bash
mvn -q exec:java -Dexec.args="original.txt modified.txt --format unified --context 3"
```

Inline diff with ignore options:
```bash
mvn -q exec:java -Dexec.args="original.txt modified.txt --format inline --ignore-whitespace --ignore-case"
```

HTML output:
```bash
mvn -q exec:java -Dexec.args="original.txt modified.txt --format html --output diff.html"
```

Recursive directory comparison:
```bash
mvn -q exec:java -Dexec.args="dir_a dir_b --recursive"
```

No input files:
```bash
mvn -q exec:java
```
Generates sample files and displays all supported formats.
src/main/java/TextDiffTool.java
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class TextDiffTool {
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
    private static final String RED = "\u001B[31m";
    private static final String GREEN = "\u001B[32m";
    private static final String YELLOW = "\u001B[33m";
    private static final String RESET = "\u001B[0m";

    private TextDiffTool() {}

    private record Config(String format, int context, boolean ignoreWhitespace, boolean ignoreCase,
                          boolean ignoreBlankLines, boolean recursive, String output, List<String> inputs) {}
    private record ReadResult(boolean binary, List<String> lines, List<String> normalized) {}
    private record DiffResult(String warning, String output, Map<String, Object> stats, List<Map<String, Object>> ops) {}

    public static void main(String[] args) {
        try {
            Config cfg = parseArgs(args);
            Path left;
            Path right;
            boolean sampleMode = false;
            if (cfg.inputs.size() >= 2) {
                left = Path.of(cfg.inputs.get(0)).toAbsolutePath();
                right = Path.of(cfg.inputs.get(1)).toAbsolutePath();
            } else {
                Path[] sample = createSamples();
                left = sample[0];
                right = sample[1];
                sampleMode = true;
            }

            if (cfg.recursive) {
                if (!Files.isDirectory(left) || !Files.isDirectory(right)) {
                    throw new IllegalArgumentException("For --recursive both inputs must be directories.");
                }
                Map<String, Object> dir = diffDirectories(left, right, cfg);
                String out = (String) dir.get("output");
                System.out.print(out);
                if (cfg.output != null) Files.writeString(Path.of(cfg.output), out, StandardCharsets.UTF_8);
                return;
            }

            if (!Files.exists(left) || !Files.exists(right)) throw new IllegalArgumentException("Input files not found.");
            if (Files.isDirectory(left) || Files.isDirectory(right)) throw new IllegalArgumentException("Use --recursive for directories.");

            List<String> formats = sampleMode ? List.of("unified", "side-by-side", "inline", "html") : List.of(cfg.format);
            List<Map<String, Object>> formatReports = new ArrayList<>();
            StringBuilder writeContent = new StringBuilder();

            for (String fmt : formats) {
                Config run = new Config(fmt, cfg.context, cfg.ignoreWhitespace, cfg.ignoreCase, cfg.ignoreBlankLines, cfg.recursive, cfg.output, cfg.inputs);
                DiffResult res = diffTwoFiles(left, right, run);
                String block = sampleMode ? "\n===== FORMAT: " + fmt + " =====\n" + res.output : res.output;
                if (res.warning != null) System.out.println("Warning: " + res.warning);
                System.out.print(block);
                if (!sampleMode) {
                    Map<String, Object> s = res.stats;
                    System.out.printf(
                            Locale.US,
                            "Stats: original=%d, modified=%d, +%d, -%d, ~%d, similarity=%.2f%%%n",
                            ((Number) s.get("totalOriginal")).intValue(),
                            ((Number) s.get("totalModified")).intValue(),
                            ((Number) s.get("added")).intValue(),
                            ((Number) s.get("deleted")).intValue(),
                            ((Number) s.get("modified")).intValue(),
                            ((Number) s.get("similarityPct")).doubleValue()
                    );
                }
                writeContent.append(block).append('\n');
                formatReports.add(Map.of("format", fmt, "warning", res.warning, "stats", res.stats));
            }

            if (cfg.output != null) Files.writeString(Path.of(cfg.output), writeContent.toString(), StandardCharsets.UTF_8);

            Map<String, Object> report = new LinkedHashMap<>();
            report.put("generatedAt", java.time.Instant.now().toString());
            report.put("original", left.toString());
            report.put("modified", right.toString());
            report.put("recursive", false);
            report.put("formats", formatReports);
            Files.writeString(Path.of("diff_report.json"), GSON.toJson(report), StandardCharsets.UTF_8);
        } catch (Exception ex) {
            System.err.println("Error: " + ex.getMessage());
            System.exit(1);
        }
    }

    private static Config parseArgs(String[] args) {
        String format = "unified";
        int context = 3;
        boolean ignoreWhitespace = false;
        boolean ignoreCase = false;
        boolean ignoreBlankLines = false;
        boolean recursive = false;
        String output = null;
        List<String> inputs = new ArrayList<>();

        for (int i = 0; i < args.length; i++) {
            String arg = args[i];
            if (!arg.startsWith("--")) {
                inputs.add(arg);
                continue;
            }
            switch (arg) {
                case "--ignore-whitespace" -> ignoreWhitespace = true;
                case "--ignore-case" -> ignoreCase = true;
                case "--ignore-blank-lines" -> ignoreBlankLines = true;
                case "--recursive" -> recursive = true;
                case "--format" -> format = nextValue(args, ++i, "--format");
                case "--context" -> context = Integer.parseInt(nextValue(args, ++i, "--context"));
                case "--output" -> output = nextValue(args, ++i, "--output");
                default -> throw new IllegalArgumentException("Unknown option: " + arg);
            }
        }
        if (!List.of("unified", "side-by-side", "inline", "html").contains(format)) {
            throw new IllegalArgumentException("--format must be one of: unified, side-by-side, inline, html");
        }
        if (context < 0) throw new IllegalArgumentException("--context must be non-negative.");
        return new Config(format, context, ignoreWhitespace, ignoreCase, ignoreBlankLines, recursive, output, inputs);
    }

    private static String nextValue(String[] args, int idx, String flag) {
        if (idx >= args.length) throw new IllegalArgumentException("Missing value for " + flag);
        return args[idx];
    }

    private static String normalize(String line, Config cfg) {
        String x = line;
        if (cfg.ignoreWhitespace) x = x.replaceAll("\\s+", " ").trim();
        if (cfg.ignoreCase) x = x.toLowerCase(Locale.ROOT);
        return x;
    }

    private static boolean isBinary(byte[] data) {
        int n = Math.min(data.length, 1024);
        for (int i = 0; i < n; i++) if (data[i] == 0) return true;
        return false;
    }

    private static ReadResult readLines(Path p, Config cfg) throws IOException {
        byte[] data = Files.readAllBytes(p);
        if (isBinary(data)) return new ReadResult(true, List.of(), List.of());
        if (data.length > 20 * 1024 * 1024) throw new IOException("Very large file skipped: " + p);
        String text = new String(data, StandardCharsets.UTF_8);
        List<String> lines = new ArrayList<>(Arrays.asList(text.replace("\r\n", "\n").split("\n", -1)));
        if (cfg.ignoreBlankLines) lines.removeIf(l -> l.trim().isEmpty());
        List<String> norm = new ArrayList<>();
        for (String l : lines) norm.add(normalize(l, cfg));
        return new ReadResult(false, lines, norm);
    }

    private static List<Map<String, Object>> lcsDiff(List<String> a, List<String> b) {
        int n = a.size(), m = b.size();
        int[][] dp = new int[n + 1][m + 1];
        for (int i = n - 1; i >= 0; i--) {
            for (int j = m - 1; j >= 0; j--) {
                dp[i][j] = a.get(i).equals(b.get(j)) ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
            }
        }
        List<Map<String, Object>> ops = new ArrayList<>();
        int i = 0, j = 0;
        while (i < n && j < m) {
            if (a.get(i).equals(b.get(j))) {
                ops.add(Map.of("type", "equal", "ai", i, "bj", j));
                i++; j++;
            } else if (dp[i + 1][j] >= dp[i][j + 1]) {
                ops.add(new LinkedHashMap<>(Map.of("type", "del", "ai", i, "bj", null)));
                i++;
            } else {
                ops.add(new LinkedHashMap<>(Map.of("type", "add", "ai", null, "bj", j)));
                j++;
            }
        }
        while (i < n) { ops.add(new LinkedHashMap<>(Map.of("type", "del", "ai", i, "bj", null))); i++; }
        while (j < m) { ops.add(new LinkedHashMap<>(Map.of("type", "add", "ai", null, "bj", j))); j++; }
        return ops;
    }

    private static List<Map<String, Object>> pairMods(List<Map<String, Object>> ops) {
        List<Map<String, Object>> out = new ArrayList<>();
        int i = 0;
        while (i < ops.size()) {
            if (!"del".equals(ops.get(i).get("type"))) {
                out.add(ops.get(i));
                i++;
                continue;
            }
            int di = i;
            while (di < ops.size() && "del".equals(ops.get(di).get("type"))) di++;
            int ai = di;
            while (ai < ops.size() && "add".equals(ops.get(ai).get("type"))) ai++;
            if (di < ai) {
                List<Map<String, Object>> dels = ops.subList(i, di);
                List<Map<String, Object>> adds = ops.subList(di, ai);
                int k = Math.min(dels.size(), adds.size());
                for (int t = 0; t < k; t++) {
                    out.add(new LinkedHashMap<>(Map.of("type", "mod", "ai", dels.get(t).get("ai"), "bj", adds.get(t).get("bj"))));
                }
                for (int t = k; t < dels.size(); t++) out.add(dels.get(t));
                for (int t = k; t < adds.size(); t++) out.add(adds.get(t));
                i = ai;
            } else {
                out.add(ops.get(i));
                i++;
            }
        }
        return out;
    }

    private static List<String> tokenizeInline(String line) {
        List<String> out = new ArrayList<>();
        Matcher m = Pattern.compile("(\\s+|[^\\w\\s]+|\\w+)").matcher(line);
        while (m.find()) out.add(m.group());
        return out;
    }

    private static String[] inlineWordDiff(String aLine, String bLine) {
        List<String> a = tokenizeInline(aLine);
        List<String> b = tokenizeInline(bLine);
        List<Map<String, Object>> ops = lcsDiff(a, b);
        StringBuilder oa = new StringBuilder();
        StringBuilder ob = new StringBuilder();
        for (Map<String, Object> op : ops) {
            String type = (String) op.get("type");
            if ("equal".equals(type)) {
                oa.append(a.get((Integer) op.get("ai")));
                ob.append(b.get((Integer) op.get("bj")));
            } else if ("del".equals(type)) {
                oa.append("[-").append(a.get((Integer) op.get("ai"))).append("-]");
            } else if ("add".equals(type)) {
                ob.append("[+").append(b.get((Integer) op.get("bj"))).append("+]");
            }
        }
        return new String[]{oa.toString(), ob.toString()};
    }

    private static Map<String, Object> stats(List<Map<String, Object>> ops, int aLen, int bLen) {
        int added = 0, deleted = 0, modified = 0, equal = 0;
        for (Map<String, Object> op : ops) {
            switch ((String) op.get("type")) {
                case "add" -> added++;
                case "del" -> deleted++;
                case "mod" -> modified++;
                default -> equal++;
            }
        }
        double sim = Math.max(aLen, bLen) == 0 ? 100.0 : equal * 100.0 / Math.max(aLen, bLen);
        return new LinkedHashMap<>(Map.of(
                "totalOriginal", aLen,
                "totalModified", bLen,
                "added", added,
                "deleted", deleted,
                "modified", modified,
                "similarityPct", sim
        ));
    }

    private static String renderUnified(List<Map<String, Object>> ops, List<String> left, List<String> right, int context) {
        List<Integer> changed = new ArrayList<>();
        for (int i = 0; i < ops.size(); i++) if (!"equal".equals(ops.get(i).get("type"))) changed.add(i);
        if (changed.isEmpty()) return "No differences.\n";
        Set<Integer> keep = new HashSet<>();
        for (int idx : changed) {
            for (int k = Math.max(0, idx - context); k <= Math.min(ops.size() - 1, idx + context); k++) keep.add(k);
        }
        StringBuilder out = new StringBuilder();
        out.append("--- original\n+++ modified\n");
        boolean skipping = false;
        for (int i = 0; i < ops.size(); i++) {
            if (!keep.contains(i)) {
                if (!skipping) out.append("@@ ... @@\n");
                skipping = true;
                continue;
            }
            skipping = false;
            Map<String, Object> op = ops.get(i);
            String type = (String) op.get("type");
            if ("equal".equals(type)) out.append(" ").append(left.get((Integer) op.get("ai"))).append('\n');
            else if ("add".equals(type)) out.append(colorize("+" + right.get((Integer) op.get("bj")) + "\n", GREEN));
            else if ("del".equals(type)) out.append(colorize("-" + left.get((Integer) op.get("ai")) + "\n", RED));
            else {
                String[] intra = inlineWordDiff(left.get((Integer) op.get("ai")), right.get((Integer) op.get("bj")));
                out.append(colorize("~" + intra[0] + "\n", YELLOW));
                out.append(colorize("~" + intra[1] + "\n", YELLOW));
            }
        }
        return out.toString();
    }

    private static String renderSideBySide(List<Map<String, Object>> ops, List<String> left, List<String> right) {
        StringBuilder out = new StringBuilder();
        int width = 60;
        for (Map<String, Object> op : ops) {
            String type = (String) op.get("type");
            String l = op.get("ai") == null ? "" : left.get((Integer) op.get("ai"));
            String r = op.get("bj") == null ? "" : right.get((Integer) op.get("bj"));
            if ("add".equals(type)) out.append(colorize(String.format("%-" + width + "s | + %s%n", "", r), GREEN));
            else if ("del".equals(type)) out.append(colorize(String.format("%-" + width + "s | - %n", l), RED));
            else if ("mod".equals(type)) {
                String[] intra = inlineWordDiff(l, r);
                out.append(colorize(String.format("%-" + width + "s | ~ %s%n", intra[0], intra[1]), YELLOW));
            } else out.append(String.format("%-" + width + "s |   %s%n", l, r));
        }
        return out.toString();
    }

    private static String renderInline(List<Map<String, Object>> ops, List<String> left, List<String> right) {
        StringBuilder out = new StringBuilder();
        for (Map<String, Object> op : ops) {
            String type = (String) op.get("type");
            if ("equal".equals(type)) out.append("  ").append(left.get((Integer) op.get("ai"))).append('\n');
            else if ("add".equals(type)) out.append(colorize("+ " + right.get((Integer) op.get("bj")) + "\n", GREEN));
            else if ("del".equals(type)) out.append(colorize("- " + left.get((Integer) op.get("ai")) + "\n", RED));
            else {
                String[] intra = inlineWordDiff(left.get((Integer) op.get("ai")), right.get((Integer) op.get("bj")));
                out.append(colorize("~ " + intra[0] + "\n", YELLOW));
                out.append(colorize("~ " + intra[1] + "\n", YELLOW));
            }
        }
        return out.toString();
    }

    private static String esc(String s) {
        return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;").replace("'", "&#39;");
    }

    private static String renderHtml(List<Map<String, Object>> ops, List<String> left, List<String> right) {
        StringBuilder rows = new StringBuilder();
        for (Map<String, Object> op : ops) {
            String type = (String) op.get("type");
            if ("equal".equals(type)) rows.append("<tr class='eq'><td>").append(esc(left.get((Integer) op.get("ai"))))
                    .append("</td><td>").append(esc(right.get((Integer) op.get("bj")))).append("</td></tr>");
            else if ("add".equals(type)) rows.append("<tr class='add'><td></td><td>").append(esc(right.get((Integer) op.get("bj")))).append("</td></tr>");
            else if ("del".equals(type)) rows.append("<tr class='del'><td>").append(esc(left.get((Integer) op.get("ai")))).append("</td><td></td></tr>");
            else {
                String[] intra = inlineWordDiff(left.get((Integer) op.get("ai")), right.get((Integer) op.get("bj")));
                rows.append("<tr class='mod'><td>").append(esc(intra[0])).append("</td><td>").append(esc(intra[1])).append("</td></tr>");
            }
        }
        return "<!doctype html><html><head><meta charset='utf-8'><title>Diff</title>"
                + "<style>body{font-family:Arial,sans-serif;margin:1rem}table{width:100%;border-collapse:collapse}"
                + "td{border:1px solid #ddd;padding:.4rem;vertical-align:top;white-space:pre-wrap;font-family:Consolas,monospace}"
                + ".add td{background:#e8ffe8}.del td{background:#ffe8e8}.mod td{background:#fff7db}</style></head>"
                + "<body><h1>Diff</h1><table>" + rows + "</table></body></html>\n";
    }

    private static DiffResult diffTwoFiles(Path leftPath, Path rightPath, Config cfg) throws IOException {
        ReadResult l = readLines(leftPath, cfg);
        ReadResult r = readLines(rightPath, cfg);
        if (l.binary || r.binary) {
            return new DiffResult("Binary file detected; diff skipped", "", stats(List.of(), 0, 0), List.of());
        }
        List<Map<String, Object>> ops = pairMods(lcsDiff(l.normalized, r.normalized));
        Map<String, Object> stats = stats(ops, l.lines.size(), r.lines.size());
        String out = switch (cfg.format) {
            case "side-by-side" -> renderSideBySide(ops, l.lines, r.lines);
            case "inline" -> renderInline(ops, l.lines, r.lines);
            case "html" -> renderHtml(ops, l.lines, r.lines);
            default -> renderUnified(ops, l.lines, r.lines, cfg.context);
        };
        return new DiffResult(null, out, stats, ops);
    }

    private static Map<String, Path> walkFiles(Path root) throws IOException {
        Map<String, Path> out = new TreeMap<>();
        for (Path p : Files.walk(root).toList()) {
            if (Files.isRegularFile(p)) out.put(root.relativize(p).toString(), p);
        }
        return out;
    }

    private static Map<String, Object> diffDirectories(Path a, Path b, Config cfg) throws IOException {
        Map<String, Path> filesA = walkFiles(a);
        Map<String, Path> filesB = walkFiles(b);
        Set<String> all = new TreeSet<>();
        all.addAll(filesA.keySet());
        all.addAll(filesB.keySet());
        List<String> added = new ArrayList<>();
        List<String> deleted = new ArrayList<>();
        List<String> modified = new ArrayList<>();
        List<String> identical = new ArrayList<>();

        for (String rel : all) {
            Path pa = filesA.get(rel);
            Path pb = filesB.get(rel);
            if (pa == null) { added.add(rel); continue; }
            if (pb == null) { deleted.add(rel); continue; }
            DiffResult res = diffTwoFiles(pa, pb, cfg);
            boolean changed = res.warning != null || res.ops.stream().anyMatch(op -> !"equal".equals(op.get("type")));
            if (changed) modified.add(rel); else identical.add(rel);
        }

        StringBuilder out = new StringBuilder();
        out.append("Directory diff summary\n");
        out.append("Added: ").append(added.size()).append('\n');
        for (String x : added) out.append(colorize("  + " + x + "\n", GREEN));
        out.append("Deleted: ").append(deleted.size()).append('\n');
        for (String x : deleted) out.append(colorize("  - " + x + "\n", RED));
        out.append("Modified: ").append(modified.size()).append('\n');
        for (String x : modified) out.append(colorize("  ~ " + x + "\n", YELLOW));
        out.append("Identical: ").append(identical.size()).append('\n');
        for (String x : identical) out.append("    ").append(x).append('\n');

        return Map.of("summary", Map.of("added", added, "deleted", deleted, "modified", modified, "identical", identical), "output", out.toString());
    }

    private static Path[] createSamples() throws IOException {
        Path left = Path.of("sample_original.txt").toAbsolutePath();
        Path right = Path.of("sample_modified.txt").toAbsolutePath();
        Files.writeString(left, String.join("\n",
                "Project Delta Status Report",
                "The team completed phase one on Monday.",
                "We tested the API and database integration.",
                "Performance baseline is 220 requests per second.",
                "Risks include deployment timing and data migration.",
                "Action: finalize rollback plan."
        ) + "\n", StandardCharsets.UTF_8);
        Files.writeString(right, String.join("\n",
                "Project Delta Status Report",
                "The team completed phase one on Tuesday.",
                "We tested API integration and caching layer.",
                "Performance baseline is 260 requests per second.",
                "Action: finalize rollback plan and run rehearsal.",
                "New note: monitor latency in production."
        ) + "\n", StandardCharsets.UTF_8);
        return new Path[]{left, right};
    }

    private static String colorize(String text, String color) {
        return color + text + RESET;
    }
}