added more abstraction, worse, but capable