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.