Final submitted code. see inapols forked repo for changes