modified for generality