Add autorestart logic to the kernel managers

Currently, when kernels die in the notebook, the user is prompted and asked if they want to restart the kernel.  This is problematic from a number of standpoints:

* If there is client, the kernel/notebook mapping gets messed up.
* A dead kernel should always be restarted.

In this PR, I have added a new KernelRestarter object that works alongside a KernelManager object to poll the kernel's subprocess and call KernelManager.restart_kernel if it dies.  I am also changing how the user is notified of this event.

Remaining:

- [ ] Finish logic in MultiKernelManager.
- [ ] Update MultiKernelManager tests.
- [ ] Add new kernel message when the kernel starts/restarts.
- [ ] Add new kernel death logic to the notebook UI.
- [ ] Test different combinations of frontends.
- [ ] Decide what to do about old heartbeat code.