I'm really happy with how this decomposed nicely into a composition-based solution :).  This is really clean and well done!