Update the docs database.
Refactor our per-file diff rendering code into a DiffRenderer class.

DiffRenderer is responsible for taking the output of get_diff_files, and
some configuration (highlighting, collapse state, etc.) and rendering
diff output. It separates out the various responsibilities of the old
function, such as computing the cache key and rendering to strings and
HttpResponses.

There's one DiffRenderer per thing to render. It's created, used, and
thrown away.

A DiffRenderer is accessed by get_diff_renderer or
get_diff_renderer_class, rather than relying on using DiffRenderer
directly, allowing for some extensibility.

The new tests rely on kgb for function spies.
Switch to using the cached template loader.

The cached template loader will cache the path to a template, given a
template name. Unlike the standard loaders, which will search every
location every time, this will only search the location once per thread.

This is not a memcached-based solution, but rather local memory, so
every thread will start with a fresh cache.

In my tests, this sped up the dashboard and review request pages by
~100-120ms, after the first load.
Move opcodes_with_metadata into a DiffOpcodeGenerator class.

This new class performs all the same functions as the original
functions. Some of the code has been moved out into helper functions
for organization issues, but the logic hasn't changed.

This is part of an effort to clean up the diff viewer code and make it
more extensible.
Create a base Differ class and move some centralized stuff into it.

The two differs now inherit from Differ. This centralizes the
"interesting line" registration, and even the interesting line header
registration.

The filetype header maps have been moved into filetypes.py.

A tiny optimization was made, which was to check the diff compat version
1 (Myers differ) first, and not second. It won't make a huge difference,
but it's silly we didn't do that before.
Move chunk generation out of diffutils and into DiffChunkGenerator.

This class handles all the responsibilities of diff chunk generation.
It's basically the same code as before, but some things were able to be
cleaned up. For example, all the nested functions are gone, and instead
are just methods of the class. Functions can access self.<whatever>
instead of variables that happen to be in scope or variables. The yields
don't have to pass chunk_index and then increment it themselves.

This drastically shortens what's in diffutils.py. It also reduces how
much populate_diff_chunks now has to do.
Increase the size of the review request actions.

The review request actions were hard to hit on smaller screens. In
general, given how important they are, they're just too small. This
increases the size and makes the more prominent and easier to hit.
Fix the upload dialogs on the review UI pages.

The upload dialogs didn't contain the Django forms needed to populate
the on-screen forms, due to not using make_review_request_context. This
function (which hopefully we can kill in the future) has been moved into
reviewboard.reviews.context (to prevent a circular dependency) and is
now used in the review UI rendering code.
Prevent the page from jumping when modifying an issue state.

The introduction of the issue summary table had an annoying problem
where the page would scroll slightly after clicking Fixed, Drop, or
Reopen. The reason is that the matching entry in the table would be
added/removed, and that would affect the scroll offset.

We now work around that by updating the scroll offset after modifying
the table to scroll by the appropriate difference. Users won't see it
jump anymore.
Dynamically reload the dashboard contents without a page refresh.

The dashboard contents are now dynamically loaded every 5 minutes.
We fetch the entire page and just extract the dashboard content
(including sidebar) and replace the current content with it.

We replace the Edit Columns pencil icon with a spinner during reload.

One of the nice advantages to this is that if the server goes down at
all while the client is trying to reload, the worst that happens is they
get an HTTP 404/500/whatever error in the console log/network inspector.
The fetch will be tried again at the next 5 minute mark.

The sidebar count calculations have been moved into the view. It's been
made a bit smarter there. We don't attempt to calculate if we're only
fetching the datagrid (due to reload, reordering of columns, etc.),
cutting down on queries.