Fix FileOutput component so it can be parallelized.

Previously only the last component created would really be able to write
to the file. Now, each component will open the file with an exclusive
lock for each message, append its line, and release the file.
Add characterization tests for existing behavior regarding ZeroMQ socket
creation by RubyDSL.
Connect component inputs before outputs.

Aiming toward using ZeroMQ in-proc sockets for in-shard connections.
Unlike other ZeroMQ sockets, inproc sockets require 'bind' to be called
strictly before 'connect', so iterating and starting ports by component
is not going to work. We need to get all the input ports binding before
we get the output ports connecting.
Use inproc ZeroMQ sockets for in-shard comms.

This has the happy benefit that for connections within a shard, there's
no longer any communications between shards. That is, a message flowing
A->B->C (where a shard contains A, B, and C) will always remain on that
shard, not possibly move to another shard because there are IPCs between
components.

We don't need to namespace the inproc sockets with anything other than
connection UUID, because there will only be one copy of any connection
within any given shard, and each shard will gets own copy of the inproc
socket.
Bind one-to-many connections on the cardinality-1 side.

Fan-in (many-to-one) worked already, because the consumer (input port)
`bind`ed the socket and all the producers (output ports) `connect`ed.

Fan-out (one-to-many) would only route to one consumer, because all the
consumers tried to `bind` the same socket, and all of them got clobbered
and the last one to `bind` was the only one to receive messages. We need
to run the `bind`/`connect` pair the other way for fan-out.

Many-to-many will require a broker solution using zmq_proxy.
Many-to-many connections spawn a broker process.

IPC sockets can only be bound once, but connected many times. To get
many pushers to spread their messages to many listeners, we start a
separate broker process that uses ZeroMQ devices to make the connection
(it binds on both sides and all producers and consumers connect).

Modern ZeroMQ code uses 'zeromq_proxy' as the call for this, but at this
time ffi-rzmq still maps the old Device API.

NEEDS MORE COMMENTS AND LOGGING.