<commit_before>var ocelotController, OcelotPromiseFactory, MD5Tools, CTXPATH = "%CTXPATH%";
if ("WebSocket" in window) {
   ocelotController = (function () {
      var MSG = "MESSAGE", RES = "RESULT", FAULT = "FAULT", ALL = "ALL", EVT = "Event", ADD = "add", RM = "remove",
         CLEANCACHE = "ocelot-cleancache", STATUS = "ocelot-status", OSRV = "fr.hhdev.ocelot.OcelotServices", SUB = "subscribe", UNSUB = "unsubscribe",
         stateLabels = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'], promises = {}, openHandlers = [], closeHandlers = [], errorHandlers = [], ws, ocelotSrv;
      ocelotSrv = new OcelotServices();
      function showErrorSocketIsNotReady(msg) {
         alert('WebSocket is not ready : ' + msg + '\nCode : ' + ocelotController.status);
      }
      function createEventFromPromise(type, promise) {
         var evt = document.createEvent(EVT);
         evt.initEvent(type, true, false);
         evt.dataservice = promise.dataservice;
         evt.operation = promise.operation;
         evt.args = promise.args;
         return evt;
      }
      function createMessageEventFromPromise(promise, response) {
         var evt = createEventFromPromise(MSG, promise);
         evt.response = response;
         return evt;
      }
      function createResultEventFromPromise(promise, response) {
         var evt = createEventFromPromise(RES, promise);
         evt.response = response;
         return evt;
      }
      function createFaultEventFromPromise(promise, response) {
         var evt = createEventFromPromise(FAULT, promise);
         evt.response = response;
         return evt;
      }
      function stateUpdated() {
         var response, promise = promises[STATUS];
         if (promise) {
            response = createMessageEventFromPromise(promise, ocelotController.status);
            promise.response = response;
         }
      }
      function isTopicSubscription(promise, topic) {
         if (promise.dataservice === OSRV && promise.operation === SUB) {
            return isTopic(promise, topic);
         }
         return false;
      }
      function isTopicUnsubscription(promise, topic) {
         if (promise.dataservice === OSRV && promise.operation === UNSUB) {
            return isTopic(promise, topic);
         }
         return false;
      }
      function isTopic(promise, topic) {
         return topic ? (promise.args[0] === topic) : true;
      }
      function init() {
         if (document.location.href.toString().indexOf(document.location.protocol + "//" + document.location.hostname + ":" + document.location.port + CTXPATH) === 0) {
            ws = new WebSocket("ws://" + document.location.hostname + ":" + document.location.port + CTXPATH+"/ocelot-endpoint");
         } else {
            ws = new WebSocket("ws://" + document.location.hostname + ":" + document.location.port + "/ocelot-endpoint");
         }
         ws.onmessage = function (evt) {
            var response, msgToClient = JSON.parse(evt.data), promise = promises[msgToClient.id];
            if (!promise) {
               return;
            }
            if (msgToClient.type === FAULT) {
               response = createFaultEventFromPromise(promise, msgToClient.response);
               delete promises[msgToClient.id];
            } else if (msgToClient.type === RES) {
               // if msg is response of subscribe request
               if (isTopicSubscription(promise)) {
                  promises[promise.args[0]] = promise;
               }
               else if (isTopicUnsubscription(promise)) {
                  delete promises[promise.args[0]];
               }
               // if msgToClient has dead line so we stock in cache
               ocelotController.cacheManager.putResultInCache(msgToClient);
               response = createResultEventFromPromise(promise, msgToClient.response);
               delete promises[msgToClient.id];
            } else if (msgToClient.type === MSG) {
               response = createMessageEventFromPromise(promise, msgToClient.response);
            }
            promise.response = response;
         };
         ws.onopen = function (evt) {
            var handler, ps;
            stateUpdated();
            if(Object.keys(promises).length) { // its not open, but re-open, we redo the previous subscription
               ps = promises;
               promises = {};
               Object.keys(ps).forEach(function (id, index, array) {
                  if(id !== ps[id].id) {
                     ocelotController.addPromise(ps[id]);
                  }
               });
               while (handler = openHandlers.shift()) { // launch open handlers
                  handler();
               }
               return;
            }
            // Controller subscribe to ocelot-cleancache topic
            ocelotSrv.subscribe(CLEANCACHE).message(function (id) {
               if (id === ALL) { ocelotController.cacheManager.clearCache(); }
               else { ocelotController.cacheManager.removeEntryInCache(id); }
            });
            // Get Locale from server or cache and re-set it
            ocelotSrv.getLocale().then(function (locale) {
               if (locale) { ocelotSrv.setLocale(locale); }
            });
            // send states or current objects in cache with lastupdate
            ocelotSrv.getOutDatedCache(ocelotController.cacheManager.getLastUpdateCache()).then(function (entries) {
               ocelotController.cacheManager.removeEntries(entries);
            });
            while (handler = openHandlers.shift()) { // launch open handlers
               handler();
            }
         };
         ws.onerror = function (evt) {
            var handler;
            while (handler = errorHandlers.shift()) {
               handler(evt);
            }
            stateUpdated();
         };
         ws.onclose = function (evt) {
            var handler;
            while (handler = closeHandlers.shift()) {
               handler();
            }
            stateUpdated();
         };
      }
      init();
      return {
         get status() {
            return stateLabels[ws.readyState];
         },
         addOpenListener: function (listener) {
            if (ws.readyState === 1) { // OPEN
               listener();
            } else {
               openHandlers.push(listener);
            }
         },
         addCloseListener: function (listener) {
            if (ws.readyState === 3) { // CLOSED
               listener();
            } else {
               closeHandlers.push(listener);
            }
         },
         addErrorListener: function (listener) {
            errorHandlers.push(listener);
         },
         open: function () {
            init();
         },
         close: function () {
            ws.close();
         },
         addPromise: function (promise) {
            if (isTopicSubscription(promise, STATUS)) {
               promises[STATUS] = promise;
               stateUpdated();
               return;
            }
            if (isTopicUnsubscription(promise, STATUS)) {
               delete promises[STATUS];
               return;
            }
            // check entry cache
            var msgToClient = ocelotController.cacheManager.getResultInCache(promise.id, promise.cacheIgnored);
            if (msgToClient) {
               // present and valid, return response without call
               promise.response = createResultEventFromPromise(promise, msgToClient.response);
               return;
            }
            // else call
            if (ws.readyState === 1) {
               promises[promise.id] = promise;
               ws.send(JSON.stringify(promise.json));
            } else {
               promise.response = createMessageEventFromPromise(promise, {"classname":"none", "message":"Websocket is not ready : status "+status, "stacktrace":[]});
            }
         },
         cacheManager: (function () {
            var LU = "ocelot-lastupdate", addHandlers = [], removeHandlers = [], lastUpdateManager;
            lastUpdateManager = {
               addEntry: function (id) {
                  var lastUpdates = this.getLastUpdateCache();
                  lastUpdates[id] = Date.now();
                  localStorage.setItem(LU, JSON.stringify(lastUpdates));
               },
               removeEntry: function (id) {
                  var lastUpdates = this.getLastUpdateCache();
                  delete lastUpdates[id];
                  localStorage.setItem(LU, JSON.stringify(lastUpdates));
               },
               getLastUpdateCache: function () {
                  var lastUpdates = localStorage.getItem(LU);
                  if (!lastUpdates) {
                     lastUpdates = {};
                  } else {
                     lastUpdates = JSON.parse(lastUpdates);
                  }
                  return lastUpdates;
               }
            };
            function manageAddEvent(msgToClient) {
               var evt = document.createEvent(EVT);
               evt.initEvent(ADD, true, false);
               evt.msg = msgToClient;
               addHandlers.forEach(function (handler, index, array) {
                  handler(evt);
               });
            }
            function manageRemoveEvent(compositeKey) {
               var evt = document.createEvent(EVT);
               evt.initEvent(RM, true, false);
               evt.key = compositeKey;
               removeHandlers.forEach(function (handler, index, array) {
                  handler(evt);
               });
            }
            return {
               getLastUpdateCache: function () {
                  return lastUpdateManager.getLastUpdateCache();
               },
               /**
                * Add listener for receive cache event
                * @param {String} type event : add, remove
                * @param {Function} listener
                */
               addEventListener: function (type, listener) {
                  if (type === ADD) {
                     addHandlers.push(listener);
                  } else if (type === RM) {
                     removeHandlers.push(listener);
                  }
               },
               /**
                * Add result in cache storage
                * @param {MessageToClient} msgToClient
                */
               putResultInCache: function (msgToClient) {
                  var ids, json, obj;
                  lastUpdateManager.addEntry(msgToClient.id);
                  manageAddEvent(msgToClient);
                  ids = msgToClient.id.split("_");
                  json = localStorage.getItem(ids[0]);
                  obj = {};
                  if (json) { obj = JSON.parse(json); }
                  obj[ids[1]] = msgToClient;
                  json = JSON.stringify(obj);
                  localStorage.setItem(ids[0], json);
               },
               /**
                * get entry from cache
                * @param {String} compositeKey
                * @param {boolean} ignoreCache
                * @returns {MessageToClient}
                */
               getResultInCache: function (compositeKey, ignoreCache) {
                  var ids, json, msgToClient, obj, now;
                  if (ignoreCache) { return null; }
                  ids = compositeKey.split("_");
                  msgToClient = null;
                  json = localStorage.getItem(ids[0]);
                  if (json) {
                     obj = JSON.parse(json);
                     msgToClient = obj[ids[1]];
                  }
                  if (msgToClient) {
                     now = new Date().getTime();
                     // check validity
                     if (now > msgToClient.deadline) {
                        this.removeEntryInCache(compositeKey);
                        msgToClient = null; // invalid
                     }
                  }
                  return msgToClient;
               },
               /**
                * Remove sub entry or entry in cache
                * @param {String} compositeKey
                */
               removeEntryInCache: function (compositeKey) {
                  var ids, entry, obj;
                  lastUpdateManager.removeEntry(compositeKey);
                  manageRemoveEvent(compositeKey);
                  ids = compositeKey.split("_");
                  entry = localStorage.getItem(ids[0]);
                  if (entry) {
                     obj = JSON.parse(entry);
                     if (ids.length === 2) {
                        delete obj[ids[1]];
                        localStorage.setItem(ids[0], JSON.stringify(obj));
                     } else {
                        localStorage.removeItem(ids[0]);
                     }
                  }
               },
               /**
                * Remove all entries defined in list
                * @param {array} list
                */
               removeEntries: function (list) {
                  list.forEach(function (key, index, array) {
                     removeEntryInCache(key);
                  });
               },
               /**
                * Clear cache storage
                */
               clearCache: function () {
                  localStorage.clear();
               }
            };
         })()
      };
   })();

   OcelotPromiseFactory = function () {
      var MSG = "MESSAGE", RES = "RESULT", FAULT = "FAULT";
      return {
         createPromise: function (ds, id, op, argNames, args) {
            return (function (ds, id, op, argNames, args) {
               var handler, evt = null, thenHandlers = [], catchHandlers = [], eventHandlers = [], messageHandlers = [];
               function process(e) {
                  if (!e) { return; }
                  if (e.type !== MSG) {
                     while (handler = eventHandlers.shift()) {
                        handler(e);
                     }
                     if (e.type === RES) {
                        while (handler = thenHandlers.shift()) {
                           handler(e.response);
                        }
                     } else if (e.type === FAULT) {
                        while (handler = catchHandlers.shift()) {
                           handler(e.response);
                        }
                     }
                  } else {
                     messageHandlers.forEach(function (messageHandler, index, array) {
                        messageHandler(e.response);
                     });
                  }
               }
               var promise = {
                  id: id, dataservice: ds, operation: op, args: args, argNames: argNames, cacheIgnored: false,
                  set response(e) {
                     evt = e;
                     process(e);
                  },
                  ignoreCache: function (ignore) {
                     this.cacheIgnored = ignore;
                     return this;
                  },
                  then: function (onFulfilled, onRejected) {
                     if (onFulfilled) { thenHandlers.push(onFulfilled); }
                     if (onRejected) { catchHandlers.push(onRejected); }
                     if (evt) { process(evt); }
                     return this;
                  },
                  catch : function (onRejected) {
                     if (onRejected) { catchHandlers.push(onRejected); }
                     if (evt) { process(evt); }
                     return this;
                  },
                  event: function (onEvented) {
                     if (onEvented) { eventHandlers.push(onEvented); }
                     if (evt) { process(evt); }
                     return this;
                  },
                  message: function (onMessaged) {
                     if (onMessaged) { messageHandlers.push(onMessaged); }
                     if (evt) { process(evt); }
                     return this;
                  },
                  get json() {
                     return {"id": this.id, "ds": this.dataservice, "op": this.operation, "argNames": this.argNames, "args": this.args};
                  }
               };
               var e = document.createEvent("Event");
               e.initEvent("call", true, false);
               e.promise = promise;
               setTimeout(function () {
                  document.dispatchEvent(e);
               }, 1);
               return promise;
            })(ds, id, op, argNames, args);
         }
      };
   }();<commit_msg>allow port 80, cause document.location.port == "" in this case<commit_after>var ocelotController, OcelotPromiseFactory, MD5Tools, CTXPATH = "%CTXPATH%";
if ("WebSocket" in window) {
   ocelotController = (function () {
      var MSG = "MESSAGE", RES = "RESULT", FAULT = "FAULT", ALL = "ALL", EVT = "Event", ADD = "add", RM = "remove",
         CLEANCACHE = "ocelot-cleancache", STATUS = "ocelot-status", OSRV = "fr.hhdev.ocelot.OcelotServices", SUB = "subscribe", UNSUB = "unsubscribe",
         stateLabels = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'], promises = {}, openHandlers = [], closeHandlers = [], errorHandlers = [], ws, ocelotSrv;
      ocelotSrv = new OcelotServices();
      function showErrorSocketIsNotReady(msg) {
         alert('WebSocket is not ready : ' + msg + '\nCode : ' + ocelotController.status);
      }
      function createEventFromPromise(type, promise) {
         var evt = document.createEvent(EVT);
         evt.initEvent(type, true, false);
         evt.dataservice = promise.dataservice;
         evt.operation = promise.operation;
         evt.args = promise.args;
         return evt;
      }
      function createMessageEventFromPromise(promise, response) {
         var evt = createEventFromPromise(MSG, promise);
         evt.response = response;
         return evt;
      }
      function createResultEventFromPromise(promise, response) {
         var evt = createEventFromPromise(RES, promise);
         evt.response = response;
         return evt;
      }
      function createFaultEventFromPromise(promise, response) {
         var evt = createEventFromPromise(FAULT, promise);
         evt.response = response;
         return evt;
      }
      function stateUpdated() {
         var response, promise = promises[STATUS];
         if (promise) {
            response = createMessageEventFromPromise(promise, ocelotController.status);
            promise.response = response;
         }
      }
      function isTopicSubscription(promise, topic) {
         if (promise.dataservice === OSRV && promise.operation === SUB) {
            return isTopic(promise, topic);
         }
         return false;
      }
      function isTopicUnsubscription(promise, topic) {
         if (promise.dataservice === OSRV && promise.operation === UNSUB) {
            return isTopic(promise, topic);
         }
         return false;
      }
      function isTopic(promise, topic) {
         return topic ? (promise.args[0] === topic) : true;
      }
      function init() {
         var host = document.location.hostname;
         if (document.location.port && document.location.port !== "") {
            host = host + ":" + document.location.port;
         }
         if (document.location.href.toString().indexOf(document.location.protocol + "//" + host + CTXPATH) === 0) {
            ws = new WebSocket("ws://" + host + CTXPATH + "/ocelot-endpoint");
         } else {
            ws = new WebSocket("ws://" + host + "/ocelot-endpoint");
         }
         ws.onmessage = function (evt) {
            var response, msgToClient = JSON.parse(evt.data), promise = promises[msgToClient.id];
            if (!promise) {
               return;
            }
            if (msgToClient.type === FAULT) {
               response = createFaultEventFromPromise(promise, msgToClient.response);
               delete promises[msgToClient.id];
            } else if (msgToClient.type === RES) {
               // if msg is response of subscribe request
               if (isTopicSubscription(promise)) {
                  promises[promise.args[0]] = promise;
               }
               else if (isTopicUnsubscription(promise)) {
                  delete promises[promise.args[0]];
               }
               // if msgToClient has dead line so we stock in cache
               ocelotController.cacheManager.putResultInCache(msgToClient);
               response = createResultEventFromPromise(promise, msgToClient.response);
               delete promises[msgToClient.id];
            } else if (msgToClient.type === MSG) {
               response = createMessageEventFromPromise(promise, msgToClient.response);
            }
            promise.response = response;
         };
         ws.onopen = function (evt) {
            var handler, ps;
            stateUpdated();
            if (Object.keys(promises).length) { // its not open, but re-open, we redo the previous subscription
               ps = promises;
               promises = {};
               Object.keys(ps).forEach(function (id, index, array) {
                  if (id !== ps[id].id) {
                     ocelotController.addPromise(ps[id]);
                  }
               });
               while (handler = openHandlers.shift()) { // launch open handlers
                  handler();
               }
               return;
            }
            // Controller subscribe to ocelot-cleancache topic
            ocelotSrv.subscribe(CLEANCACHE).message(function (id) {
               if (id === ALL) {
                  ocelotController.cacheManager.clearCache();
               }
               else {
                  ocelotController.cacheManager.removeEntryInCache(id);
               }
            });
            // Get Locale from server or cache and re-set it
            ocelotSrv.getLocale().then(function (locale) {
               if (locale) {
                  ocelotSrv.setLocale(locale);
               }
            });
            // send states or current objects in cache with lastupdate
            ocelotSrv.getOutDatedCache(ocelotController.cacheManager.getLastUpdateCache()).then(function (entries) {
               ocelotController.cacheManager.removeEntries(entries);
            });
            while (handler = openHandlers.shift()) { // launch open handlers
               handler();
            }
         };
         ws.onerror = function (evt) {
            var handler;
            while (handler = errorHandlers.shift()) {
               handler(evt);
            }
            stateUpdated();
         };
         ws.onclose = function (evt) {
            var handler;
            while (handler = closeHandlers.shift()) {
               handler();
            }
            stateUpdated();
         };
      }
      init();
      return {
         get status() {
            return stateLabels[ws.readyState];
         },
         addOpenListener: function (listener) {
            if (ws.readyState === 1) { // OPEN
               listener();
            } else {
               openHandlers.push(listener);
            }
         },
         addCloseListener: function (listener) {
            if (ws.readyState === 3) { // CLOSED
               listener();
            } else {
               closeHandlers.push(listener);
            }
         },
         addErrorListener: function (listener) {
            errorHandlers.push(listener);
         },
         open: function () {
            init();
         },
         close: function () {
            ws.close();
         },
         addPromise: function (promise) {
            if (isTopicSubscription(promise, STATUS)) {
               promises[STATUS] = promise;
               stateUpdated();
               return;
            }
            if (isTopicUnsubscription(promise, STATUS)) {
               delete promises[STATUS];
               return;
            }
            // check entry cache
            var msgToClient = ocelotController.cacheManager.getResultInCache(promise.id, promise.cacheIgnored);
            if (msgToClient) {
               // present and valid, return response without call
               promise.response = createResultEventFromPromise(promise, msgToClient.response);
               return;
            }
            // else call
            if (ws.readyState === 1) {
               promises[promise.id] = promise;
               ws.send(JSON.stringify(promise.json));
            } else {
               promise.response = createMessageEventFromPromise(promise, {"classname": "none", "message": "Websocket is not ready : status " + status, "stacktrace": []});
            }
         },
         cacheManager: (function () {
            var LU = "ocelot-lastupdate", addHandlers = [], removeHandlers = [], lastUpdateManager;
            lastUpdateManager = {
               addEntry: function (id) {
                  var lastUpdates = this.getLastUpdateCache();
                  lastUpdates[id] = Date.now();
                  localStorage.setItem(LU, JSON.stringify(lastUpdates));
               },
               removeEntry: function (id) {
                  var lastUpdates = this.getLastUpdateCache();
                  delete lastUpdates[id];
                  localStorage.setItem(LU, JSON.stringify(lastUpdates));
               },
               getLastUpdateCache: function () {
                  var lastUpdates = localStorage.getItem(LU);
                  if (!lastUpdates) {
                     lastUpdates = {};
                  } else {
                     lastUpdates = JSON.parse(lastUpdates);
                  }
                  return lastUpdates;
               }
            };
            function manageAddEvent(msgToClient) {
               var evt = document.createEvent(EVT);
               evt.initEvent(ADD, true, false);
               evt.msg = msgToClient;
               addHandlers.forEach(function (handler, index, array) {
                  handler(evt);
               });
            }
            function manageRemoveEvent(compositeKey) {
               var evt = document.createEvent(EVT);
               evt.initEvent(RM, true, false);
               evt.key = compositeKey;
               removeHandlers.forEach(function (handler, index, array) {
                  handler(evt);
               });
            }
            return {
               getLastUpdateCache: function () {
                  return lastUpdateManager.getLastUpdateCache();
               },
               /**
                * Add listener for receive cache event
                * @param {String} type event : add, remove
                * @param {Function} listener
                */
               addEventListener: function (type, listener) {
                  if (type === ADD) {
                     addHandlers.push(listener);
                  } else if (type === RM) {
                     removeHandlers.push(listener);
                  }
               },
               /**
                * Add result in cache storage
                * @param {MessageToClient} msgToClient
                */
               putResultInCache: function (msgToClient) {
                  var ids, json, obj;
                  lastUpdateManager.addEntry(msgToClient.id);
                  manageAddEvent(msgToClient);
                  ids = msgToClient.id.split("_");
                  json = localStorage.getItem(ids[0]);
                  obj = {};
                  if (json) {
                     obj = JSON.parse(json);
                  }
                  obj[ids[1]] = msgToClient;
                  json = JSON.stringify(obj);
                  localStorage.setItem(ids[0], json);
               },
               /**
                * get entry from cache
                * @param {String} compositeKey
                * @param {boolean} ignoreCache
                * @returns {MessageToClient}
                */
               getResultInCache: function (compositeKey, ignoreCache) {
                  var ids, json, msgToClient, obj, now;
                  if (ignoreCache) {
                     return null;
                  }
                  ids = compositeKey.split("_");
                  msgToClient = null;
                  json = localStorage.getItem(ids[0]);
                  if (json) {
                     obj = JSON.parse(json);
                     msgToClient = obj[ids[1]];
                  }
                  if (msgToClient) {
                     now = new Date().getTime();
                     // check validity
                     if (now > msgToClient.deadline) {
                        this.removeEntryInCache(compositeKey);
                        msgToClient = null; // invalid
                     }
                  }
                  return msgToClient;
               },
               /**
                * Remove sub entry or entry in cache
                * @param {String} compositeKey
                */
               removeEntryInCache: function (compositeKey) {
                  var ids, entry, obj;
                  lastUpdateManager.removeEntry(compositeKey);
                  manageRemoveEvent(compositeKey);
                  ids = compositeKey.split("_");
                  entry = localStorage.getItem(ids[0]);
                  if (entry) {
                     obj = JSON.parse(entry);
                     if (ids.length === 2) {
                        delete obj[ids[1]];
                        localStorage.setItem(ids[0], JSON.stringify(obj));
                     } else {
                        localStorage.removeItem(ids[0]);
                     }
                  }
               },
               /**
                * Remove all entries defined in list
                * @param {array} list
                */
               removeEntries: function (list) {
                  list.forEach(function (key, index, array) {
                     removeEntryInCache(key);
                  });
               },
               /**
                * Clear cache storage
                */
               clearCache: function () {
                  localStorage.clear();
               }
            };
         })()
      };
   })();

   OcelotPromiseFactory = function () {
      var MSG = "MESSAGE", RES = "RESULT", FAULT = "FAULT";
      return {
         createPromise: function (ds, id, op, argNames, args) {
            return (function (ds, id, op, argNames, args) {
               var handler, evt = null, thenHandlers = [], catchHandlers = [], eventHandlers = [], messageHandlers = [];
               function process(e) {
                  if (!e) {
                     return;
                  }
                  if (e.type !== MSG) {
                     while (handler = eventHandlers.shift()) {
                        handler(e);
                     }
                     if (e.type === RES) {
                        while (handler = thenHandlers.shift()) {
                           handler(e.response);
                        }
                     } else if (e.type === FAULT) {
                        while (handler = catchHandlers.shift()) {
                           handler(e.response);
                        }
                     }
                  } else {
                     messageHandlers.forEach(function (messageHandler, index, array) {
                        messageHandler(e.response);
                     });
                  }
               }
               var promise = {
                  id: id, dataservice: ds, operation: op, args: args, argNames: argNames, cacheIgnored: false,
                  set response(e) {
                     evt = e;
                     process(e);
                  },
                  ignoreCache: function (ignore) {
                     this.cacheIgnored = ignore;
                     return this;
                  },
                  then: function (onFulfilled, onRejected) {
                     if (onFulfilled) {
                        thenHandlers.push(onFulfilled);
                     }
                     if (onRejected) {
                        catchHandlers.push(onRejected);
                     }
                     if (evt) {
                        process(evt);
                     }
                     return this;
                  },
                  catch : function (onRejected) {
                     if (onRejected) {
                        catchHandlers.push(onRejected);
                     }
                     if (evt) {
                        process(evt);
                     }
                     return this;
                  },
                  event: function (onEvented) {
                     if (onEvented) {
                        eventHandlers.push(onEvented);
                     }
                     if (evt) {
                        process(evt);
                     }
                     return this;
                  },
                  message: function (onMessaged) {
                     if (onMessaged) {
                        messageHandlers.push(onMessaged);
                     }
                     if (evt) {
                        process(evt);
                     }
                     return this;
                  },
                  get json() {
                     return {"id": this.id, "ds": this.dataservice, "op": this.operation, "argNames": this.argNames, "args": this.args};
                  }
               };
               var e = document.createEvent("Event");
               e.initEvent("call", true, false);
               e.promise = promise;
               setTimeout(function () {
                  document.dispatchEvent(e);
               }, 1);
               return promise;
            })(ds, id, op, argNames, args);
         }
      };
   }();
{'fraction_non_alphanumeric': 0.10432577477663432, 'fraction_numerical': 0.0011794886916521687, 'mean_word_length': 1.2465553789083201, 'pattern_counts': {'":': 20, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6192215', 'n_tokens_mistral': 8351, 'n_tokens_neox': 8073, 'n_words': 1730}