This is the final code after a lot of changes and improvements