text: var Emitter = require("eventemitter2")
  
  var utils = require("../../utils")
  
  // transportOptions
      // listeners - An empty object should be passed in
  module.exports = function(transportOptions) {
      return {
          // connectionOptions
              // port
              // createOnClose - If not false, will create an onClose handler
              // emitErrors - If this exists, throws these errors instead of connecting
              // setupSendRawMessage - A function that will be passed a sendMessage function
          connect: function(connectionOptions, rpepOptions) {
              var listenerInfo = transportOptions.listeners[connectionOptions.port]
  
              var clientConnInfo = createConnectionEmitter(connectionOptions.createOnClose, connectionOptions.setupSendRawMessage)
  
              if(connectionOptions.throwErrors === undefined) {
                  if(listenerInfo === undefined) {
                      throw new Error("Couldn't connect to port: "+connectionOptions.port)
                  }
  
                  var serverConnInfo = createConnectionEmitter(listenerInfo.createOnClose, listenerInfo.setupSendRawMessage)
                  tieConnections(serverConnInfo, clientConnInfo)
  
                  setTimeout(function() { // ensure asynchronicity
                      listenerInfo.listener.emit('connect', serverConnInfo, clientConnInfo)
                  })
              } else {
                  setTimeout(function() {
                      connectionOptions.throwErrors.forEach(function(e) {
                          clientConnInfo.emit('error', e)
                      })
  
                      clientConnInfo.triggerClose()
                  })
              }
  
              return ConnectionObject(clientConnInfo)
          },
  
          // listeningOptions
              // port - A fake port to listen on
              // createOnClose - If not false, will setup an onClose handler for the created server connection
              // throwError - If not undefined, will throw the error
          listen: function(listeningOptions, rpepOptions, requestHandler) {
              if(listeningOptions.throwError !== undefined) {
                  setTimeout(function() {
                      errorHandler(listeningOptions.throwError)
                  })
  
                  return {
                      close: function() {
  
                      },
                      onListening: function(cb) {
  
                      },
                      onClose: function(cb) {
  
                      },
                      onError: function(cb) {
                          errorHandler = cb
                      }
                  }
              }
  
  
              var listeningEmitterInfo = createListenEmitter()
              transportOptions.listeners[listeningOptions.port] = {
                  listener: listeningEmitterInfo,
                  createOnClose: listeningOptions.createOnClose
              }
  
              listeningEmitterInfo.options.onConnect(function(connectionOptions, clientConnEmitter) {
                  if(transportOptions.listeners[listeningOptions.port]) {
                      requestHandler({
                          // t is meant to be a deadunit a test object
                          accept: function(t) {
                              if(t) {
                                  t.ok(true)
                              }
  
                              clientConnEmitter.triggerOpen()
                              return ConnectionObject(connectionOptions)
                          }, reject: function(t) {
                              if(t) {
                                  t.ok(true)
                              }
  
                              clientConnEmitter.triggerClose()
                          },
                          rawMessage: connectionOptions
                      })
                  }
              })
              listeningEmitterInfo.options.onError(function(e) {
                  if(errorHandler) errorHandler(e)
              })
  
              var closeCalled = false
              var onCloseHandler, errorHandler
              return {
                  close: function() {
                      if(!closeCalled) {
                          delete transportOptions.listeners[listeningOptions.port]
                          if(onCloseHandler) onCloseHandler()
                      } //else connection already closed - ignore
                  },
                  onListening: function(cb) {
                      setTimeout(cb)
                  },
                  onClose: function(cb) {
                      onCloseHandler = cb
                  },
                  onError: function(cb) {
                      errorHandler = cb
                  }
              }
          }
      }
  }
  // connectionInfo.options
      // send
      // drop (Optional)
      // onReceive
      // onClose
      // onError
      // onTriggerClose - sets up a handler that will be triggered when an external closure wants to happen
      // onTriggerOpen
      // createOnClose
  var ConnectionObject = function(connectionInfo) {
      var isOpen  = true
      var messageHandler, errorHandlers = [], closeHandlers = [], openHandlers = []
  
      var result = {
          send: function(m) {
              if(!isOpen) throw new Error("Connection closed")
              setTimeout(function() { // ensure asynchronicity
                  connectionInfo.options.send(m)
              })
          },
          close: function() {
              if(isOpen && closeHandlers.length > 0) {
                  setTimeout(function() { // ensure asynchronicity
                      connectionInfo.emit('close')
                  })
                  callAllHandlers(closeHandlers)
                  isOpen = false
              }
          },
          onOpen: function(cb) {
              openHandlers.push(cb)
          },
          onMessage: function(cb) {
              messageHandler = cb
          },
          onError: function(cb) {
              errorHandlers.push(cb)
          },
          rawConnection: connectionInfo
      }
  
      if(connectionInfo.options.createOnClose) {
          result.onClose = function(cb) {
              closeHandlers.push(cb)
          }
      }
  
      if(connectionInfo.options.drop) {
          result.drop = function() {
              if(isOpen) callAllHandlers(closeHandlers)
          }
      }
  
      connectionInfo.options.onTriggerClose(function() {
          // isOpen = false
          callAllHandlers(closeHandlers)
      })
      connectionInfo.options.onTriggerOpen(function() {
          // isOpen = false
          callAllHandlers(openHandlers)
      })
      connectionInfo.options.onReceive(function(m) {
          if(messageHandler) messageHandler(m)
      })
      connectionInfo.options.onError(function(e) {
          callAllHandlers(errorHandlers, e)
      })
  
      return result
  }
  
  function callAllHandlers(handlers, param) {
      handlers.forEach(function(handler) {
          handler(param)
      })
  }
  
  
  
  // takes two connections and ties them together so sending from one will receive on the other
  // one and two are both emitters (from createConnectionEmitter)
  function tieConnections(one, two) {
      one.on('send', function(m) {
          two.emit('message', m)
      })
      if(two.options.createOnClose) {
          one.on('close', function() {
              two.triggerClose()
          })
      }
      two.on('send', function(m) {
          one.emit('message', m)
      })
      if(one.options.createOnClose) {
          two.on('close', function() {
              one.triggerClose()
          })
      }
  }
  
  function createConnectionEmitter(onClose, setupSendRawMessage) {
      var connectionEmitter = new Emitter, triggerCloseHandler, triggerOpenHandler
      var result = {
          emit: function() {
              connectionEmitter.emit.apply(connectionEmitter,arguments)
          },
          on: function() {
              connectionEmitter.on.apply(connectionEmitter,arguments)
          },
          triggerClose: function() {
              triggerCloseHandler()
          },
          triggerOpen: function() {
              triggerOpenHandler()
          },
          options: {
              send: function(m) {
                  connectionEmitter.emit('send', m)
              },
              onReceive: function(cb){connectionEmitter.on('message',cb)},
              onError: function(cb){connectionEmitter.on('error',cb)},
              onTriggerClose: function(cb) {triggerCloseHandler=cb},
              onTriggerOpen: function(cb) {triggerOpenHandler=cb},
              createOnClose: onClose !== false,
              setupSendRawMessage: setupSendRawMessage
          }
      }
  
      return result
  }
  
  function createListenEmitter() {
      var listenEmitter = new Emitter
      return {
          emit: function() {
              listenEmitter.emit.apply(listenEmitter,arguments)
          },
          on: function() {
              listenEmitter.on.apply(listenEmitter,arguments)
          },
          options: {
              onError: function(cb){listenEmitter.on('error',cb)},    // onError - Sets up a handler that's called when the caller wants to trigger a listener error
              onConnect: function(cb){listenEmitter.on('connect',cb)} // onConnect - Sets up a handler that's called with the caller wants to trigger a connection.
          }
      }
  }