also wrote a single-thread version, differences are minimal