final version + tests