This all duplicates logic from `static/js/exercise.js`.  The design of the current interaction makes it quite a bit of code churn to make that into common code; it didn't seem worth that level of destabilization to make a common source, and I can see reasons to keep that localized to the client for the future (to allow client-side updates), so I duplicated the code.