rewritten for better functionality and ES6 generators