Original version from 2013 autumn, with some fix and code refactoring