refactoring to make implementation more general