text: /**
   * eventsource.js
   * Available under MIT License (MIT)
   * https://github.com/Yaffle/EventSource/
   *
   * Forked and modified by Matthias Nehlsen under:
   * https://github.com/matthiasn/EventSource
   *
   * Modifications:
   * 1) only loads when a global EventSource object does not exist.
   * 2) skip check for ContentType as that check was not compatible with Play Framework's EventSource
   *    implementation.
   */
  
  /*jslint indent: 2, vars: true, plusplus: true */
  /*global setTimeout, clearTimeout */
  
  /** modified by Matthias Nehlsen on June 9th, 2014 to add check without changing the indentation of the rest of the
   *  file so that changes can more easily be tracked. */
  (function (global) {
  "use strict";
  if (!global.EventSource) { (function (global) {
  
    function Map() {
      this.data = {};
    }
  
    Map.prototype = {
      get: function (key) {
        return this.data[key + "~"];
      },
      set: function (key, value) {
        this.data[key + "~"] = value;
      },
      "delete": function (key) {
        delete this.data[key + "~"];
      }
    };
  
    function EventTarget() {
      this.listeners = new Map();
    }
  
    function throwError(e) {
      setTimeout(function () {
        throw e;
      }, 0);
    }
  
    EventTarget.prototype = {
      dispatchEvent: function (event) {
        event.target = this;
        var type = String(event.type);
        var listeners = this.listeners;
        var typeListeners = listeners.get(type);
        if (!typeListeners) {
          return;
        }
        var length = typeListeners.length;
        var i = -1;
        var listener = null;
        while (++i < length) {
          listener = typeListeners[i];
          try {
            listener.call(this, event);
          } catch (e) {
            throwError(e);
          }
        }
      },
      addEventListener: function (type, callback) {
        type = String(type);
        var listeners = this.listeners;
        var typeListeners = listeners.get(type);
        if (!typeListeners) {
          typeListeners = [];
          listeners.set(type, typeListeners);
        }
        var i = typeListeners.length;
        while (--i >= 0) {
          if (typeListeners[i] === callback) {
            return;
          }
        }
        typeListeners.push(callback);
      },
      removeEventListener: function (type, callback) {
        type = String(type);
        var listeners = this.listeners;
        var typeListeners = listeners.get(type);
        if (!typeListeners) {
          return;
        }
        var length = typeListeners.length;
        var filtered = [];
        var i = -1;
        while (++i < length) {
          if (typeListeners[i] !== callback) {
            filtered.push(typeListeners[i]);
          }
        }
        if (filtered.length === 0) {
          listeners["delete"](type);
        } else {
          listeners.set(type, filtered);
        }
      }
    };
  
    function Event(type) {
      this.type = type;
      this.target = null;
    }
  
    function MessageEvent(type, options) {
      Event.call(this, type);
      this.data = options.data;
      this.lastEventId = options.lastEventId;
    }
  
    MessageEvent.prototype = Event.prototype;
  
    var XHR = global.XMLHttpRequest;
    var XDR = global.XDomainRequest;
    var isCORSSupported = Boolean(XHR && ((new XHR()).withCredentials !== undefined));
    var isXHR = isCORSSupported;
    var Transport = isCORSSupported ? XHR : XDR;
    var WAITING = -1;
    var CONNECTING = 0;
    var OPEN = 1;
    var CLOSED = 2;
    var AFTER_CR = 3;
    var FIELD_START = 4;
    var FIELD = 5;
    var VALUE_START = 6;
    var VALUE = 7;
    var contentTypeRegExp = /^text\/event\-stream;?(\s*charset\=utf\-8)?$/i;
  
    var MINIMUM_DURATION = 1000;
    var MAXIMUM_DURATION = 18000000;
  
    function getDuration(value, def) {
      var n = Number(value) || def;
      return (n < MINIMUM_DURATION ? MINIMUM_DURATION : (n > MAXIMUM_DURATION ? MAXIMUM_DURATION : n));
    }
  
    function fire(that, f, event) {
      try {
        if (typeof f === "function") {
          f.call(that, event);
        }
      } catch (e) {
        throwError(e);
      }
    }
  
    function EventSource(url, options) {
      url = String(url);
  
      var withCredentials = Boolean(isCORSSupported && options && options.withCredentials);
      var initialRetry = getDuration(options ? options.retry : NaN, 1000);
      var heartbeatTimeout = getDuration(options ? options.heartbeatTimeout : NaN, 45000);
      var lastEventId = (options && options.lastEventId && String(options.lastEventId)) || "";
      var that = this;
      var retry = initialRetry;
      var wasActivity = false;
      var xhr = new Transport();
      var timeout = 0;
      var timeout0 = 0;
      var charOffset = 0;
      var currentState = WAITING;
      var dataBuffer = [];
      var lastEventIdBuffer = "";
      var eventTypeBuffer = "";
      var onTimeout = null;
  
      var state = FIELD_START;
      var field = "";
      var value = "";
  
      options = null;
  
      function close() {
        currentState = CLOSED;
        if (xhr !== null) {
          xhr.abort();
          xhr = null;
        }
        if (timeout !== 0) {
          clearTimeout(timeout);
          timeout = 0;
        }
        if (timeout0 !== 0) {
          clearTimeout(timeout0);
          timeout0 = 0;
        }
        that.readyState = CLOSED;
      }
  
      function onProgress(isLoadEnd) {
        var responseText = currentState === OPEN || currentState === CONNECTING ? xhr.responseText || "" : "";
        var event = null;
        var isWrongStatusCodeOrContentType = false;
  
        if (currentState === CONNECTING) {
          var status = 0;
          var statusText = "";
          var contentType = "";
          if (isXHR) {
            try {
              status = Number(xhr.status || 0);
              statusText = String(xhr.statusText || "");
              contentType = String(xhr.getResponseHeader("Content-Type") || "");
            } catch (error) {
              // https://bugs.webkit.org/show_bug.cgi?id=29121
              status = 0;
              // FF < 14, WebKit
              // https://bugs.webkit.org/show_bug.cgi?id=29658
              // https://bugs.webkit.org/show_bug.cgi?id=77854
            }
          } else {
            status = 200;
            contentType = xhr.contentType;
          }
          /** modified by Matthias Nehlsen on June 9th, 2014 to remove incompatible ContentType type check. */
          //if (status === 200 && contentTypeRegExp.test(contentType)) {
          if (status === 200) {
            currentState = OPEN;
            wasActivity = true;
            retry = initialRetry;
            that.readyState = OPEN;
            event = new Event("open");
            that.dispatchEvent(event);
            fire(that, that.onopen, event);
            if (currentState === CLOSED) {
              return;
            }
          } else {
            if (status !== 0) {
              var message = "";
              if (status !== 200) {
                message = "EventSource's response has a status " + status + " " + statusText.replace(/\s+/g, " ") + " that is not 200. Aborting the connection.";
              } else {
                message = "EventSource's response has a Content-Type specifying an unsupported type: " + contentType.replace(/\s+/g, " ") + ". Aborting the connection.";
              }
              setTimeout(function () {
                throw new Error(message);
              });
              isWrongStatusCodeOrContentType = true;
            }
          }
        }
  
        if (currentState === OPEN) {
          if (responseText.length > charOffset) {
            wasActivity = true;
          }
          var i = charOffset - 1;
          var length = responseText.length;
          var c = "\n";
          while (++i < length) {
            c = responseText[i];
            if (state === AFTER_CR && c === "\n") {
              state = FIELD_START;
            } else {
              if (state === AFTER_CR) {
                state = FIELD_START;
              }
              if (c === "\r" || c === "\n") {
                if (field === "data") {
                  dataBuffer.push(value);
                } else if (field === "id") {
                  lastEventIdBuffer = value;
                } else if (field === "event") {
                  eventTypeBuffer = value;
                } else if (field === "retry") {
                  initialRetry = getDuration(value, initialRetry);
                  retry = initialRetry;
                } else if (field === "heartbeatTimeout") {//!
                  heartbeatTimeout = getDuration(value, heartbeatTimeout);
                  if (timeout !== 0) {
                    clearTimeout(timeout);
                    timeout = setTimeout(onTimeout, heartbeatTimeout);
                  }
                }
                value = "";
                field = "";
                if (state === FIELD_START) {
                  if (dataBuffer.length !== 0) {
                    lastEventId = lastEventIdBuffer;
                    if (eventTypeBuffer === "") {
                      eventTypeBuffer = "message";
                    }
                    event = new MessageEvent(eventTypeBuffer, {
                      data: dataBuffer.join("\n"),
                      lastEventId: lastEventIdBuffer
                    });
                    that.dispatchEvent(event);
                    if (eventTypeBuffer === "message") {
                      fire(that, that.onmessage, event);
                    }
                    if (currentState === CLOSED) {
                      return;
                    }
                  }
                  dataBuffer.length = 0;
                  eventTypeBuffer = "";
                }
                state = c === "\r" ? AFTER_CR : FIELD_START;
              } else {
                if (state === FIELD_START) {
                  state = FIELD;
                }
                if (state === FIELD) {
                  if (c === ":") {
                    state = VALUE_START;
                  } else {
                    field += c;
                  }
                } else if (state === VALUE_START) {
                  if (c !== " ") {
                    value += c;
                  }
                  state = VALUE;
                } else if (state === VALUE) {
                  value += c;
                }
              }
            }
          }
          charOffset = length;
        }
  
        if ((currentState === OPEN || currentState === CONNECTING) &&
            (isLoadEnd || isWrongStatusCodeOrContentType || (charOffset > 1024 * 1024) || (timeout === 0 && !wasActivity))) {
          currentState = WAITING;
          xhr.abort();
          if (timeout !== 0) {
            clearTimeout(timeout);
            timeout = 0;
          }
          if (retry > initialRetry * 16) {
            retry = initialRetry * 16;
          }
          if (retry > MAXIMUM_DURATION) {
            retry = MAXIMUM_DURATION;
          }
          timeout = setTimeout(onTimeout, retry);
          retry = retry * 2 + 1;
  
          that.readyState = CONNECTING;
          event = new Event("error");
          that.dispatchEvent(event);
          fire(that, that.onerror, event);
        } else {
          if (timeout === 0) {
            wasActivity = false;
            timeout = setTimeout(onTimeout, heartbeatTimeout);
          }
        }
      }
  
      function onProgress2() {
        onProgress(false);
      }
  
      function onLoadEnd() {
        onProgress(true);
      }
  
      if (isXHR) {
        // workaround for Opera issue with "progress" events
        timeout0 = setTimeout(function f() {
          if (xhr.readyState === 3) {
            onProgress2();
          }
          timeout0 = setTimeout(f, 500);
        }, 0);
      }
  
      onTimeout = function () {
        timeout = 0;
        if (currentState !== WAITING) {
          onProgress(false);
          return;
        }
        // loading indicator in Safari, Chrome < 14, Firefox
        // https://bugzilla.mozilla.org/show_bug.cgi?id=736723
        if (isXHR && (xhr.sendAsBinary !== undefined || xhr.onloadend === undefined) && global.document && global.document.readyState && global.document.readyState !== "complete") {
          timeout = setTimeout(onTimeout, 4);
          return;
        }
        // XDomainRequest#abort removes onprogress, onerror, onload
  
        xhr.onload = xhr.onerror = onLoadEnd;
  
        if (isXHR) {
          // improper fix to match Firefox behaviour, but it is better than just ignore abort
          // see https://bugzilla.mozilla.org/show_bug.cgi?id=768596
          // https://bugzilla.mozilla.org/show_bug.cgi?id=880200
          // https://code.google.com/p/chromium/issues/detail?id=153570
          xhr.onabort = onLoadEnd;
  
          // Firefox 3.5 - 3.6 - ? < 9.0
          // onprogress is not fired sometimes or delayed
          xhr.onreadystatechange = onProgress2;
        }
  
        xhr.onprogress = onProgress2;
  
        wasActivity = false;
        timeout = setTimeout(onTimeout, heartbeatTimeout);
  
        charOffset = 0;
        currentState = CONNECTING;
        dataBuffer.length = 0;
        eventTypeBuffer = "";
        lastEventIdBuffer = lastEventId;
        value = "";
        field = "";
        state = FIELD_START;
  
        var s = url.slice(0, 5);
        if (s !== "data:" && s !== "blob:") {
          s = url + ((url.indexOf("?", 0) === -1 ? "?" : "&") + "lastEventId=" + encodeURIComponent(lastEventId) + "&r=" + String(Math.random() + 1).slice(2));
        } else {
          s = url;
        }
        xhr.open("GET", s, true);
  
        if (isXHR) {
          // withCredentials should be set after "open" for Safari and Chrome (< 19 ?)
          xhr.withCredentials = withCredentials;
  
          xhr.responseType = "text";
  
          // Request header field Cache-Control is not allowed by Access-Control-Allow-Headers.
          // "Cache-control: no-cache" are not honored in Chrome and Firefox
          // https://bugzilla.mozilla.org/show_bug.cgi?id=428916
          //xhr.setRequestHeader("Cache-Control", "no-cache");
          xhr.setRequestHeader("Accept", "text/event-stream");
          // Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers.
          //xhr.setRequestHeader("Last-Event-ID", lastEventId);
        }
  
        xhr.send(null);
      };
  
      EventTarget.call(this);
      this.close = close;
      this.url = url;
      this.readyState = CONNECTING;
      this.withCredentials = withCredentials;
  
      this.onopen = null;
      this.onmessage = null;
      this.onerror = null;
  
      onTimeout();
    }
  
    function F() {
      this.CONNECTING = CONNECTING;
      this.OPEN = OPEN;
      this.CLOSED = CLOSED;
    }
    F.prototype = EventTarget.prototype;
  
    EventSource.prototype = new F();
    F.call(EventSource);
  
    if (Transport) {
      // Why replace a native EventSource ?
      // https://bugzilla.mozilla.org/show_bug.cgi?id=444328
      // https://bugzilla.mozilla.org/show_bug.cgi?id=831392
      // https://code.google.com/p/chromium/issues/detail?id=260144
      // https://code.google.com/p/chromium/issues/detail?id=225654
      // ...
  
      /** modified by Matthias Nehlsen on June 9th, 2014 */
      console.log("Using EventSource PolyFill");
      global.EventSource = EventSource;
    }
  }(global))}}(this));
  