copied and modified from Aleksey V. Zapparov