Completely revised to reduce boilerplate