VERY MUCH IMPROVED TERMIO MODULE IN THIS COMMIT...
SSH Plugin:  Added logic that will make sure that the public key isn't automatically (re)generated if it is uploaded within two seconds of the private key.  This would happen because the JS that submits the private and public keys to the server is handled via two separate WebSocket actions (even though they're called at the same time).  I did it this way--instead of just changing the JS logic--to ensure that the back-end can handle such situations if there's ever a 3rd party plugin that calls the WebSocket actions in question (never trust the client).
SSH Plugin:  Generating the public key using the private key is now handled asynchronously (so it won't block on a slow or bogged-down system).
SSH Plugin:  The user will now be asked for the passphrase of the private key if they do not provide a public key when submitting identity upload form.  This is so the public key can be generated from the private and sure beats a silent failure.
SSH Plugin:  Private keys will now be validated before they're saved.  If a key does not pass (basic) validation an error will be presented to the user and nothing will be saved.
SSH Plugin:  Reduced the width of the metadata panel in the SSH identity manager a bit so it would fit better on smaller screens.
ssh_connect.py:  Fixed a bug where it would use all identities if none were marked to be used by default.
gateone.py:  Added a new function to TerminalWebSocket:  term_ended().  It just sends the "term_ended" message to the client letting it know that a given terminal has been closed.
gateone.py:  Changed the logic inside of TerminalWebSocket.new_terminal() so that it uses term_ended() instead of just calling new_terminal() when a the CALLBACK_EXIT callback is called.  This should be a lot less confusing in the logs when it says %USER% new_terminal() ever time a terminal closes.
termio.py:  Instead of using "signal.signal(signal.SIGCHLD, signal.SIG_IGN)" to automatically clean up ended processes (i.e. to prevent defunct) MultplexPOSIXIOLoop now calls "os.waitpid(self.pid. os.WNOHANG)" whenever isalive() is called.  This allows the Multiplex instance to have an exitstatus variable that can be reviewed after-the-fact to determine if a program executed successfully.
termio.py:  Added the aforementioned Multiplex.exitstatus variable.  By default it is set to None and will get assigned an integer once the underlying program has ended.
termio.py:  Multiplex.spawn() now takes an additional argument:  exitfunc.  This can be a function that will be called when the program exits.  The function will be called with the exit status code as the only argument.
termio.py:  Added a new global function:  getstatusoutput().  It emulates commands.getstatusoutput() but provides the option to provide specific parameters to the Multiplex.spawn() function.
termio.py:  Simplified the logic inside of MultiplexPOSIXIOLoop.isalive() so that it returns faster/uses less CPU.  It should also now be portable across all Unix OSes.
termio.py:  You can now pass a string as the 'callback' argument to Multiplex.expect() and it will automatically be converted into a function that writes said string to the child process.
termio.py:  Loads of little tweaks here and there to make the logic more robust.
termio.py:  The MultiplexMacOSIOLoop class has been removed since the isalive() function has been modified to be more portable across (Unix) platforms.
termio.py:  The creation of Multiplex.term (using the provided terminal emulator) now works if the given terminal emulator class doesn't support em_dimensions as a keyword argument.
termio.py:  The use of timeout_func() has been replaced with simpler logic that detects when the time is right to engage the rate limiter.  Also, this new rate limiter logic is MUCH more responsive than before.  When running a command like, "yes" the time between pressing ctrl-c and when it stops outputting data to the screen should now be under 3 seconds (usually shorter).
termio.py:  Fixed a bug where optional expect() patterns weren't being processed properly.
termio.py:  Fixed a bug where multi-regex patterns weren't working with preprocess().
termio.py:  Removed the use of threading.Lock() since it wasn't really doing anything (there's no precise concurrency problems with IOLoop).
utils.py:  Moved get_or_update_metadata() (and related functions) into termio.py and logging_plugin.py directly.  This is to remove utils.py as a dependency of termio.py.
Rebuilt the docs.
Themes:  Trivial tweaks here and there to make things look better.