Add SIN.04028 tutorial material, tutor prompt and conversation log

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 15:11:02 +02:00
co-authored by Claude Opus 5
parent bac80295b7
commit f615bef426
30 changed files with 8123 additions and 0 deletions
@@ -0,0 +1,68 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.Instant;
import java.util.Arrays;
import java.util.UUID;
final class FileMessageBoard {
static final Path ROOT = Path.of(
System.getProperty("messageBoard.root", "messageBoard")
).toAbsolutePath().normalize();
private FileMessageBoard() {}
static String serialize(Message message) {
var text = message.type() + "\n" + message.value();
if (message.timestamp() != null)
text += "\nTIMESTAMP: " + message.timestamp();
return text;
}
static Message read(Path file) throws IOException {
var lines = Files.readString(file).split("\\R", -1);
if (lines.length < 2)
throw new IOException("A message needs a type and a value: " + file);
var endOfValue = lines.length;
Instant timestamp = null;
var lastLine = lines[lines.length - 1];
if (lastLine.startsWith("TIMESTAMP: ")) {
timestamp = Instant.parse(lastLine.substring("TIMESTAMP: ".length()));
endOfValue--;
}
var value = String.join(
"\n",
Arrays.copyOfRange(lines, 1, endOfValue)
);
return new Message(lines[0], value, timestamp);
}
static void publish(String mailbox, Message message) throws IOException {
var directory = directory(mailbox);
Files.createDirectories(directory);
var id = UUID.randomUUID().toString();
var temporary = directory.resolve(id + ".tmp");
var published = directory.resolve(id + ".msg");
Files.writeString(temporary, serialize(message));
Files.move(temporary, published, StandardCopyOption.ATOMIC_MOVE);
}
static Path directory(String name) {
var directory = ROOT.resolve(name).normalize();
if (!directory.startsWith(ROOT))
throw new IllegalArgumentException("Mailbox escapes the message board");
return directory;
}
}