new version, no global variables, suitable for multithreading