docs: async def zmq_ipc_pipe_end(ctx, side, endpoint, *, serializer: Optional[Serializer]=None, initialize=True):
          """
          Returns a `ZmqPipeEnd` backed by an `ipc` connection; the endpoint must contain the scheme part.
          If both ends of the connection are created on the same thread/task, to avoid a deadlock,
          it's necessary to first create both ends, then initialize `'b'` then `'a'`, such as this:
  
              a = await zmq_ipc_pipe_end(ctx, 'a', endpoint, initialize=False)
              b = await zmq_ipc_pipe_end(ctx, 'b', endpoint)
              await a.initialize()
  
          In that case, prefer `zmq_ipc_pipe` for creating both ends.
  
          Side `'a'` will bind a `ROUTER` socket on the given endpoint;
          side `'b'` will connect a `DEALER` socket to the given endpoint.
          """
  
          if side == 'a':
              result = ZmqPipeEnd(ctx, zmq.ROUTER, endpoint, port=None, bind=True, serializer=serializer)
          elif side == 'b':
              result = ZmqPipeEnd(ctx, zmq.DEALER, endpoint, port=None, serializer=serializer)
          else:
              raise ValueError("side must be 'a' or 'b'")
  
          if initialize:
              await result.initialize()
          return result