const defaultNexusServer = 'ws://localhost:3000';

function timebox(desc, func, ms=1000) {
  const error = new Error('timeout while `' + desc + '`');
  return new Promise((resolve, reject) => {
    const timeout = setTimeout(() => { throw  error}, ms);
    return func(val => {
      clearTimeout(timeout);
      return resolve(val);
    }, err => {
      clearTimeout(timeout);
      return reject(err);
    })
  });
}

class HostWrapper {
  constructor(opts={}) {
    const { disableDefaultCallbacks = true } = opts;

    this.host = new nexusHost(
      opts.nexusServer || defaultNexusServer,
      opts.hostName || 'defaultHostName',
      disableDefaultCallbacks,
    );
  }

  get id(){
    return this.host.id;
  }

  get name() {
    return this.host.name;
  }

  onRegistered() {
    return timebox(
      `waiting for host '${this.host.name}' to register`,
      resolve => this.host.onRegistered = resolve,
    );
  }

  close() {
    return timebox(
      `waiting to close host '${this.host.name}'`,
      resolve => {
        this.host.onClose = resolve
        this.host.close();
      },
    )
  }
}

class ClientWrapper {
  constructor(opts={}) {
    this.client = new nexusClient(
      opts.nexusServer || defaultNexusServer,
      opts.autoConnectOptions || null,
    );
  }

  onServerConnect() {
    return timebox(
      `waiting for client to connect to server`,
      resolve => this.client.onServerConnect = resolve,
    );
  }

  getHostList() {
    return new Promise(resolve => this.client.getHostList(resolve));
  }

  close() {
    return timebox(
      `waiting to close client`,
      resolve => {
        this.client.onClose = resolve;
        this.client.close();
      },
    )
  }
}

class NexusSpecHelpers {
  // ===================== Spec Helpers ===================== //

  findHost(hostList, id) {
    // hostList := [ host, host, ...]
    // host := { hostID: integer, hostName: string}
    return hostList.find(host => host.hostID == id);
  }

  newHost(opts) {
    return this.host = new HostWrapper(opts);
  }

  newClient(opts) {
    return this.client = new ClientWrapper(opts);
  }
}

class EnsureConnection {
  constructor() {
    this.ws = new WebSocket(ServerAddr);
    this.closed = false;
    this._shouldClose = false;

    this.ws.onclose = () => {
      if(!this._shouldClose) {
        console.warn("No Connection to Nexus Server!");
      }
      this.closed = true;
    }
  }

  close() {
    this._shouldClose = true;
    this.ws.close();
  }
}

@@ -44,16 +44,191 @@
 3000';%0A%0A
+const getUniqueId = (function() %7B%0A  let id = 0;%0A  return function() %7B%0A    // provides a unique id even if called twice in a row%0A    return %60$%7BDate.now()%7D.$%7Bid++%7D%60;%0A  %7D%0A%7D)();%0A%0A
 function
@@ -644,17 +644,34 @@
   const 
-%7B
+defaults = %7B%0A     
  disable
@@ -690,25 +690,135 @@
 acks
- = true %7D = 
+: true,%0A      hostName: getUniqueId(),%0A      nexusServer: defaultNexusServer,%0A    %7D%0A    const options = %7B ...defaults, ...
 opts
-;
+%7D
 %0A%0A  
@@ -847,32 +847,35 @@
 sHost(%0A      opt
+ion
 s.nexusServer %7C%7C
@@ -871,38 +871,16 @@
 usServer
- %7C%7C defaultNexusServer
 ,%0A      
@@ -882,16 +882,19 @@
      opt
+ion
 s.hostNa
@@ -899,37 +899,16 @@
 Name
- %7C%7C 'defaultHostName'
 ,%0A      
 disa
@@ -899,24 +899,32 @@
 Name,%0A      
+options.
 disableDefau

Make each default hostName unique