heavily modified and updated