finished, need check and refactor