Index: trip-planner-front/node_modules/engine.io/lib/engine.io.js
===================================================================
--- trip-planner-front/node_modules/engine.io/lib/engine.io.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/engine.io/lib/engine.io.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
@@ -0,0 +1,127 @@
+/**
+ * Module dependencies.
+ */
+
+const http = require("http");
+const Server = require("./server");
+
+/**
+ * Invoking the library as a function delegates to attach if the first argument
+ * is an `http.Server`.
+ *
+ * If there are no arguments or the first argument is an options object, then
+ * a new Server instance is returned.
+ *
+ * @param {http.Server} server (if specified, will be attached to by the new Server instance)
+ * @param {Object} options
+ * @return {Server} engine server
+ * @api public
+ */
+
+exports = module.exports = function() {
+  // backwards compatible use as `.attach`
+  // if first argument is an http server
+  if (arguments.length && arguments[0] instanceof http.Server) {
+    return attach.apply(this, arguments);
+  }
+
+  // if first argument is not an http server, then just make a regular eio server
+  return new Server(...arguments);
+};
+
+/**
+ * Protocol revision number.
+ *
+ * @api public
+ */
+
+exports.protocol = 1;
+
+/**
+ * Expose Server constructor.
+ *
+ * @api public
+ */
+
+exports.Server = Server;
+
+/**
+ * Expose Socket constructor.
+ *
+ * @api public
+ */
+
+exports.Socket = require("./socket");
+
+/**
+ * Expose Transport constructor.
+ *
+ * @api public
+ */
+
+exports.Transport = require("./transport");
+
+/**
+ * Expose mutable list of available transports.
+ *
+ * @api public
+ */
+
+exports.transports = require("./transports");
+
+/**
+ * Exports parser.
+ *
+ * @api public
+ */
+
+exports.parser = require("engine.io-parser");
+
+/**
+ * Creates an http.Server exclusively used for WS upgrades.
+ *
+ * @param {Number} port
+ * @param {Function} callback
+ * @param {Object} options
+ * @return {Server} websocket.io server
+ * @api public
+ */
+
+exports.listen = listen;
+
+function listen(port, options, fn) {
+  if ("function" === typeof options) {
+    fn = options;
+    options = {};
+  }
+
+  const server = http.createServer(function(req, res) {
+    res.writeHead(501);
+    res.end("Not Implemented");
+  });
+
+  // create engine server
+  const engine = exports.attach(server, options);
+  engine.httpServer = server;
+
+  server.listen(port, fn);
+
+  return engine;
+}
+
+/**
+ * Captures upgrade requests for a http.Server.
+ *
+ * @param {http.Server} server
+ * @param {Object} options
+ * @return {Server} engine server
+ * @api public
+ */
+
+exports.attach = attach;
+
+function attach(server, options) {
+  const engine = new Server(options);
+  engine.attach(server, options);
+  return engine;
+}
Index: trip-planner-front/node_modules/engine.io/lib/parser-v3/index.js
===================================================================
--- trip-planner-front/node_modules/engine.io/lib/parser-v3/index.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/engine.io/lib/parser-v3/index.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
@@ -0,0 +1,483 @@
+// imported from https://github.com/socketio/engine.io-parser/tree/2.2.x
+
+/**
+ * Module dependencies.
+ */
+
+var utf8 = require('./utf8');
+
+/**
+ * Current protocol version.
+ */
+exports.protocol = 3;
+
+const hasBinary = (packets) => {
+  for (const packet of packets) {
+    if (packet.data instanceof ArrayBuffer || ArrayBuffer.isView(packet.data)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ * Packet types.
+ */
+
+var packets = exports.packets = {
+    open:     0    // non-ws
+  , close:    1    // non-ws
+  , ping:     2
+  , pong:     3
+  , message:  4
+  , upgrade:  5
+  , noop:     6
+};
+
+var packetslist = Object.keys(packets);
+
+/**
+ * Premade error packet.
+ */
+
+var err = { type: 'error', data: 'parser error' };
+
+const EMPTY_BUFFER = Buffer.concat([]);
+
+/**
+ * Encodes a packet.
+ *
+ *     <packet type id> [ <data> ]
+ *
+ * Example:
+ *
+ *     5hello world
+ *     3
+ *     4
+ *
+ * Binary is encoded in an identical principle
+ *
+ * @api private
+ */
+
+exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) {
+  if (typeof supportsBinary === 'function') {
+    callback = supportsBinary;
+    supportsBinary = null;
+  }
+
+  if (typeof utf8encode === 'function') {
+    callback = utf8encode;
+    utf8encode = null;
+  }
+
+  if (Buffer.isBuffer(packet.data)) {
+    return encodeBuffer(packet, supportsBinary, callback);
+  } else if (packet.data && (packet.data.buffer || packet.data) instanceof ArrayBuffer) {
+    return encodeBuffer({ type: packet.type, data: arrayBufferToBuffer(packet.data) }, supportsBinary, callback);
+  }
+
+  // Sending data as a utf-8 string
+  var encoded = packets[packet.type];
+
+  // data fragment is optional
+  if (undefined !== packet.data) {
+    encoded += utf8encode ? utf8.encode(String(packet.data), { strict: false }) : String(packet.data);
+  }
+
+  return callback('' + encoded);
+};
+
+/**
+ * Encode Buffer data
+ */
+
+function encodeBuffer(packet, supportsBinary, callback) {
+  if (!supportsBinary) {
+    return exports.encodeBase64Packet(packet, callback);
+  }
+
+  var data = packet.data;
+  var typeBuffer = Buffer.allocUnsafe(1);
+  typeBuffer[0] = packets[packet.type];
+  return callback(Buffer.concat([typeBuffer, data]));
+}
+
+/**
+ * Encodes a packet with binary data in a base64 string
+ *
+ * @param {Object} packet, has `type` and `data`
+ * @return {String} base64 encoded message
+ */
+
+exports.encodeBase64Packet = function(packet, callback){
+  var data = Buffer.isBuffer(packet.data) ? packet.data : arrayBufferToBuffer(packet.data);
+  var message = 'b' + packets[packet.type];
+  message += data.toString('base64');
+  return callback(message);
+};
+
+/**
+ * Decodes a packet. Data also available as an ArrayBuffer if requested.
+ *
+ * @return {Object} with `type` and `data` (if any)
+ * @api private
+ */
+
+exports.decodePacket = function (data, binaryType, utf8decode) {
+  if (data === undefined) {
+    return err;
+  }
+
+  var type;
+
+  // String data
+  if (typeof data === 'string') {
+
+    type = data.charAt(0);
+
+    if (type === 'b') {
+      return exports.decodeBase64Packet(data.substr(1), binaryType);
+    }
+
+    if (utf8decode) {
+      data = tryDecode(data);
+      if (data === false) {
+        return err;
+      }
+    }
+
+    if (Number(type) != type || !packetslist[type]) {
+      return err;
+    }
+
+    if (data.length > 1) {
+      return { type: packetslist[type], data: data.substring(1) };
+    } else {
+      return { type: packetslist[type] };
+    }
+  }
+
+  // Binary data
+  if (binaryType === 'arraybuffer') {
+    // wrap Buffer/ArrayBuffer data into an Uint8Array
+    var intArray = new Uint8Array(data);
+    type = intArray[0];
+    return { type: packetslist[type], data: intArray.buffer.slice(1) };
+  }
+
+  if (data instanceof ArrayBuffer) {
+    data = arrayBufferToBuffer(data);
+  }
+  type = data[0];
+  return { type: packetslist[type], data: data.slice(1) };
+};
+
+function tryDecode(data) {
+  try {
+    data = utf8.decode(data, { strict: false });
+  } catch (e) {
+    return false;
+  }
+  return data;
+}
+
+/**
+ * Decodes a packet encoded in a base64 string.
+ *
+ * @param {String} base64 encoded message
+ * @return {Object} with `type` and `data` (if any)
+ */
+
+exports.decodeBase64Packet = function(msg, binaryType) {
+  var type = packetslist[msg.charAt(0)];
+  var data = Buffer.from(msg.substr(1), 'base64');
+  if (binaryType === 'arraybuffer') {
+    var abv = new Uint8Array(data.length);
+    for (var i = 0; i < abv.length; i++){
+      abv[i] = data[i];
+    }
+    data = abv.buffer;
+  }
+  return { type: type, data: data };
+};
+
+/**
+ * Encodes multiple messages (payload).
+ *
+ *     <length>:data
+ *
+ * Example:
+ *
+ *     11:hello world2:hi
+ *
+ * If any contents are binary, they will be encoded as base64 strings. Base64
+ * encoded strings are marked with a b before the length specifier
+ *
+ * @param {Array} packets
+ * @api private
+ */
+
+exports.encodePayload = function (packets, supportsBinary, callback) {
+  if (typeof supportsBinary === 'function') {
+    callback = supportsBinary;
+    supportsBinary = null;
+  }
+
+  if (supportsBinary && hasBinary(packets)) {
+    return exports.encodePayloadAsBinary(packets, callback);
+  }
+
+  if (!packets.length) {
+    return callback('0:');
+  }
+
+  function encodeOne(packet, doneCallback) {
+    exports.encodePacket(packet, supportsBinary, false, function(message) {
+      doneCallback(null, setLengthHeader(message));
+    });
+  }
+
+  map(packets, encodeOne, function(err, results) {
+    return callback(results.join(''));
+  });
+};
+
+function setLengthHeader(message) {
+  return message.length + ':' + message;
+}
+
+/**
+ * Async array map using after
+ */
+
+function map(ary, each, done) {
+  const results = new Array(ary.length);
+  let count = 0;
+
+  for (let i = 0; i < ary.length; i++) {
+    each(ary[i], (error, msg) => {
+      results[i] = msg;
+      if (++count === ary.length) {
+        done(null, results);
+      }
+    });
+  }
+}
+
+/*
+ * Decodes data when a payload is maybe expected. Possible binary contents are
+ * decoded from their base64 representation
+ *
+ * @param {String} data, callback method
+ * @api public
+ */
+
+exports.decodePayload = function (data, binaryType, callback) {
+  if (typeof data !== 'string') {
+    return exports.decodePayloadAsBinary(data, binaryType, callback);
+  }
+
+  if (typeof binaryType === 'function') {
+    callback = binaryType;
+    binaryType = null;
+  }
+
+  if (data === '') {
+    // parser error - ignoring payload
+    return callback(err, 0, 1);
+  }
+
+  var length = '', n, msg, packet;
+
+  for (var i = 0, l = data.length; i < l; i++) {
+    var chr = data.charAt(i);
+
+    if (chr !== ':') {
+      length += chr;
+      continue;
+    }
+
+    if (length === '' || (length != (n = Number(length)))) {
+      // parser error - ignoring payload
+      return callback(err, 0, 1);
+    }
+
+    msg = data.substr(i + 1, n);
+
+    if (length != msg.length) {
+      // parser error - ignoring payload
+      return callback(err, 0, 1);
+    }
+
+    if (msg.length) {
+      packet = exports.decodePacket(msg, binaryType, false);
+
+      if (err.type === packet.type && err.data === packet.data) {
+        // parser error in individual packet - ignoring payload
+        return callback(err, 0, 1);
+      }
+
+      var more = callback(packet, i + n, l);
+      if (false === more) return;
+    }
+
+    // advance cursor
+    i += n;
+    length = '';
+  }
+
+  if (length !== '') {
+    // parser error - ignoring payload
+    return callback(err, 0, 1);
+  }
+
+};
+
+/**
+ *
+ * Converts a buffer to a utf8.js encoded string
+ *
+ * @api private
+ */
+
+function bufferToString(buffer) {
+  var str = '';
+  for (var i = 0, l = buffer.length; i < l; i++) {
+    str += String.fromCharCode(buffer[i]);
+  }
+  return str;
+}
+
+/**
+ *
+ * Converts a utf8.js encoded string to a buffer
+ *
+ * @api private
+ */
+
+function stringToBuffer(string) {
+  var buf = Buffer.allocUnsafe(string.length);
+  for (var i = 0, l = string.length; i < l; i++) {
+    buf.writeUInt8(string.charCodeAt(i), i);
+  }
+  return buf;
+}
+
+/**
+ *
+ * Converts an ArrayBuffer to a Buffer
+ *
+ * @api private
+ */
+
+function arrayBufferToBuffer(data) {
+  // data is either an ArrayBuffer or ArrayBufferView.
+  var length = data.byteLength || data.length;
+  var offset = data.byteOffset || 0;
+
+  return Buffer.from(data.buffer || data, offset, length);
+}
+
+/**
+ * Encodes multiple messages (payload) as binary.
+ *
+ * <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number
+ * 255><data>
+ *
+ * Example:
+ * 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
+ *
+ * @param {Array} packets
+ * @return {Buffer} encoded payload
+ * @api private
+ */
+
+exports.encodePayloadAsBinary = function (packets, callback) {
+  if (!packets.length) {
+    return callback(EMPTY_BUFFER);
+  }
+
+  map(packets, encodeOneBinaryPacket, function(err, results) {
+    return callback(Buffer.concat(results));
+  });
+};
+
+function encodeOneBinaryPacket(p, doneCallback) {
+
+  function onBinaryPacketEncode(packet) {
+
+    var encodingLength = '' + packet.length;
+    var sizeBuffer;
+
+    if (typeof packet === 'string') {
+      sizeBuffer = Buffer.allocUnsafe(encodingLength.length + 2);
+      sizeBuffer[0] = 0; // is a string (not true binary = 0)
+      for (var i = 0; i < encodingLength.length; i++) {
+        sizeBuffer[i + 1] = parseInt(encodingLength[i], 10);
+      }
+      sizeBuffer[sizeBuffer.length - 1] = 255;
+      return doneCallback(null, Buffer.concat([sizeBuffer, stringToBuffer(packet)]));
+    }
+
+    sizeBuffer = Buffer.allocUnsafe(encodingLength.length + 2);
+    sizeBuffer[0] = 1; // is binary (true binary = 1)
+    for (var i = 0; i < encodingLength.length; i++) {
+      sizeBuffer[i + 1] = parseInt(encodingLength[i], 10);
+    }
+    sizeBuffer[sizeBuffer.length - 1] = 255;
+
+    doneCallback(null, Buffer.concat([sizeBuffer, packet]));
+  }
+
+  exports.encodePacket(p, true, true, onBinaryPacketEncode);
+
+}
+
+
+/*
+ * Decodes data when a payload is maybe expected. Strings are decoded by
+ * interpreting each byte as a key code for entries marked to start with 0. See
+ * description of encodePayloadAsBinary
+
+ * @param {Buffer} data, callback method
+ * @api public
+ */
+
+exports.decodePayloadAsBinary = function (data, binaryType, callback) {
+  if (typeof binaryType === 'function') {
+    callback = binaryType;
+    binaryType = null;
+  }
+
+  var bufferTail = data;
+  var buffers = [];
+  var i;
+
+  while (bufferTail.length > 0) {
+    var strLen = '';
+    var isString = bufferTail[0] === 0;
+    for (i = 1; ; i++) {
+      if (bufferTail[i] === 255)  break;
+      // 310 = char length of Number.MAX_VALUE
+      if (strLen.length > 310) {
+        return callback(err, 0, 1);
+      }
+      strLen += '' + bufferTail[i];
+    }
+    bufferTail = bufferTail.slice(strLen.length + 1);
+
+    var msgLength = parseInt(strLen, 10);
+
+    var msg = bufferTail.slice(1, msgLength + 1);
+    if (isString) msg = bufferToString(msg);
+    buffers.push(msg);
+    bufferTail = bufferTail.slice(msgLength + 1);
+  }
+
+  var total = buffers.length;
+  for (i = 0; i < total; i++) {
+    var buffer = buffers[i];
+    callback(exports.decodePacket(buffer, binaryType, true), i, total);
+  }
+};
Index: trip-planner-front/node_modules/engine.io/lib/parser-v3/utf8.js
===================================================================
--- trip-planner-front/node_modules/engine.io/lib/parser-v3/utf8.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/engine.io/lib/parser-v3/utf8.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
@@ -0,0 +1,210 @@
+/*! https://mths.be/utf8js v2.1.2 by @mathias */
+
+var stringFromCharCode = String.fromCharCode;
+
+// Taken from https://mths.be/punycode
+function ucs2decode(string) {
+	var output = [];
+	var counter = 0;
+	var length = string.length;
+	var value;
+	var extra;
+	while (counter < length) {
+		value = string.charCodeAt(counter++);
+		if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+			// high surrogate, and there is a next character
+			extra = string.charCodeAt(counter++);
+			if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+				output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+			} else {
+				// unmatched surrogate; only append this code unit, in case the next
+				// code unit is the high surrogate of a surrogate pair
+				output.push(value);
+				counter--;
+			}
+		} else {
+			output.push(value);
+		}
+	}
+	return output;
+}
+
+// Taken from https://mths.be/punycode
+function ucs2encode(array) {
+	var length = array.length;
+	var index = -1;
+	var value;
+	var output = '';
+	while (++index < length) {
+		value = array[index];
+		if (value > 0xFFFF) {
+			value -= 0x10000;
+			output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+			value = 0xDC00 | value & 0x3FF;
+		}
+		output += stringFromCharCode(value);
+	}
+	return output;
+}
+
+function checkScalarValue(codePoint, strict) {
+	if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {
+		if (strict) {
+			throw Error(
+				'Lone surrogate U+' + codePoint.toString(16).toUpperCase() +
+				' is not a scalar value'
+			);
+		}
+		return false;
+	}
+	return true;
+}
+/*--------------------------------------------------------------------------*/
+
+function createByte(codePoint, shift) {
+	return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
+}
+
+function encodeCodePoint(codePoint, strict) {
+	if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
+		return stringFromCharCode(codePoint);
+	}
+	var symbol = '';
+	if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
+		symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
+	}
+	else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
+		if (!checkScalarValue(codePoint, strict)) {
+			codePoint = 0xFFFD;
+		}
+		symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
+		symbol += createByte(codePoint, 6);
+	}
+	else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
+		symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
+		symbol += createByte(codePoint, 12);
+		symbol += createByte(codePoint, 6);
+	}
+	symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
+	return symbol;
+}
+
+function utf8encode(string, opts) {
+	opts = opts || {};
+	var strict = false !== opts.strict;
+
+	var codePoints = ucs2decode(string);
+	var length = codePoints.length;
+	var index = -1;
+	var codePoint;
+	var byteString = '';
+	while (++index < length) {
+		codePoint = codePoints[index];
+		byteString += encodeCodePoint(codePoint, strict);
+	}
+	return byteString;
+}
+
+/*--------------------------------------------------------------------------*/
+
+function readContinuationByte() {
+	if (byteIndex >= byteCount) {
+		throw Error('Invalid byte index');
+	}
+
+	var continuationByte = byteArray[byteIndex] & 0xFF;
+	byteIndex++;
+
+	if ((continuationByte & 0xC0) == 0x80) {
+		return continuationByte & 0x3F;
+	}
+
+	// If we end up here, it’s not a continuation byte
+	throw Error('Invalid continuation byte');
+}
+
+function decodeSymbol(strict) {
+	var byte1;
+	var byte2;
+	var byte3;
+	var byte4;
+	var codePoint;
+
+	if (byteIndex > byteCount) {
+		throw Error('Invalid byte index');
+	}
+
+	if (byteIndex == byteCount) {
+		return false;
+	}
+
+	// Read first byte
+	byte1 = byteArray[byteIndex] & 0xFF;
+	byteIndex++;
+
+	// 1-byte sequence (no continuation bytes)
+	if ((byte1 & 0x80) == 0) {
+		return byte1;
+	}
+
+	// 2-byte sequence
+	if ((byte1 & 0xE0) == 0xC0) {
+		byte2 = readContinuationByte();
+		codePoint = ((byte1 & 0x1F) << 6) | byte2;
+		if (codePoint >= 0x80) {
+			return codePoint;
+		} else {
+			throw Error('Invalid continuation byte');
+		}
+	}
+
+	// 3-byte sequence (may include unpaired surrogates)
+	if ((byte1 & 0xF0) == 0xE0) {
+		byte2 = readContinuationByte();
+		byte3 = readContinuationByte();
+		codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
+		if (codePoint >= 0x0800) {
+			return checkScalarValue(codePoint, strict) ? codePoint : 0xFFFD;
+		} else {
+			throw Error('Invalid continuation byte');
+		}
+	}
+
+	// 4-byte sequence
+	if ((byte1 & 0xF8) == 0xF0) {
+		byte2 = readContinuationByte();
+		byte3 = readContinuationByte();
+		byte4 = readContinuationByte();
+		codePoint = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0C) |
+			(byte3 << 0x06) | byte4;
+		if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
+			return codePoint;
+		}
+	}
+
+	throw Error('Invalid UTF-8 detected');
+}
+
+var byteArray;
+var byteCount;
+var byteIndex;
+function utf8decode(byteString, opts) {
+	opts = opts || {};
+	var strict = false !== opts.strict;
+
+	byteArray = ucs2decode(byteString);
+	byteCount = byteArray.length;
+	byteIndex = 0;
+	var codePoints = [];
+	var tmp;
+	while ((tmp = decodeSymbol(strict)) !== false) {
+		codePoints.push(tmp);
+	}
+	return ucs2encode(codePoints);
+}
+
+module.exports = {
+	version: '2.1.2',
+	encode: utf8encode,
+	decode: utf8decode
+};
Index: trip-planner-front/node_modules/engine.io/lib/server.js
===================================================================
--- trip-planner-front/node_modules/engine.io/lib/server.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/engine.io/lib/server.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
@@ -0,0 +1,599 @@
+const qs = require("querystring");
+const parse = require("url").parse;
+const base64id = require("base64id");
+const transports = require("./transports");
+const EventEmitter = require("events").EventEmitter;
+const Socket = require("./socket");
+const debug = require("debug")("engine");
+const cookieMod = require("cookie");
+
+class Server extends EventEmitter {
+  /**
+   * Server constructor.
+   *
+   * @param {Object} options
+   * @api public
+   */
+  constructor(opts = {}) {
+    super();
+
+    this.clients = {};
+    this.clientsCount = 0;
+
+    this.opts = Object.assign(
+      {
+        wsEngine: process.env.EIO_WS_ENGINE || "ws",
+        pingTimeout: 5000,
+        pingInterval: 25000,
+        upgradeTimeout: 10000,
+        maxHttpBufferSize: 1e6,
+        transports: Object.keys(transports),
+        allowUpgrades: true,
+        httpCompression: {
+          threshold: 1024
+        },
+        cors: false,
+        allowEIO3: false
+      },
+      opts
+    );
+
+    if (opts.cookie) {
+      this.opts.cookie = Object.assign(
+        {
+          name: "io",
+          path: "/",
+          httpOnly: opts.cookie.path !== false,
+          sameSite: "lax"
+        },
+        opts.cookie
+      );
+    }
+
+    if (this.opts.cors) {
+      this.corsMiddleware = require("cors")(this.opts.cors);
+    }
+
+    if (opts.perMessageDeflate) {
+      this.opts.perMessageDeflate = Object.assign(
+        {
+          threshold: 1024
+        },
+        opts.perMessageDeflate
+      );
+    }
+
+    this.init();
+  }
+
+  /**
+   * Initialize websocket server
+   *
+   * @api private
+   */
+  init() {
+    if (!~this.opts.transports.indexOf("websocket")) return;
+
+    if (this.ws) this.ws.close();
+
+    // add explicit require for bundlers like webpack
+    const wsModule =
+      this.opts.wsEngine === "ws" ? require("ws") : require(this.opts.wsEngine);
+    this.ws = new wsModule.Server({
+      noServer: true,
+      clientTracking: false,
+      perMessageDeflate: this.opts.perMessageDeflate,
+      maxPayload: this.opts.maxHttpBufferSize
+    });
+  }
+
+  /**
+   * Returns a list of available transports for upgrade given a certain transport.
+   *
+   * @return {Array}
+   * @api public
+   */
+  upgrades(transport) {
+    if (!this.opts.allowUpgrades) return [];
+    return transports[transport].upgradesTo || [];
+  }
+
+  /**
+   * Verifies a request.
+   *
+   * @param {http.IncomingMessage}
+   * @return {Boolean} whether the request is valid
+   * @api private
+   */
+  verify(req, upgrade, fn) {
+    // transport check
+    const transport = req._query.transport;
+    if (!~this.opts.transports.indexOf(transport)) {
+      debug('unknown transport "%s"', transport);
+      return fn(Server.errors.UNKNOWN_TRANSPORT, false);
+    }
+
+    // 'Origin' header check
+    const isOriginInvalid = checkInvalidHeaderChar(req.headers.origin);
+    if (isOriginInvalid) {
+      req.headers.origin = null;
+      debug("origin header invalid");
+      return fn(Server.errors.BAD_REQUEST, false);
+    }
+
+    // sid check
+    const sid = req._query.sid;
+    if (sid) {
+      if (!this.clients.hasOwnProperty(sid)) {
+        debug('unknown sid "%s"', sid);
+        return fn(Server.errors.UNKNOWN_SID, false);
+      }
+      if (!upgrade && this.clients[sid].transport.name !== transport) {
+        debug("bad request: unexpected transport without upgrade");
+        return fn(Server.errors.BAD_REQUEST, false);
+      }
+    } else {
+      // handshake is GET only
+      if ("GET" !== req.method)
+        return fn(Server.errors.BAD_HANDSHAKE_METHOD, false);
+      if (!this.opts.allowRequest) return fn(null, true);
+      return this.opts.allowRequest(req, fn);
+    }
+
+    fn(null, true);
+  }
+
+  /**
+   * Prepares a request by processing the query string.
+   *
+   * @api private
+   */
+  prepare(req) {
+    // try to leverage pre-existing `req._query` (e.g: from connect)
+    if (!req._query) {
+      req._query = ~req.url.indexOf("?") ? qs.parse(parse(req.url).query) : {};
+    }
+  }
+
+  /**
+   * Closes all clients.
+   *
+   * @api public
+   */
+  close() {
+    debug("closing all open clients");
+    for (let i in this.clients) {
+      if (this.clients.hasOwnProperty(i)) {
+        this.clients[i].close(true);
+      }
+    }
+    if (this.ws) {
+      debug("closing webSocketServer");
+      this.ws.close();
+      // don't delete this.ws because it can be used again if the http server starts listening again
+    }
+    return this;
+  }
+
+  /**
+   * Handles an Engine.IO HTTP request.
+   *
+   * @param {http.IncomingMessage} request
+   * @param {http.ServerResponse|http.OutgoingMessage} response
+   * @api public
+   */
+  handleRequest(req, res) {
+    debug('handling "%s" http request "%s"', req.method, req.url);
+    this.prepare(req);
+    req.res = res;
+
+    const callback = (err, success) => {
+      if (!success) {
+        sendErrorMessage(req, res, err);
+        return;
+      }
+
+      if (req._query.sid) {
+        debug("setting new request for existing client");
+        this.clients[req._query.sid].transport.onRequest(req);
+      } else {
+        this.handshake(req._query.transport, req);
+      }
+    };
+
+    if (this.corsMiddleware) {
+      this.corsMiddleware.call(null, req, res, () => {
+        this.verify(req, false, callback);
+      });
+    } else {
+      this.verify(req, false, callback);
+    }
+  }
+
+  /**
+   * generate a socket id.
+   * Overwrite this method to generate your custom socket id
+   *
+   * @param {Object} request object
+   * @api public
+   */
+  generateId(req) {
+    return base64id.generateId();
+  }
+
+  /**
+   * Handshakes a new client.
+   *
+   * @param {String} transport name
+   * @param {Object} request object
+   * @api private
+   */
+  async handshake(transportName, req) {
+    const protocol = req._query.EIO === "3" ? 3 : 4; // 4th revision by default
+    if (protocol === 3 && !this.opts.allowEIO3) {
+      debug("unsupported protocol version");
+      sendErrorMessage(
+        req,
+        req.res,
+        Server.errors.UNSUPPORTED_PROTOCOL_VERSION
+      );
+      return;
+    }
+
+    let id;
+    try {
+      id = await this.generateId(req);
+    } catch (e) {
+      debug("error while generating an id");
+      sendErrorMessage(req, req.res, Server.errors.BAD_REQUEST);
+      return;
+    }
+
+    debug('handshaking client "%s"', id);
+
+    try {
+      var transport = new transports[transportName](req);
+      if ("polling" === transportName) {
+        transport.maxHttpBufferSize = this.opts.maxHttpBufferSize;
+        transport.httpCompression = this.opts.httpCompression;
+      } else if ("websocket" === transportName) {
+        transport.perMessageDeflate = this.opts.perMessageDeflate;
+      }
+
+      if (req._query && req._query.b64) {
+        transport.supportsBinary = false;
+      } else {
+        transport.supportsBinary = true;
+      }
+    } catch (e) {
+      debug('error handshaking to transport "%s"', transportName);
+      sendErrorMessage(req, req.res, Server.errors.BAD_REQUEST);
+      return;
+    }
+    const socket = new Socket(id, this, transport, req, protocol);
+    const self = this;
+
+    if (this.opts.cookie) {
+      transport.on("headers", headers => {
+        headers["Set-Cookie"] = cookieMod.serialize(
+          this.opts.cookie.name,
+          id,
+          this.opts.cookie
+        );
+      });
+    }
+
+    transport.onRequest(req);
+
+    this.clients[id] = socket;
+    this.clientsCount++;
+
+    socket.once("close", function() {
+      delete self.clients[id];
+      self.clientsCount--;
+    });
+
+    this.emit("connection", socket);
+  }
+
+  /**
+   * Handles an Engine.IO HTTP Upgrade.
+   *
+   * @api public
+   */
+  handleUpgrade(req, socket, upgradeHead) {
+    this.prepare(req);
+
+    const self = this;
+    this.verify(req, true, function(err, success) {
+      if (!success) {
+        abortConnection(socket, err);
+        return;
+      }
+
+      const head = Buffer.from(upgradeHead); // eslint-disable-line node/no-deprecated-api
+      upgradeHead = null;
+
+      // delegate to ws
+      self.ws.handleUpgrade(req, socket, head, function(conn) {
+        self.onWebSocket(req, conn);
+      });
+    });
+  }
+
+  /**
+   * Called upon a ws.io connection.
+   *
+   * @param {ws.Socket} websocket
+   * @api private
+   */
+  onWebSocket(req, socket) {
+    socket.on("error", onUpgradeError);
+
+    if (
+      transports[req._query.transport] !== undefined &&
+      !transports[req._query.transport].prototype.handlesUpgrades
+    ) {
+      debug("transport doesnt handle upgraded requests");
+      socket.close();
+      return;
+    }
+
+    // get client id
+    const id = req._query.sid;
+
+    // keep a reference to the ws.Socket
+    req.websocket = socket;
+
+    if (id) {
+      const client = this.clients[id];
+      if (!client) {
+        debug("upgrade attempt for closed client");
+        socket.close();
+      } else if (client.upgrading) {
+        debug("transport has already been trying to upgrade");
+        socket.close();
+      } else if (client.upgraded) {
+        debug("transport had already been upgraded");
+        socket.close();
+      } else {
+        debug("upgrading existing transport");
+
+        // transport error handling takes over
+        socket.removeListener("error", onUpgradeError);
+
+        const transport = new transports[req._query.transport](req);
+        if (req._query && req._query.b64) {
+          transport.supportsBinary = false;
+        } else {
+          transport.supportsBinary = true;
+        }
+        transport.perMessageDeflate = this.perMessageDeflate;
+        client.maybeUpgrade(transport);
+      }
+    } else {
+      // transport error handling takes over
+      socket.removeListener("error", onUpgradeError);
+
+      this.handshake(req._query.transport, req);
+    }
+
+    function onUpgradeError() {
+      debug("websocket error before upgrade");
+      // socket.close() not needed
+    }
+  }
+
+  /**
+   * Captures upgrade requests for a http.Server.
+   *
+   * @param {http.Server} server
+   * @param {Object} options
+   * @api public
+   */
+  attach(server, options) {
+    const self = this;
+    options = options || {};
+    let path = (options.path || "/engine.io").replace(/\/$/, "");
+
+    const destroyUpgradeTimeout = options.destroyUpgradeTimeout || 1000;
+
+    // normalize path
+    path += "/";
+
+    function check(req) {
+      return path === req.url.substr(0, path.length);
+    }
+
+    // cache and clean up listeners
+    const listeners = server.listeners("request").slice(0);
+    server.removeAllListeners("request");
+    server.on("close", self.close.bind(self));
+    server.on("listening", self.init.bind(self));
+
+    // add request handler
+    server.on("request", function(req, res) {
+      if (check(req)) {
+        debug('intercepting request for path "%s"', path);
+        self.handleRequest(req, res);
+      } else {
+        let i = 0;
+        const l = listeners.length;
+        for (; i < l; i++) {
+          listeners[i].call(server, req, res);
+        }
+      }
+    });
+
+    if (~self.opts.transports.indexOf("websocket")) {
+      server.on("upgrade", function(req, socket, head) {
+        if (check(req)) {
+          self.handleUpgrade(req, socket, head);
+        } else if (false !== options.destroyUpgrade) {
+          // default node behavior is to disconnect when no handlers
+          // but by adding a handler, we prevent that
+          // and if no eio thing handles the upgrade
+          // then the socket needs to die!
+          setTimeout(function() {
+            if (socket.writable && socket.bytesWritten <= 0) {
+              return socket.end();
+            }
+          }, destroyUpgradeTimeout);
+        }
+      });
+    }
+  }
+}
+
+/**
+ * Protocol errors mappings.
+ */
+
+Server.errors = {
+  UNKNOWN_TRANSPORT: 0,
+  UNKNOWN_SID: 1,
+  BAD_HANDSHAKE_METHOD: 2,
+  BAD_REQUEST: 3,
+  FORBIDDEN: 4,
+  UNSUPPORTED_PROTOCOL_VERSION: 5
+};
+
+Server.errorMessages = {
+  0: "Transport unknown",
+  1: "Session ID unknown",
+  2: "Bad handshake method",
+  3: "Bad request",
+  4: "Forbidden",
+  5: "Unsupported protocol version"
+};
+
+/**
+ * Sends an Engine.IO Error Message
+ *
+ * @param {http.ServerResponse} response
+ * @param {code} error code
+ * @api private
+ */
+
+function sendErrorMessage(req, res, code) {
+  const headers = { "Content-Type": "application/json" };
+
+  const isForbidden = !Server.errorMessages.hasOwnProperty(code);
+  if (isForbidden) {
+    res.writeHead(403, headers);
+    res.end(
+      JSON.stringify({
+        code: Server.errors.FORBIDDEN,
+        message: code || Server.errorMessages[Server.errors.FORBIDDEN]
+      })
+    );
+    return;
+  }
+  if (res !== undefined) {
+    res.writeHead(400, headers);
+    res.end(
+      JSON.stringify({
+        code: code,
+        message: Server.errorMessages[code]
+      })
+    );
+  }
+}
+
+/**
+ * Closes the connection
+ *
+ * @param {net.Socket} socket
+ * @param {code} error code
+ * @api private
+ */
+
+function abortConnection(socket, code) {
+  socket.on("error", () => {
+    debug("ignoring error from closed connection");
+  });
+  if (socket.writable) {
+    const message = Server.errorMessages.hasOwnProperty(code)
+      ? Server.errorMessages[code]
+      : String(code || "");
+    const length = Buffer.byteLength(message);
+    socket.write(
+      "HTTP/1.1 400 Bad Request\r\n" +
+        "Connection: close\r\n" +
+        "Content-type: text/html\r\n" +
+        "Content-Length: " +
+        length +
+        "\r\n" +
+        "\r\n" +
+        message
+    );
+  }
+  socket.destroy();
+}
+
+module.exports = Server;
+
+/* eslint-disable */
+
+/**
+ * From https://github.com/nodejs/node/blob/v8.4.0/lib/_http_common.js#L303-L354
+ *
+ * True if val contains an invalid field-vchar
+ *  field-value    = *( field-content / obs-fold )
+ *  field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+ *  field-vchar    = VCHAR / obs-text
+ *
+ * checkInvalidHeaderChar() is currently designed to be inlinable by v8,
+ * so take care when making changes to the implementation so that the source
+ * code size does not exceed v8's default max_inlined_source_size setting.
+ **/
+// prettier-ignore
+const validHdrChars = [
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0 - 15
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32 - 47
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48 - 63
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 - 95
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112 - 127
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128 ...
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // ... 255
+]
+
+function checkInvalidHeaderChar(val) {
+  val += "";
+  if (val.length < 1) return false;
+  if (!validHdrChars[val.charCodeAt(0)]) {
+    debug('invalid header, index 0, char "%s"', val.charCodeAt(0));
+    return true;
+  }
+  if (val.length < 2) return false;
+  if (!validHdrChars[val.charCodeAt(1)]) {
+    debug('invalid header, index 1, char "%s"', val.charCodeAt(1));
+    return true;
+  }
+  if (val.length < 3) return false;
+  if (!validHdrChars[val.charCodeAt(2)]) {
+    debug('invalid header, index 2, char "%s"', val.charCodeAt(2));
+    return true;
+  }
+  if (val.length < 4) return false;
+  if (!validHdrChars[val.charCodeAt(3)]) {
+    debug('invalid header, index 3, char "%s"', val.charCodeAt(3));
+    return true;
+  }
+  for (let i = 4; i < val.length; ++i) {
+    if (!validHdrChars[val.charCodeAt(i)]) {
+      debug('invalid header, index "%i", char "%s"', i, val.charCodeAt(i));
+      return true;
+    }
+  }
+  return false;
+}
Index: trip-planner-front/node_modules/engine.io/lib/socket.js
===================================================================
--- trip-planner-front/node_modules/engine.io/lib/socket.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/engine.io/lib/socket.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
@@ -0,0 +1,522 @@
+const EventEmitter = require("events");
+const debug = require("debug")("engine:socket");
+
+class Socket extends EventEmitter {
+  /**
+   * Client class (abstract).
+   *
+   * @api private
+   */
+  constructor(id, server, transport, req, protocol) {
+    super();
+    this.id = id;
+    this.server = server;
+    this.upgrading = false;
+    this.upgraded = false;
+    this.readyState = "opening";
+    this.writeBuffer = [];
+    this.packetsFn = [];
+    this.sentCallbackFn = [];
+    this.cleanupFn = [];
+    this.request = req;
+    this.protocol = protocol;
+
+    // Cache IP since it might not be in the req later
+    if (req.websocket && req.websocket._socket) {
+      this.remoteAddress = req.websocket._socket.remoteAddress;
+    } else {
+      this.remoteAddress = req.connection.remoteAddress;
+    }
+
+    this.checkIntervalTimer = null;
+    this.upgradeTimeoutTimer = null;
+    this.pingTimeoutTimer = null;
+    this.pingIntervalTimer = null;
+
+    this.setTransport(transport);
+    this.onOpen();
+  }
+
+  /**
+   * Called upon transport considered open.
+   *
+   * @api private
+   */
+  onOpen() {
+    this.readyState = "open";
+
+    // sends an `open` packet
+    this.transport.sid = this.id;
+    this.sendPacket(
+      "open",
+      JSON.stringify({
+        sid: this.id,
+        upgrades: this.getAvailableUpgrades(),
+        pingInterval: this.server.opts.pingInterval,
+        pingTimeout: this.server.opts.pingTimeout
+      })
+    );
+
+    if (this.server.opts.initialPacket) {
+      this.sendPacket("message", this.server.opts.initialPacket);
+    }
+
+    this.emit("open");
+
+    if (this.protocol === 3) {
+      // in protocol v3, the client sends a ping, and the server answers with a pong
+      this.resetPingTimeout(
+        this.server.opts.pingInterval + this.server.opts.pingTimeout
+      );
+    } else {
+      // in protocol v4, the server sends a ping, and the client answers with a pong
+      this.schedulePing();
+    }
+  }
+
+  /**
+   * Called upon transport packet.
+   *
+   * @param {Object} packet
+   * @api private
+   */
+  onPacket(packet) {
+    if ("open" === this.readyState) {
+      // export packet event
+      debug("packet");
+      this.emit("packet", packet);
+
+      // Reset ping timeout on any packet, incoming data is a good sign of
+      // other side's liveness
+      this.resetPingTimeout(
+        this.server.opts.pingInterval + this.server.opts.pingTimeout
+      );
+
+      switch (packet.type) {
+        case "ping":
+          if (this.transport.protocol !== 3) {
+            this.onError("invalid heartbeat direction");
+            return;
+          }
+          debug("got ping");
+          this.sendPacket("pong");
+          this.emit("heartbeat");
+          break;
+
+        case "pong":
+          if (this.transport.protocol === 3) {
+            this.onError("invalid heartbeat direction");
+            return;
+          }
+          debug("got pong");
+          this.schedulePing();
+          this.emit("heartbeat");
+          break;
+
+        case "error":
+          this.onClose("parse error");
+          break;
+
+        case "message":
+          this.emit("data", packet.data);
+          this.emit("message", packet.data);
+          break;
+      }
+    } else {
+      debug("packet received with closed socket");
+    }
+  }
+
+  /**
+   * Called upon transport error.
+   *
+   * @param {Error} error object
+   * @api private
+   */
+  onError(err) {
+    debug("transport error");
+    this.onClose("transport error", err);
+  }
+
+  /**
+   * Pings client every `this.pingInterval` and expects response
+   * within `this.pingTimeout` or closes connection.
+   *
+   * @api private
+   */
+  schedulePing() {
+    clearTimeout(this.pingIntervalTimer);
+    this.pingIntervalTimer = setTimeout(() => {
+      debug(
+        "writing ping packet - expecting pong within %sms",
+        this.server.opts.pingTimeout
+      );
+      this.sendPacket("ping");
+      this.resetPingTimeout(this.server.opts.pingTimeout);
+    }, this.server.opts.pingInterval);
+  }
+
+  /**
+   * Resets ping timeout.
+   *
+   * @api private
+   */
+  resetPingTimeout(timeout) {
+    clearTimeout(this.pingTimeoutTimer);
+    this.pingTimeoutTimer = setTimeout(() => {
+      if (this.readyState === "closed") return;
+      this.onClose("ping timeout");
+    }, timeout);
+  }
+
+  /**
+   * Attaches handlers for the given transport.
+   *
+   * @param {Transport} transport
+   * @api private
+   */
+  setTransport(transport) {
+    const onError = this.onError.bind(this);
+    const onPacket = this.onPacket.bind(this);
+    const flush = this.flush.bind(this);
+    const onClose = this.onClose.bind(this, "transport close");
+
+    this.transport = transport;
+    this.transport.once("error", onError);
+    this.transport.on("packet", onPacket);
+    this.transport.on("drain", flush);
+    this.transport.once("close", onClose);
+    // this function will manage packet events (also message callbacks)
+    this.setupSendCallback();
+
+    this.cleanupFn.push(function() {
+      transport.removeListener("error", onError);
+      transport.removeListener("packet", onPacket);
+      transport.removeListener("drain", flush);
+      transport.removeListener("close", onClose);
+    });
+  }
+
+  /**
+   * Upgrades socket to the given transport
+   *
+   * @param {Transport} transport
+   * @api private
+   */
+  maybeUpgrade(transport) {
+    debug(
+      'might upgrade socket transport from "%s" to "%s"',
+      this.transport.name,
+      transport.name
+    );
+
+    this.upgrading = true;
+
+    const self = this;
+
+    // set transport upgrade timer
+    self.upgradeTimeoutTimer = setTimeout(function() {
+      debug("client did not complete upgrade - closing transport");
+      cleanup();
+      if ("open" === transport.readyState) {
+        transport.close();
+      }
+    }, this.server.opts.upgradeTimeout);
+
+    function onPacket(packet) {
+      if ("ping" === packet.type && "probe" === packet.data) {
+        transport.send([{ type: "pong", data: "probe" }]);
+        self.emit("upgrading", transport);
+        clearInterval(self.checkIntervalTimer);
+        self.checkIntervalTimer = setInterval(check, 100);
+      } else if ("upgrade" === packet.type && self.readyState !== "closed") {
+        debug("got upgrade packet - upgrading");
+        cleanup();
+        self.transport.discard();
+        self.upgraded = true;
+        self.clearTransport();
+        self.setTransport(transport);
+        self.emit("upgrade", transport);
+        self.flush();
+        if (self.readyState === "closing") {
+          transport.close(function() {
+            self.onClose("forced close");
+          });
+        }
+      } else {
+        cleanup();
+        transport.close();
+      }
+    }
+
+    // we force a polling cycle to ensure a fast upgrade
+    function check() {
+      if ("polling" === self.transport.name && self.transport.writable) {
+        debug("writing a noop packet to polling for fast upgrade");
+        self.transport.send([{ type: "noop" }]);
+      }
+    }
+
+    function cleanup() {
+      self.upgrading = false;
+
+      clearInterval(self.checkIntervalTimer);
+      self.checkIntervalTimer = null;
+
+      clearTimeout(self.upgradeTimeoutTimer);
+      self.upgradeTimeoutTimer = null;
+
+      transport.removeListener("packet", onPacket);
+      transport.removeListener("close", onTransportClose);
+      transport.removeListener("error", onError);
+      self.removeListener("close", onClose);
+    }
+
+    function onError(err) {
+      debug("client did not complete upgrade - %s", err);
+      cleanup();
+      transport.close();
+      transport = null;
+    }
+
+    function onTransportClose() {
+      onError("transport closed");
+    }
+
+    function onClose() {
+      onError("socket closed");
+    }
+
+    transport.on("packet", onPacket);
+    transport.once("close", onTransportClose);
+    transport.once("error", onError);
+
+    self.once("close", onClose);
+  }
+
+  /**
+   * Clears listeners and timers associated with current transport.
+   *
+   * @api private
+   */
+  clearTransport() {
+    let cleanup;
+
+    const toCleanUp = this.cleanupFn.length;
+
+    for (let i = 0; i < toCleanUp; i++) {
+      cleanup = this.cleanupFn.shift();
+      cleanup();
+    }
+
+    // silence further transport errors and prevent uncaught exceptions
+    this.transport.on("error", function() {
+      debug("error triggered by discarded transport");
+    });
+
+    // ensure transport won't stay open
+    this.transport.close();
+
+    clearTimeout(this.pingTimeoutTimer);
+  }
+
+  /**
+   * Called upon transport considered closed.
+   * Possible reasons: `ping timeout`, `client error`, `parse error`,
+   * `transport error`, `server close`, `transport close`
+   */
+  onClose(reason, description) {
+    if ("closed" !== this.readyState) {
+      this.readyState = "closed";
+
+      // clear timers
+      clearTimeout(this.pingIntervalTimer);
+      clearTimeout(this.pingTimeoutTimer);
+
+      clearInterval(this.checkIntervalTimer);
+      this.checkIntervalTimer = null;
+      clearTimeout(this.upgradeTimeoutTimer);
+      const self = this;
+      // clean writeBuffer in next tick, so developers can still
+      // grab the writeBuffer on 'close' event
+      process.nextTick(function() {
+        self.writeBuffer = [];
+      });
+      this.packetsFn = [];
+      this.sentCallbackFn = [];
+      this.clearTransport();
+      this.emit("close", reason, description);
+    }
+  }
+
+  /**
+   * Setup and manage send callback
+   *
+   * @api private
+   */
+  setupSendCallback() {
+    const self = this;
+    this.transport.on("drain", onDrain);
+
+    this.cleanupFn.push(function() {
+      self.transport.removeListener("drain", onDrain);
+    });
+
+    // the message was sent successfully, execute the callback
+    function onDrain() {
+      if (self.sentCallbackFn.length > 0) {
+        const seqFn = self.sentCallbackFn.splice(0, 1)[0];
+        if ("function" === typeof seqFn) {
+          debug("executing send callback");
+          seqFn(self.transport);
+        } else if (Array.isArray(seqFn)) {
+          debug("executing batch send callback");
+          const l = seqFn.length;
+          let i = 0;
+          for (; i < l; i++) {
+            if ("function" === typeof seqFn[i]) {
+              seqFn[i](self.transport);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Sends a message packet.
+   *
+   * @param {String} message
+   * @param {Object} options
+   * @param {Function} callback
+   * @return {Socket} for chaining
+   * @api public
+   */
+  send(data, options, callback) {
+    this.sendPacket("message", data, options, callback);
+    return this;
+  }
+
+  write(data, options, callback) {
+    this.sendPacket("message", data, options, callback);
+    return this;
+  }
+
+  /**
+   * Sends a packet.
+   *
+   * @param {String} packet type
+   * @param {String} optional, data
+   * @param {Object} options
+   * @api private
+   */
+  sendPacket(type, data, options, callback) {
+    if ("function" === typeof options) {
+      callback = options;
+      options = null;
+    }
+
+    options = options || {};
+    options.compress = false !== options.compress;
+
+    if ("closing" !== this.readyState && "closed" !== this.readyState) {
+      debug('sending packet "%s" (%s)', type, data);
+
+      const packet = {
+        type: type,
+        options: options
+      };
+      if (data) packet.data = data;
+
+      // exports packetCreate event
+      this.emit("packetCreate", packet);
+
+      this.writeBuffer.push(packet);
+
+      // add send callback to object, if defined
+      if (callback) this.packetsFn.push(callback);
+
+      this.flush();
+    }
+  }
+
+  /**
+   * Attempts to flush the packets buffer.
+   *
+   * @api private
+   */
+  flush() {
+    if (
+      "closed" !== this.readyState &&
+      this.transport.writable &&
+      this.writeBuffer.length
+    ) {
+      debug("flushing buffer to transport");
+      this.emit("flush", this.writeBuffer);
+      this.server.emit("flush", this, this.writeBuffer);
+      const wbuf = this.writeBuffer;
+      this.writeBuffer = [];
+      if (!this.transport.supportsFraming) {
+        this.sentCallbackFn.push(this.packetsFn);
+      } else {
+        this.sentCallbackFn.push.apply(this.sentCallbackFn, this.packetsFn);
+      }
+      this.packetsFn = [];
+      this.transport.send(wbuf);
+      this.emit("drain");
+      this.server.emit("drain", this);
+    }
+  }
+
+  /**
+   * Get available upgrades for this socket.
+   *
+   * @api private
+   */
+  getAvailableUpgrades() {
+    const availableUpgrades = [];
+    const allUpgrades = this.server.upgrades(this.transport.name);
+    let i = 0;
+    const l = allUpgrades.length;
+    for (; i < l; ++i) {
+      const upg = allUpgrades[i];
+      if (this.server.opts.transports.indexOf(upg) !== -1) {
+        availableUpgrades.push(upg);
+      }
+    }
+    return availableUpgrades;
+  }
+
+  /**
+   * Closes the socket and underlying transport.
+   *
+   * @param {Boolean} optional, discard
+   * @return {Socket} for chaining
+   * @api public
+   */
+  close(discard) {
+    if ("open" !== this.readyState) return;
+
+    this.readyState = "closing";
+
+    if (this.writeBuffer.length) {
+      this.once("drain", this.closeTransport.bind(this, discard));
+      return;
+    }
+
+    this.closeTransport(discard);
+  }
+
+  /**
+   * Closes the underlying transport.
+   *
+   * @param {Boolean} discard
+   * @api private
+   */
+  closeTransport(discard) {
+    if (discard) this.transport.discard();
+    this.transport.close(this.onClose.bind(this, "forced close"));
+  }
+}
+
+module.exports = Socket;
Index: trip-planner-front/node_modules/engine.io/lib/transport.js
===================================================================
--- trip-planner-front/node_modules/engine.io/lib/transport.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/engine.io/lib/transport.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
@@ -0,0 +1,110 @@
+const EventEmitter = require("events");
+const parser_v4 = require("engine.io-parser");
+const parser_v3 = require("./parser-v3/index");
+const debug = require("debug")("engine:transport");
+
+/**
+ * Noop function.
+ *
+ * @api private
+ */
+
+function noop() {}
+
+class Transport extends EventEmitter {
+  /**
+   * Transport constructor.
+   *
+   * @param {http.IncomingMessage} request
+   * @api public
+   */
+  constructor(req) {
+    super();
+    this.readyState = "open";
+    this.discarded = false;
+    this.protocol = req._query.EIO === "3" ? 3 : 4; // 4th revision by default
+    this.parser = this.protocol === 3 ? parser_v3 : parser_v4;
+  }
+
+  /**
+   * Flags the transport as discarded.
+   *
+   * @api private
+   */
+  discard() {
+    this.discarded = true;
+  }
+
+  /**
+   * Called with an incoming HTTP request.
+   *
+   * @param {http.IncomingMessage} request
+   * @api private
+   */
+  onRequest(req) {
+    debug("setting request");
+    this.req = req;
+  }
+
+  /**
+   * Closes the transport.
+   *
+   * @api private
+   */
+  close(fn) {
+    if ("closed" === this.readyState || "closing" === this.readyState) return;
+
+    this.readyState = "closing";
+    this.doClose(fn || noop);
+  }
+
+  /**
+   * Called with a transport error.
+   *
+   * @param {String} message error
+   * @param {Object} error description
+   * @api private
+   */
+  onError(msg, desc) {
+    if (this.listeners("error").length) {
+      const err = new Error(msg);
+      err.type = "TransportError";
+      err.description = desc;
+      this.emit("error", err);
+    } else {
+      debug("ignored transport error %s (%s)", msg, desc);
+    }
+  }
+
+  /**
+   * Called with parsed out a packets from the data stream.
+   *
+   * @param {Object} packet
+   * @api private
+   */
+  onPacket(packet) {
+    this.emit("packet", packet);
+  }
+
+  /**
+   * Called with the encoded packet data.
+   *
+   * @param {String} data
+   * @api private
+   */
+  onData(data) {
+    this.onPacket(this.parser.decodePacket(data));
+  }
+
+  /**
+   * Called upon transport close.
+   *
+   * @api private
+   */
+  onClose() {
+    this.readyState = "closed";
+    this.emit("close");
+  }
+}
+
+module.exports = Transport;
Index: trip-planner-front/node_modules/engine.io/lib/transports/index.js
===================================================================
--- trip-planner-front/node_modules/engine.io/lib/transports/index.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/engine.io/lib/transports/index.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
@@ -0,0 +1,31 @@
+const XHR = require("./polling");
+const JSONP = require("./polling-jsonp");
+
+/**
+ * Export transports.
+ */
+
+module.exports = exports = {
+  polling: polling,
+  websocket: require("./websocket")
+};
+
+/**
+ * Export upgrades map.
+ */
+
+exports.polling.upgradesTo = ["websocket"];
+
+/**
+ * Polling polymorphic constructor.
+ *
+ * @api private
+ */
+
+function polling(req) {
+  if ("string" === typeof req._query.j) {
+    return new JSONP(req);
+  } else {
+    return new XHR(req);
+  }
+}
Index: trip-planner-front/node_modules/engine.io/lib/transports/polling-jsonp.js
===================================================================
--- trip-planner-front/node_modules/engine.io/lib/transports/polling-jsonp.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/engine.io/lib/transports/polling-jsonp.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
@@ -0,0 +1,58 @@
+const Polling = require("./polling");
+const qs = require("querystring");
+const rDoubleSlashes = /\\\\n/g;
+const rSlashes = /(\\)?\\n/g;
+
+class JSONP extends Polling {
+  /**
+   * JSON-P polling transport.
+   *
+   * @api public
+   */
+  constructor(req) {
+    super(req);
+
+    this.head = "___eio[" + (req._query.j || "").replace(/[^0-9]/g, "") + "](";
+    this.foot = ");";
+  }
+
+  /**
+   * Handles incoming data.
+   * Due to a bug in \n handling by browsers, we expect a escaped string.
+   *
+   * @api private
+   */
+  onData(data) {
+    // we leverage the qs module so that we get built-in DoS protection
+    // and the fast alternative to decodeURIComponent
+    data = qs.parse(data).d;
+    if ("string" === typeof data) {
+      // client will send already escaped newlines as \\\\n and newlines as \\n
+      // \\n must be replaced with \n and \\\\n with \\n
+      data = data.replace(rSlashes, function(match, slashes) {
+        return slashes ? match : "\n";
+      });
+      super.onData(data.replace(rDoubleSlashes, "\\n"));
+    }
+  }
+
+  /**
+   * Performs the write.
+   *
+   * @api private
+   */
+  doWrite(data, options, callback) {
+    // we must output valid javascript, not valid json
+    // see: http://timelessrepo.com/json-isnt-a-javascript-subset
+    const js = JSON.stringify(data)
+      .replace(/\u2028/g, "\\u2028")
+      .replace(/\u2029/g, "\\u2029");
+
+    // prepare response
+    data = this.head + js + this.foot;
+
+    super.doWrite(data, options, callback);
+  }
+}
+
+module.exports = JSONP;
Index: trip-planner-front/node_modules/engine.io/lib/transports/polling.js
===================================================================
--- trip-planner-front/node_modules/engine.io/lib/transports/polling.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/engine.io/lib/transports/polling.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
@@ -0,0 +1,393 @@
+const Transport = require("../transport");
+const zlib = require("zlib");
+const accepts = require("accepts");
+const debug = require("debug")("engine:polling");
+
+const compressionMethods = {
+  gzip: zlib.createGzip,
+  deflate: zlib.createDeflate
+};
+
+class Polling extends Transport {
+  /**
+   * HTTP polling constructor.
+   *
+   * @api public.
+   */
+  constructor(req) {
+    super(req);
+
+    this.closeTimeout = 30 * 1000;
+    this.maxHttpBufferSize = null;
+    this.httpCompression = null;
+  }
+
+  /**
+   * Transport name
+   *
+   * @api public
+   */
+  get name() {
+    return "polling";
+  }
+
+  /**
+   * Overrides onRequest.
+   *
+   * @param {http.IncomingMessage}
+   * @api private
+   */
+  onRequest(req) {
+    const res = req.res;
+
+    if ("GET" === req.method) {
+      this.onPollRequest(req, res);
+    } else if ("POST" === req.method) {
+      this.onDataRequest(req, res);
+    } else {
+      res.writeHead(500);
+      res.end();
+    }
+  }
+
+  /**
+   * The client sends a request awaiting for us to send data.
+   *
+   * @api private
+   */
+  onPollRequest(req, res) {
+    if (this.req) {
+      debug("request overlap");
+      // assert: this.res, '.req and .res should be (un)set together'
+      this.onError("overlap from client");
+      res.writeHead(500);
+      res.end();
+      return;
+    }
+
+    debug("setting request");
+
+    this.req = req;
+    this.res = res;
+
+    const self = this;
+
+    function onClose() {
+      self.onError("poll connection closed prematurely");
+    }
+
+    function cleanup() {
+      req.removeListener("close", onClose);
+      self.req = self.res = null;
+    }
+
+    req.cleanup = cleanup;
+    req.on("close", onClose);
+
+    this.writable = true;
+    this.emit("drain");
+
+    // if we're still writable but had a pending close, trigger an empty send
+    if (this.writable && this.shouldClose) {
+      debug("triggering empty send to append close packet");
+      this.send([{ type: "noop" }]);
+    }
+  }
+
+  /**
+   * The client sends a request with data.
+   *
+   * @api private
+   */
+  onDataRequest(req, res) {
+    if (this.dataReq) {
+      // assert: this.dataRes, '.dataReq and .dataRes should be (un)set together'
+      this.onError("data request overlap from client");
+      res.writeHead(500);
+      res.end();
+      return;
+    }
+
+    const isBinary = "application/octet-stream" === req.headers["content-type"];
+
+    if (isBinary && this.protocol === 4) {
+      return this.onError("invalid content");
+    }
+
+    this.dataReq = req;
+    this.dataRes = res;
+
+    let chunks = isBinary ? Buffer.concat([]) : "";
+    const self = this;
+
+    function cleanup() {
+      req.removeListener("data", onData);
+      req.removeListener("end", onEnd);
+      req.removeListener("close", onClose);
+      self.dataReq = self.dataRes = chunks = null;
+    }
+
+    function onClose() {
+      cleanup();
+      self.onError("data request connection closed prematurely");
+    }
+
+    function onData(data) {
+      let contentLength;
+      if (isBinary) {
+        chunks = Buffer.concat([chunks, data]);
+        contentLength = chunks.length;
+      } else {
+        chunks += data;
+        contentLength = Buffer.byteLength(chunks);
+      }
+
+      if (contentLength > self.maxHttpBufferSize) {
+        chunks = isBinary ? Buffer.concat([]) : "";
+        req.connection.destroy();
+      }
+    }
+
+    function onEnd() {
+      self.onData(chunks);
+
+      const headers = {
+        // text/html is required instead of text/plain to avoid an
+        // unwanted download dialog on certain user-agents (GH-43)
+        "Content-Type": "text/html",
+        "Content-Length": 2
+      };
+
+      res.writeHead(200, self.headers(req, headers));
+      res.end("ok");
+      cleanup();
+    }
+
+    req.on("close", onClose);
+    if (!isBinary) req.setEncoding("utf8");
+    req.on("data", onData);
+    req.on("end", onEnd);
+  }
+
+  /**
+   * Processes the incoming data payload.
+   *
+   * @param {String} encoded payload
+   * @api private
+   */
+  onData(data) {
+    debug('received "%s"', data);
+    const self = this;
+    const callback = function(packet) {
+      if ("close" === packet.type) {
+        debug("got xhr close packet");
+        self.onClose();
+        return false;
+      }
+
+      self.onPacket(packet);
+    };
+
+    if (this.protocol === 3) {
+      this.parser.decodePayload(data, callback);
+    } else {
+      this.parser.decodePayload(data).forEach(callback);
+    }
+  }
+
+  /**
+   * Overrides onClose.
+   *
+   * @api private
+   */
+  onClose() {
+    if (this.writable) {
+      // close pending poll request
+      this.send([{ type: "noop" }]);
+    }
+    super.onClose();
+  }
+
+  /**
+   * Writes a packet payload.
+   *
+   * @param {Object} packet
+   * @api private
+   */
+  send(packets) {
+    this.writable = false;
+
+    if (this.shouldClose) {
+      debug("appending close packet to payload");
+      packets.push({ type: "close" });
+      this.shouldClose();
+      this.shouldClose = null;
+    }
+
+    const doWrite = data => {
+      const compress = packets.some(packet => {
+        return packet.options && packet.options.compress;
+      });
+      this.write(data, { compress });
+    };
+
+    if (this.protocol === 3) {
+      this.parser.encodePayload(packets, this.supportsBinary, doWrite);
+    } else {
+      this.parser.encodePayload(packets, doWrite);
+    }
+  }
+
+  /**
+   * Writes data as response to poll request.
+   *
+   * @param {String} data
+   * @param {Object} options
+   * @api private
+   */
+  write(data, options) {
+    debug('writing "%s"', data);
+    const self = this;
+    this.doWrite(data, options, function() {
+      self.req.cleanup();
+    });
+  }
+
+  /**
+   * Performs the write.
+   *
+   * @api private
+   */
+  doWrite(data, options, callback) {
+    const self = this;
+
+    // explicit UTF-8 is required for pages not served under utf
+    const isString = typeof data === "string";
+    const contentType = isString
+      ? "text/plain; charset=UTF-8"
+      : "application/octet-stream";
+
+    const headers = {
+      "Content-Type": contentType
+    };
+
+    if (!this.httpCompression || !options.compress) {
+      respond(data);
+      return;
+    }
+
+    const len = isString ? Buffer.byteLength(data) : data.length;
+    if (len < this.httpCompression.threshold) {
+      respond(data);
+      return;
+    }
+
+    const encoding = accepts(this.req).encodings(["gzip", "deflate"]);
+    if (!encoding) {
+      respond(data);
+      return;
+    }
+
+    this.compress(data, encoding, function(err, data) {
+      if (err) {
+        self.res.writeHead(500);
+        self.res.end();
+        callback(err);
+        return;
+      }
+
+      headers["Content-Encoding"] = encoding;
+      respond(data);
+    });
+
+    function respond(data) {
+      headers["Content-Length"] =
+        "string" === typeof data ? Buffer.byteLength(data) : data.length;
+      self.res.writeHead(200, self.headers(self.req, headers));
+      self.res.end(data);
+      callback();
+    }
+  }
+
+  /**
+   * Compresses data.
+   *
+   * @api private
+   */
+  compress(data, encoding, callback) {
+    debug("compressing");
+
+    const buffers = [];
+    let nread = 0;
+
+    compressionMethods[encoding](this.httpCompression)
+      .on("error", callback)
+      .on("data", function(chunk) {
+        buffers.push(chunk);
+        nread += chunk.length;
+      })
+      .on("end", function() {
+        callback(null, Buffer.concat(buffers, nread));
+      })
+      .end(data);
+  }
+
+  /**
+   * Closes the transport.
+   *
+   * @api private
+   */
+  doClose(fn) {
+    debug("closing");
+
+    const self = this;
+    let closeTimeoutTimer;
+
+    if (this.dataReq) {
+      debug("aborting ongoing data request");
+      this.dataReq.destroy();
+    }
+
+    if (this.writable) {
+      debug("transport writable - closing right away");
+      this.send([{ type: "close" }]);
+      onClose();
+    } else if (this.discarded) {
+      debug("transport discarded - closing right away");
+      onClose();
+    } else {
+      debug("transport not writable - buffering orderly close");
+      this.shouldClose = onClose;
+      closeTimeoutTimer = setTimeout(onClose, this.closeTimeout);
+    }
+
+    function onClose() {
+      clearTimeout(closeTimeoutTimer);
+      fn();
+      self.onClose();
+    }
+  }
+
+  /**
+   * Returns headers for a response.
+   *
+   * @param {http.IncomingMessage} request
+   * @param {Object} extra headers
+   * @api private
+   */
+  headers(req, headers) {
+    headers = headers || {};
+
+    // prevent XSS warnings on IE
+    // https://github.com/LearnBoost/socket.io/pull/1333
+    const ua = req.headers["user-agent"];
+    if (ua && (~ua.indexOf(";MSIE") || ~ua.indexOf("Trident/"))) {
+      headers["X-XSS-Protection"] = "0";
+    }
+
+    this.emit("headers", headers);
+    return headers;
+  }
+}
+
+module.exports = Polling;
Index: trip-planner-front/node_modules/engine.io/lib/transports/websocket.js
===================================================================
--- trip-planner-front/node_modules/engine.io/lib/transports/websocket.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/engine.io/lib/transports/websocket.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
@@ -0,0 +1,116 @@
+const Transport = require("../transport");
+const debug = require("debug")("engine:ws");
+
+class WebSocket extends Transport {
+  /**
+   * WebSocket transport
+   *
+   * @param {http.IncomingMessage}
+   * @api public
+   */
+  constructor(req) {
+    super(req);
+    this.socket = req.websocket;
+    this.socket.on("message", this.onData.bind(this));
+    this.socket.once("close", this.onClose.bind(this));
+    this.socket.on("error", this.onError.bind(this));
+    this.socket.on("headers", headers => {
+      this.emit("headers", headers);
+    });
+    this.writable = true;
+    this.perMessageDeflate = null;
+  }
+
+  /**
+   * Transport name
+   *
+   * @api public
+   */
+  get name() {
+    return "websocket";
+  }
+
+  /**
+   * Advertise upgrade support.
+   *
+   * @api public
+   */
+  get handlesUpgrades() {
+    return true;
+  }
+
+  /**
+   * Advertise framing support.
+   *
+   * @api public
+   */
+  get supportsFraming() {
+    return true;
+  }
+
+  /**
+   * Processes the incoming data.
+   *
+   * @param {String} encoded packet
+   * @api private
+   */
+  onData(data) {
+    debug('received "%s"', data);
+    super.onData(data);
+  }
+
+  /**
+   * Writes a packet payload.
+   *
+   * @param {Array} packets
+   * @api private
+   */
+  send(packets) {
+    var self = this;
+
+    for (var i = 0; i < packets.length; i++) {
+      var packet = packets[i];
+      this.parser.encodePacket(packet, self.supportsBinary, send);
+    }
+
+    function send(data) {
+      debug('writing "%s"', data);
+
+      // always creates a new object since ws modifies it
+      var opts = {};
+      if (packet.options) {
+        opts.compress = packet.options.compress;
+      }
+
+      if (self.perMessageDeflate) {
+        var len =
+          "string" === typeof data ? Buffer.byteLength(data) : data.length;
+        if (len < self.perMessageDeflate.threshold) {
+          opts.compress = false;
+        }
+      }
+
+      self.writable = false;
+      self.socket.send(data, opts, onEnd);
+    }
+
+    function onEnd(err) {
+      if (err) return self.onError("write error", err.stack);
+      self.writable = true;
+      self.emit("drain");
+    }
+  }
+
+  /**
+   * Closes the transport.
+   *
+   * @api private
+   */
+  doClose(fn) {
+    debug("closing");
+    this.socket.close();
+    fn && fn();
+  }
+}
+
+module.exports = WebSocket;
