reorganize code; add some unit tests