working code, needs more tests