refactor and tested