Link tasks by uuid, datetime and reverse-datetime

This allows a task be be looked up based on:

 * The corresponding worker's uuid (indirectly)
 * The task's uuid
 * The `datetime` when the first message for the specified task was
   received.

In addition, given a task uuid, the `datetime` of the task's first
received message can be obtained.
[WIP] Add skeleton of worker state structures
[WIP] Add worker state on `begin_task`
[NB] Add worker heart-beat mechanism

Add worker heart-beat mechanism, such that:

 * heart-beat is started once task sub-process has been started
 * the worker emits a heart-beat once every 4 seconds (easily changed)
 * if the broker does not receive a heart-beat or other request from a
   worker for 5 consecutive checks, the broker marks the worker as
   flat-lined and notifies the master
 * after flat-lining, if a heart-beat is restored, the worker is
   reset to `running` from `flatlined`, and the master is notified that
   the worker has been revived
Rearrange order of Broker methods
Add create_worker RPC method to Broker

Refactor most `Broker` code into `BrokerBase` class.

Add `create_worker` remote procedure call (RPC) method to `BrokerBase`.

Sub-class `BrokerBase`, creating `Broker` class, and override the
`BrokerBase` `create_worker` and `terminate_worker` methods.
Save worker-based task data under 'hidden' keys

TL;DR Worker book-keeping data gets stored under keys with prefix and
postfix of `__`.  The task that is managed by a worker should only store
data using keys that do not begin and end with `__`.

Save worker-based task data under 'hidden' keys (e.g., '__worker_info__',
'__begin_task__', etc.).  The intention is that these fields are
reserved for non-task-specific data, leaving any keys that do not start
and end with `__` open as keys for storing task-specific data by the
task itself.
Set env variables for task subprocess, save env

Set the following environment variables for task subprocess:

    ZMQ_JOB_MANAGER__BROKER_URI
    ZMQ_JOB_MANAGER__WORKER_UUID
    ZMQ_JOB_MANAGER__TASK_UUID

Save per-task environment variables and task object using `store` RPC API.
[NB] Fix heart-beat handling...

Prior to this commit, there were several issues related to heart-beat handling,
such as workers not being marked as running.

Change all `workers` indexes to sets of worker uuids (e.g., `running`,
`flatlined`, etc.).  Add `flatlined_latch` set, where flat-lined worker uuids
are added, but are removed immediately after processing the flat-line.  This
allows the `flatlined` set to maintain a list of all flat-lined workers that
have been witnessed.
Add missing `test_task.py`, add `requirements.txt`

Using `requirements.txt`, package dependencies can be installed by:

    pip install -r requirements.txt

Rename all occurrences of `master` in `worker.py` with `manager`.
Modify worker to use spawn for async task request
Modify worker to loop forever, processing tasks

Modify worker to loop forever, processing tasks as they become available.  This
is accomplished by using the RPC proxy spawn method, which uses eventlet green
threads to asynchronously request a task.
Add worker request queue methods to broker/worker

Add worker request queue methods to broker and worker.  Specifically, the
following RPC methods were added to the broker:

    queue_worker_request(command, *args, **kwargs)
    request_queue()

The `queue_worker_request` method appends the specified command configuration
to the worker's list of pending requests.  The `request_queue` can then be
called from the worker to retrieve (and flush) the list of pending requests.

In the worker class, add request handling through the `timer__queue_monitor`
periodic callback handler.  This means that at regular intervals, the worker
will retrieve and process any outstanding requests in its queue.  Currently,
the only worker command exposed is `terminate`, which accepts no args or kwargs
and stops the worker IO-loop, causing the worker process to finish and
terminate.
Deserialize JSON-encoded values passed to `store`
[NB] Add sigterm signal-handling to worker

Add sigterm signal-handling to worker, to gracefully terminate worker.  If the worker
is currently executing a task thread, store the current seconds-since-epoch
value (JSON-encoded) to the key `__sigterm_caught__`.  This provides a means to
determine if a `sigterm` was received during a task.
[NB] Rename broker to supervisor
[NB] Rename master to manager

The names of the processes in a ZeroMQ job manager system are now:

 * *Manager*
  * Accepts registration of tasks to be executed
  * Publishes worker status updates to any listening processes (for now, the
    listening process would likely be a *workers sink*)
 * *Supervisor*
  * Supervises a set of workers
  * Handles worker-related requests, such as, `queue_worker_request`,
    `request_queue`.
  * Forward requests that are not the responsibility of the supervisor on to
    the manager to be processed, also forwarding the response back to the
    worker
 * *Worker*
  * Repeatedly requests and executes tasks from the manager (through the
    supervisor)
  * For each task, the `stdout` and `stderr` are automatically forwarded on to
    the manager while the task is running (i.e., the output is streamed, not
    just sent after task completion).
  * Several key/value pairs are sent to the master for storage, including:
   * '__task__'
   * '__env__'
   * '__begin_task__'
   * '__worker_info__'
   * '__complete_task__'
 * *Worker sink*
  * Subscribes to one or more managers, listening for messages for commands,
    such as `store`, `stderr` and `stdout`.
  * Writes `store` key/value pairs in a ZODB database tree, based on worker
    UUID and task UUID.
  * Writes `stdout` and `stderr` to files in the path:
   * `~/.workers_sink/task_data/<worker_uuid>/<task_uuid>`
Add missing file