docs: function ReconnectingWebSocket (url, options) {
    var me = this;
  
    this.id = options && options.id || randomUUID();
    this.url = url + '/?id=' + this.id;
  
    this.socket = null;
    this.opened = false;
    this.closed = false;
  
    this.options = {
      reconnectTimeout: Infinity, // ms
      reconnectInterval: 5000     // ms
      //reconnectDecay: 2 // TODO: reconnect decay
    };
  
    // copy the options
    if (options) {
      if ('reconnectTimeout' in options)  this.options.reconnectTimeout = options.reconnectTimeout;
      if ('reconnectInterval' in options) this.options.reconnectInterval = options.reconnectInterval;
    }
  
    this.queue = [];
  
    this.attempts = 0;
    this.reconnectTimer = null;
  
    function connect() {
      me.socket = new WebSocket(me.url);
  
      me.socket.onmessage = function (event) {
        me.onmessage(event);
      };
  
      me.socket.onerror = function (error) {
        if (me.socket.readyState === WebSocket.OPEN) {
          me.onerror(error);
        }
        else {
          reconnect();
        }
      };
  
      me.socket.onopen = function (event) {
        // reset the number of connection attempts
        me.attempts = 0;
  
        // emit events
        if (!me.opened) {
          me.onopen(event);
          me.opened = true;
        }
        else {
          me.onreconnect(event);
        }
  
        // flush all messages in the queue (if any)
        //console.log('flush messages ' + me.queue);
        while (me.queue.length > 0) {
          var data = me.queue.shift();
          me.socket.send(data);
        }
      };
  
      me.socket.onclose = function (event) {
        if (me.closed) {
          me.onclose(event);
        }
        else {
          // start auto-reconnect attempts
          reconnect();
        }
      }
    }
  
    function reconnect() {
      // check whether already reconnecting
      if (me.reconnectTimer) {
        return;
      }
  
      me.attempts++;
      if (me.attempts < me.options.reconnectTimeout / me.options.reconnectInterval) {
        me.reconnectTimer = setTimeout(function () {
          me.reconnectTimer = null;
          connect();
        }, me.options.reconnectInterval);
      }
      else {
        // no luck, let's give up...
        me.close();
      }
    }
  
    connect();
  }