first pass at solving problem of duplicate problems

I went through a few iterations before settling on this solution:

Attempted solutions
===================

1. Have an RNG that does not repeat itself.

    I considered a linear feedback shift register, a linear congruential generator, and just a Fisher-Yates shuffle to generate a random permutation of all numbers in a range. I went with the latter because it's easy to understand and modify to generate any number of different random permutations of a range. However, after speaking with Ben Alpert, I decided to drop this for solution 2.

    cons: 
    - requires "flag day" where viewing old problems are invalidated because the RNG is different. 
    - Also, if we wish to have only 200 possible problems as we do now, we could only ensure that the first call to the RNG in a problem is a non-duplicate, which may require exercise developers to specify the first non-trivial call to the RNG (since the first call to an RNG may be just a problem. This is a leaky abstraction. :(
    - to make this work with data-ensure loops and randRangeNonZero, the code could get a little convoluted.

2. Pre-process (eg. during deploy-time) the exercises to find seeds that generate duplicate problems, and discard (all but 1 of) those seeds.

   I spent a day attempting to hack around jsdom's deficiencies (eg. no XHRs) and bugs, but doing all this required lots of changes to khan-exercise.js, may be brittle, and ultimately I decided to try out phantomjs before getting this to work.

   I then tried out phantomjs, which is headless webkit using QtWebkit. This took only 10 mins to get working with our exercises, but QtWebkit is very slow and after a day of optimizations removing unnecessary steps, it still took over half an hour to pre-process less than half the exercises. Due to other cons below, I dropped this solution as well.

   pros:
   - does not invalidate viewing of old problems done
   - allows exercise developers to more precisely define what a duplicate problem is for a an exercise (if they specify the VARS hashing function).

   cons:
   - pre-processing slows down deploy time by hours. This is because we need to run makeProblem 200 times on every problem type in each exercise, and QtWebkit is slow. We could cache these results, but every time there is a change to khan-exercise.js or any javascript file, would need to re-run the pre-processing to be safe. I also didn't think it'd be wise to spend more time doing optimizations.

3. At run-time, check if the current problem is similar to any of the last 5 problems done. If so, skip it.

   This is the final solution that was implemented in this commit. It uses localStorage for state persistence. It does not screw up problem numbers (they still only increase by 1 for each problem done) and refreshing the page would not change the problem.

   pros:
   - is not brittle
   - does not slow down deploy
   - does not invalidate older problems
   - is simple and not much code (eg. does not have to know about different problem types, but option 2 does) (compared to the options above)
   - allows exercise developers to more precisely define what a duplicate problem is for an exercise (if they specify the VARS hashing function).

   cons:
   - a tiny bit slower during run-time due to having to re-run half of makeProblem a few times if we need to skip
   - possibility of having a duplicate problem after 5 problems (the current window size), but this is a very minor con.

I need to go for dinner now. If I think of other things to add, I'll add it to the pull request message.

@beneater @kamens @spicyj (almost a full bengineer review)