Rewrite app.js, hash files on the client

app.js should be much cleaner now. Additionally, files are hashed on the
client before we upload them, and we ask the server if that hash exists
before starting the upload. That makes it so that we can often skip the
upload entirely if we've seen the file before.

This closes #88 and #85.