Full implementation. Needs more tests/docs