refactor using events instead of callbacks