refactored to be generic and functional