The code is rather long, but relatively simple and well-commented for your understanding. I've thoroughly tested this for bugs and have found none