updated from fork, diff will be ugly