rewritten from scratch using exceptions