A music library may contain several playlists, but a listener wants one uninterrupted stream of songs. When one playlist ends, the cursor should quietly move to the next non-empty playlist. From the caller's point of view, the whole library behaves like a single collection.
Playlist and MusicLibrary are already implemented for you. Your task is to implement only the Iterator pattern participants:
SongCursor, the shared contract implemented by both cursor types.PlaylistCursor, which walks the songs in one playlist.CompositeCursor, which combines several playlist cursors into one library-wide traversal.PlaylistCursor receives a Playlist. CompositeCursor receives a MusicLibrary and may use the provided playlistCount() and playlistAt(index) helpers. Both cursors must implement hasNext(), next(), remaining(), and sourceName().
The pre-implemented MusicLibrary exposes the following API to the tests:
MusicLibrary() creates a library with no playlists and no cursors.int addPlaylist(String name) appends an empty playlist and returns its id, counting from 1.boolean addSong(int playlistId, String title) appends a song to that playlist and returns true, or returns false for an id that does not exist.int songCount() returns how many songs the whole library holds.int openCursor() opens a cursor over every playlist, in the order they were added, and returns its id, counting from 1.boolean hasNext(int cursorId) returns whether a song is left anywhere from the cursor's position onward. An id that was never handed out returns false.String next(int cursorId) returns the cursor's next song and moves it along. A cursor with nothing left returns "END", and an unknown id returns "NONE".String sourcePlaylist(int cursorId) returns the name of the playlist the cursor's most recent song came from. A cursor that has returned no song yet returns "NONE", as does an unknown id.int remaining(int cursorId) returns how many songs the cursor has left, or -1 for an unknown id.An empty playlist contributes nothing. A cursor steps over it and carries on with the next one, however many empty playlists sit in a row. A library with no playlists, or with nothing but empty ones, produces a cursor that is finished before it starts.
A cursor reads the library as it stands at the time of each call, so a song added to a playlist the cursor has not reached yet is part of the run. A cursor leaves a playlist only when a call finds that playlist used up.
Two cursors over the same library hold their own positions. Unknown cursor ids and invalid playlist ids are handled by the provided library code, leaving you to focus on composing iterators and maintaining cursor state.
Input:
Output:
Explanation: Pop and Classics hold two songs each and the empty Chill playlist between them contributes nothing. The cursor returns all four songs in order, and after the third one it names Classics as the source.
Input:
Output:
Explanation: Two cursors walk the same three songs. One has taken two and has one left, the other has taken one and has two left, and both name Pop as the playlist their last song came from.
1 <= name.length <= 401 <= title.length <= 406 playlists are stored in one library.10 songs are stored in one playlist.-100 <= playlistId <= 100-100 <= cursorId <= 100100 calls in total are made across all methods.Full marks when the walk over a single playlist and the walk over the whole library satisfy the same contract, and the library-wide walk holds a per-playlist walk and forwards to it. Lose points heavily when the position lives on `MusicLibrary`, or when the library-wide walk is a flat copy of every song taken at the moment the cursor opens.
Full marks when moving on repeats until a playlist with a song is found or the playlists run out, so any run of empty playlists at the front, in the middle or at the back changes nothing about the sequence. Lose points when a single empty playlist ends the walk, or when the step-over is written as a one-off check.
Full marks when two cursors over one library hold separate positions, an exhausted cursor returns `END`, `remaining` counts across every playlist still ahead, `sourcePlaylist` names the playlist the last song came from, and an unknown id answers `NONE` or `-1`. Lose points for printing to stdout.
Passing every test is not enough on its own. A submission is accepted only when the design also clears the bar.
| Call | Returns |
|---|---|
| new MusicLibrary() | null |
| addPlaylist("Pop") | 1 |
| addPlaylist("Chill") | 2 |
| addPlaylist("Classics") | 3 |
| addSong(1, "Shape of You") | true |
| addSong(1, "Bohemian Rhapsody") | true |
| addSong(3, "Imagine") | true |
| addSong(3, "Yesterday") | true |
| songCount() | 4 |
| openCursor() | 1 |
| next(1) | "Shape of You" |
| next(1) | "Bohemian Rhapsody" |
| next(1) | "Imagine" |
| sourcePlaylist(1) | "Classics" |
| next(1) | "Yesterday" |
| hasNext(1) | false |
| next(1) | "END" |
Pop and Classics hold two songs each and the empty Chill playlist between them contributes nothing. The cursor returns all four songs in order, and after the third one it names Classics as the source.
Run checks these cases. Submit also runs a larger hidden set.

