Ported to python3, tests pass