Chunked Stream Reader I
You are given an API you cannot modify:
readChunk() -> string // next chunk of a log stream; "" means end of stream
The judge implements readChunk and passes it into your code: it is the argument your LineReader constructor receives (a plain callback in JavaScript, TypeScript, and Python; a Supplier<String> in Java; a function<string()> in C++; a func() string in Go). Don't define it yourself, and don't call it as a global — use the one handed to you.
Chunks split arbitrarily: one chunk may contain several lines, and one line may span several chunks. Implement a LineReader class whose readLine() returns the next complete line WITHOUT the newline; the final line may lack a trailing newline; return null once the stream is exhausted. Call readChunk lazily — only when you do not already have a complete line buffered.
Example:
chunks: ["ab", "c\nde", "f\n"] -> readLine(): "abc", then "def", then null chunks: ["a\n\nb"] -> "a", "" (empty line preserved), "b"
Hints
Hint 1
Keep two pieces of state: a queue of complete lines ready to serve, and the fragments of the current unterminated line. chunk.split("\n") tells you everything — every piece except the last completes a line, and the last piece is the new partial. Join fragments only when a line completes, and flush the partial at EOF.
Hint 2
Pull a chunk only when no complete line is waiting — that is the lazy requirement.