full implementation. needs testing