Orders, tickets, and sessions all need identifiers that never collide. When two parts of an application hand out identifiers, they must draw from one sequence.
IdGenerator starts as an ordinary class. Its constructor is public and getInstance() builds a new object on every call, so two components that ask for the generator each start their own sequence at ID-1 and hand out duplicates. Your task is to turn IdGenerator into a thread-safe singleton and complete its methods.
IdGate is the driver used by the judge. It asks IdGenerator for two handles independently and requests identifiers through both. It is already complete and must not be modified.
IdGenerator.getInstance() returns one controlled, thread-safe instance. Code outside the class must not be able to construct a second one.String nextId() advances the sequence and returns the new identifier. The first identifier is "ID-1", the next is "ID-2", and so on.int issuedCount() returns how many identifiers have been issued since the last reset.void reset() restarts the sequence so the next identifier is "ID-1" again. It changes only the counter; the singleton object stays the same.IdGate() calls reset() for test isolation, then obtains handle A and handle B with two separate getInstance() calls.boolean sameInstance() returns whether the two handles refer to the same IdGenerator object.String nextA() and String nextB() request the next identifier through handle A and handle B.int issuedCount() on the gate reads through handle B.All judge cases run in one process. reset() restarts the sequence between cases, but it must never clear or replace the stored singleton reference.
Thread-safety requirement: The singleton must be thread-safe: both instance publication and the advance of the counter must remain correct under concurrent calls, so no two callers ever receive the same identifier.
TypeScript operations are synchronous within one JavaScript realm; separate workers have separate singleton scopes.
Input:
Output:
Explanation: Handle A and handle B were obtained independently but refer to the same object. An identifier issued through A advances the sequence that B continues.
Input:
Output:
Explanation: Three identifiers are issued through two independently obtained handles and form one gap-free sequence. The count read through B matches.
100 calls in total are made across all methods.ID-<n> with no padding, starting at ID-1 after every reset.reset() must restart the counter without replacing the singleton object.Turn IdGenerator into a thread-safe singleton and complete its TODOs. IdGate is complete driver code and must not be modified.
Full marks when `IdGenerator` owns one safely published instance for the lifetime of the process and construction is controlled. Lose points heavily when construction remains public, the accessor can return different objects, or initialization uses an unsafe check-then-create sequence.
Full marks when `nextId`, `issuedCount`, and `reset` protect the same counter so the read, increment, and format steps cannot interleave and both driver handles draw from one sequence. Lose points for unsynchronized mutation or a counter stored outside `IdGenerator`.
Full marks when identifiers are `ID-1`, `ID-2`, and so on with no gaps or repeats, `issuedCount` matches the number issued, and `reset` restarts the sequence without recreating the singleton. Lose points for zero-based numbering, skipped numbers, or 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 IdGate() | null |
| sameInstance() | true |
| nextA() | "ID-1" |
| nextB() | "ID-2" |
Handle A and handle B were obtained independently but refer to the same object. An identifier issued through A advances the sequence that B continues.
Run checks these cases. Submit also runs a larger hidden set.

