working but needs more tests and tidying up