finally done, needs more testing