From 4822f6ec0298d37a48ce7d7afc7e4f12dcc90b32 Mon Sep 17 00:00:00 2001
From: Patrick Jentsch <p.jentsch@uni-bielefeld.de>
Date: Fri, 10 Nov 2023 10:27:39 +0100
Subject: [PATCH] integrate js cqi into corpus_analysis package

---
 .../js/CorpusAnalysis/CorpusAnalysisApp.js    |   2 +-
 app/static/js/CorpusAnalysis/Utils.js         |  53 -----
 .../js/{ => CorpusAnalysis}/cqi/api/client.js |  48 ++---
 app/static/js/CorpusAnalysis/cqi/api/index.js |   1 +
 .../js/{ => CorpusAnalysis}/cqi/client.js     |  18 +-
 app/static/js/CorpusAnalysis/cqi/constants.js |  43 ++++
 app/static/js/CorpusAnalysis/cqi/errors.js    | 185 ++++++++++++++++++
 app/static/js/CorpusAnalysis/cqi/index.js     |   1 +
 .../cqi/models/attributes.js                  |  52 ++---
 .../cqi/models/corpora.js                     |  38 ++--
 .../js/CorpusAnalysis/cqi/models/index.js     |   1 +
 .../cqi/models/resource.js                    |  22 +--
 .../cqi/models/subcorpora.js                  |  46 ++---
 app/static/js/CorpusAnalysis/cqi/status.js    |  51 +++++
 app/static/js/CorpusAnalysis/index.js         |   1 +
 app/static/js/cqi/api/index.js                |   1 -
 app/static/js/cqi/constants.js                |  43 ----
 app/static/js/cqi/errors.js                   | 185 ------------------
 app/static/js/cqi/index.js                    |   1 -
 app/static/js/cqi/models/index.js             |   1 -
 app/static/js/cqi/status.js                   |  51 -----
 app/static/js/forms/index.js                  |   2 +-
 app/static/js/resource-displays/index.js      |   2 +-
 app/static/js/resource-lists/index.js         |   2 +-
 app/templates/_scripts.html.j2                |  34 ++--
 25 files changed, 413 insertions(+), 471 deletions(-)
 delete mode 100644 app/static/js/CorpusAnalysis/Utils.js
 rename app/static/js/{ => CorpusAnalysis}/cqi/api/client.js (91%)
 create mode 100644 app/static/js/CorpusAnalysis/cqi/api/index.js
 rename app/static/js/{ => CorpusAnalysis}/cqi/client.js (54%)
 create mode 100644 app/static/js/CorpusAnalysis/cqi/constants.js
 create mode 100644 app/static/js/CorpusAnalysis/cqi/errors.js
 create mode 100644 app/static/js/CorpusAnalysis/cqi/index.js
 rename app/static/js/{ => CorpusAnalysis}/cqi/models/attributes.js (67%)
 rename app/static/js/{ => CorpusAnalysis}/cqi/models/corpora.js (66%)
 create mode 100644 app/static/js/CorpusAnalysis/cqi/models/index.js
 rename app/static/js/{ => CorpusAnalysis}/cqi/models/resource.js (66%)
 rename app/static/js/{ => CorpusAnalysis}/cqi/models/subcorpora.js (63%)
 create mode 100644 app/static/js/CorpusAnalysis/cqi/status.js
 create mode 100644 app/static/js/CorpusAnalysis/index.js
 delete mode 100644 app/static/js/cqi/api/index.js
 delete mode 100644 app/static/js/cqi/constants.js
 delete mode 100644 app/static/js/cqi/errors.js
 delete mode 100644 app/static/js/cqi/index.js
 delete mode 100644 app/static/js/cqi/models/index.js
 delete mode 100644 app/static/js/cqi/status.js

diff --git a/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js b/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js
index 2bdfac58..f364d816 100644
--- a/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js
+++ b/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js
@@ -30,7 +30,7 @@ class CorpusAnalysisApp {
       // Setup CQi over SocketIO connection and gather data from the CQPServer
       const statusTextElement = this.elements.initModal.querySelector('.status-text');
       statusTextElement.innerText = 'Creating CQi over SocketIO client...';
-      const cqiClient = new cqi.Client('/cqi_over_sio');
+      const cqiClient = new nopaque.corpus_analysis.cqi.Client('/cqi_over_sio');
       statusTextElement.innerText += ' Done';
       statusTextElement.innerHTML = 'Waiting for the CQP server...';
       const response = await cqiClient.api.socket.emitWithAck('init', this.corpusId);
diff --git a/app/static/js/CorpusAnalysis/Utils.js b/app/static/js/CorpusAnalysis/Utils.js
deleted file mode 100644
index 1ffe1dc0..00000000
--- a/app/static/js/CorpusAnalysis/Utils.js
+++ /dev/null
@@ -1,53 +0,0 @@
-  /**
-   * @param {cqi.models.corpora.Corpus} corpus
-   * @param {number[]} cposList
-   * @returns {Promise<object>}
-   */
-async function lookupsByCpos(corpus, cposList) {
-  let lookups = {};
-  lookups['cpos_lookup'] = {};
-  for (let cpos in cposList) {
-    lookups['cpos_lookup'][cpos] = {};
-  }
-
-  let pAttrs = await corpus.positionalAttributes.list();
-  for (let attr in pAttrs) {
-    let values = await attr.valuesByCpos(cposList);
-    for (let i = 0; i < cposList.length; i++) {
-      let cpos = cposList[i];
-      let value = values[i];
-      lookups['cpos_lookup'][cpos][attr.name] = value;
-    }
-  }
-
-  let sAttrs = await corpus.structuralAttributes.list();
-  for (let attr in sAttrs) {
-    // We only want to iterate over non subattributes, identifiable by
-    // sAttr.hasValues == false
-    if (attr.hasValues) {continue;}
-
-    let idList = await attr.idsByCpos(cposList);
-    for (let i = 0; i < cposList.length; i++) {
-      let cpos = cposList[i];
-      let id = idList[i];
-      if (id == -1) {continue;}
-      lookups['cpos_lookup'][cpos][attr.name] = id;
-    }
-
-    let occuredIdList = Array.from(new Set(idList.filter(x => x != -1)));
-    if (occuredIdList.length == 0) {continue;}
-  
-    let subattrs = sAttrs.filter(x => x.name.startsWith(`${attr.name}_`));
-    if (subattrs.length == 0) {continue;}
-
-    let lookupName = `${attr.name}_lookup`;
-    lookups[lookupName] = {};
-    for (let id in occuredIdList) {
-      lookups[lookupName][id] = {};
-    }
-    
-    
-  }
-
-  return lookups;
-}
diff --git a/app/static/js/cqi/api/client.js b/app/static/js/CorpusAnalysis/cqi/api/client.js
similarity index 91%
rename from app/static/js/cqi/api/client.js
rename to app/static/js/CorpusAnalysis/cqi/api/client.js
index 64495873..4603a1f3 100644
--- a/app/static/js/cqi/api/client.js
+++ b/app/static/js/CorpusAnalysis/cqi/api/client.js
@@ -1,4 +1,4 @@
-cqi.api.Client = class Client {
+nopaque.corpus_analysis.cqi.api.Client = class Client {
   /**
    * @param {string} host
    * @param {number} [timeout=60] timeout
@@ -30,10 +30,10 @@ cqi.api.Client = class Client {
     } else if (response.code === 500) {
       throw new Error(`[${response.code}] ${response.msg}`);
     } else if (response.code === 502) {
-      if (response.payload.code in cqi.errors.lookup) {
-        throw new cqi.errors.lookup[response.payload.code]();
+      if (response.payload.code in nopaque.corpus_analysis.cqi.errors.lookup) {
+        throw new nopaque.corpus_analysis.cqi.errors.lookup[response.payload.code]();
       } else {
-        throw new cqi.errors.CQiError();
+        throw new nopaque.corpus_analysis.cqi.errors.CQiError();
       }
     }
   }
@@ -41,22 +41,22 @@ cqi.api.Client = class Client {
   /**
    * @param {string} username
    * @param {string} password
-   * @returns {Promise<cqi.status.StatusConnectOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusConnectOk>}
    */
   async ctrl_connect(username, password) {
     const fn_name = 'ctrl_connect';
     const fn_args = {username: username, password: password};
     let payload = await this.#request(fn_name, fn_args);
-    return new cqi.status.lookup[payload.code]();
+    return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
   }
 
   /**
-   * @returns {Promise<cqi.status.StatusByeOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusByeOk>}
    */
   async ctrl_bye() {
     const fn_name = 'ctrl_bye';
     let payload = await this.#request(fn_name);
-    return new cqi.status.lookup[payload.code]();
+    return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
   }
 
   /**
@@ -68,12 +68,12 @@ cqi.api.Client = class Client {
   }
 
   /**
-   * @returns {Promise<cqi.status.StatusPingOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusPingOk>}
    */
   async ctrl_ping() {
     const fn_name = 'ctrl_ping';
     let payload = await this.#request(fn_name);
-    return new cqi.status.lookup[payload.code]();
+    return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
   }
 
   /**
@@ -208,13 +208,13 @@ cqi.api.Client = class Client {
    * try to unload a corpus and all its attributes from memory
    * 
    * @param {string} corpus
-   * @returns {Promise<cqi.status.StatusOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
    */
   async corpus_drop_corpus(corpus) {
     const fn_name = 'corpus_drop_corpus';
     const fn_args = {corpus: corpus};
     let payload = await this.#request(fn_name, fn_args);
-    return new cqi.status.lookup[payload.code]();
+    return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
   }
 
   /**
@@ -250,13 +250,13 @@ cqi.api.Client = class Client {
    * unload attribute from memory
    * 
    * @param {string} attribute
-   * @returns {Promise<cqi.status.StatusOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
    */
   async cl_drop_attribute(attribute) {
     const fn_name = 'cl_drop_attribute';
     const fn_args = {attribute: attribute};
     let payload = await this.#request(fn_name, fn_args);
-    return new cqi.status.lookup[payload.code]();
+    return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
   }
 
   /**
@@ -482,13 +482,13 @@ cqi.api.Client = class Client {
    * @param {string} mother_corpus
    * @param {string} subcorpus_name
    * @param {string} query
-   * @returns {Promise<cqi.status.StatusOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
    */
   async cqp_query(mother_corpus, subcorpus_name, query) {
     const fn_name = 'cqp_query';
     const fn_args = {mother_corpus: mother_corpus, subcorpus_name: subcorpus_name, query: query};
     let payload = await this.#request(fn_name, fn_args);
-    return new cqi.status.lookup[payload.code]();
+    return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
   }
 
   /**
@@ -524,7 +524,7 @@ cqi.api.Client = class Client {
 
   /**
    * Dump the values of <field> for match ranges <first> .. <last>
-   * in <subcorpus>. <field> is one of the cqi.constants.FIELD_* constants.
+   * in <subcorpus>. <field> is one of the nopaque.corpus_analysis.cqi.constants.FIELD_* constants.
    * 
    * @param {string} subcorpus
    * @param {number} field
@@ -542,13 +542,13 @@ cqi.api.Client = class Client {
    * delete a subcorpus from memory
    * 
    * @param {string} subcorpus
-   * @returns {Promise<cqi.status.StatusOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
    */
   async cqp_drop_subcorpus(subcorpus) {
     const fn_name = 'cqp_drop_subcorpus';
     const fn_args = {subcorpus: subcorpus};
     let payload = await this.#request(fn_name, fn_args);
-    return new cqi.status.lookup[payload.code]();
+    return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
   }
 
   /**
@@ -561,9 +561,9 @@ cqi.api.Client = class Client {
    *
    * returns <n> (id, frequency) pairs flattened into a list of size 2*<n>
    * field is one of
-   * - cqi.constants.FIELD_MATCH
-   * - cqi.constants.FIELD_TARGET
-   * - cqi.constants.FIELD_KEYWORD
+   * - nopaque.corpus_analysis.cqi.constants.FIELD_MATCH
+   * - nopaque.corpus_analysis.cqi.constants.FIELD_TARGET
+   * - nopaque.corpus_analysis.cqi.constants.FIELD_KEYWORD
    *
    * NB: pairs are sorted by frequency desc.
    * 
@@ -610,13 +610,13 @@ cqi.api.Client = class Client {
 
   /**
    * @param {string} corpus
-   * @returns {Promise<cqi.status.StatusOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
    */
   async ext_corpus_update_db(corpus) {
     const fn_name = 'ext_corpus_update_db';
     const fn_args = {corpus: corpus};
     let payload = await this.#request(fn_name, fn_args);
-    return new cqi.status.lookup[payload.code]();
+    return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
   }
 
   /**
diff --git a/app/static/js/CorpusAnalysis/cqi/api/index.js b/app/static/js/CorpusAnalysis/cqi/api/index.js
new file mode 100644
index 00000000..98093ade
--- /dev/null
+++ b/app/static/js/CorpusAnalysis/cqi/api/index.js
@@ -0,0 +1 @@
+nopaque.corpus_analysis.cqi.api = {};
diff --git a/app/static/js/cqi/client.js b/app/static/js/CorpusAnalysis/cqi/client.js
similarity index 54%
rename from app/static/js/cqi/client.js
rename to app/static/js/CorpusAnalysis/cqi/client.js
index dab97828..2b983e7b 100644
--- a/app/static/js/cqi/client.js
+++ b/app/static/js/CorpusAnalysis/cqi/client.js
@@ -1,23 +1,23 @@
-cqi.Client = class Client {
+nopaque.corpus_analysis.cqi.Client = class Client {
   /**
    * @param {string} host
    * @param {number} [timeout=60] timeout
    * @param {string} [version=0.1] version
    */
   constructor(host, timeout = 60, version = '0.1') {
-     /** @type {cqi.api.Client} */
-    this.api = new cqi.api.Client(host, timeout, version);
+     /** @type {nopaque.corpus_analysis.cqi.api.Client} */
+    this.api = new nopaque.corpus_analysis.cqi.api.Client(host, timeout, version);
   }
 
   /**
-   * @returns {cqi.models.corpora.CorpusCollection}
+   * @returns {nopaque.corpus_analysis.cqi.models.corpora.CorpusCollection}
    */
   get corpora() {
-    return new cqi.models.corpora.CorpusCollection(this);
+    return new nopaque.corpus_analysis.cqi.models.corpora.CorpusCollection(this);
   }
 
   /**
-   * @returns {Promise<cqi.status.StatusByeOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusByeOk>}
    */
   async bye() {
     return await this.api.ctrl_bye();
@@ -26,14 +26,14 @@ cqi.Client = class Client {
   /**
    * @param {string} username
    * @param {string} password
-   * @returns {Promise<cqi.status.StatusConnectOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusConnectOk>}
    */
   async connect(username, password) {
     return await this.api.ctrl_connect(username, password);
   }
 
   /**
-   * @returns {Promise<cqi.status.StatusPingOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusPingOk>}
    */
   async ping() {
     return await this.api.ctrl_ping();
@@ -49,7 +49,7 @@ cqi.Client = class Client {
   /**
    * Alias for "bye" method
    * 
-   * @returns {Promise<cqi.status.StatusByeOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusByeOk>}
    */
   async disconnect() {
     return await this.api.ctrl_bye();
diff --git a/app/static/js/CorpusAnalysis/cqi/constants.js b/app/static/js/CorpusAnalysis/cqi/constants.js
new file mode 100644
index 00000000..e45f761b
--- /dev/null
+++ b/app/static/js/CorpusAnalysis/cqi/constants.js
@@ -0,0 +1,43 @@
+nopaque.corpus_analysis.cqi.constants = {};
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_KEYWORD = 9;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_MATCH = 16;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_MATCHEND = 17;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET = 0;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_0 = 0;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_1 = 1;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_2 = 2;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_3 = 3;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_4 = 4;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_5 = 5;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_6 = 6;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_7 = 7;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_8 = 8;
+
+/** @type {number} */
+nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_9 = 9;
diff --git a/app/static/js/CorpusAnalysis/cqi/errors.js b/app/static/js/CorpusAnalysis/cqi/errors.js
new file mode 100644
index 00000000..216294ce
--- /dev/null
+++ b/app/static/js/CorpusAnalysis/cqi/errors.js
@@ -0,0 +1,185 @@
+nopaque.corpus_analysis.cqi.errors = {};
+
+
+/**
+ * A base class from which all other errors inherit.
+ * If you want to catch all errors that the CQi package might throw,
+ * catch this base error.
+ */
+nopaque.corpus_analysis.cqi.errors.CQiError = class CQiError extends Error {
+  constructor(message) {
+    super(message);
+    this.code = undefined;
+    this.description = undefined;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.Error = class Error extends nopaque.corpus_analysis.cqi.errors.CQiError {
+  constructor(message) {
+    super(message);
+    this.code = 2;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.ErrorGeneralError = class ErrorGeneralError extends nopaque.corpus_analysis.cqi.errors.Error {
+  constructor(message) {
+    super(message);
+    this.code = 513;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.ErrorConnectRefused = class ErrorConnectRefused extends nopaque.corpus_analysis.cqi.errors.Error {
+  constructor(message) {
+    super(message);
+    this.code = 514;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.ErrorUserAbort = class ErrorUserAbort extends nopaque.corpus_analysis.cqi.errors.Error {
+  constructor(message) {
+    super(message);
+    this.code = 515;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.ErrorSyntaxError = class ErrorSyntaxError extends nopaque.corpus_analysis.cqi.errors.Error {
+  constructor(message) {
+    super(message);
+    this.code = 516;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CLError = class Error extends nopaque.corpus_analysis.cqi.errors.CQiError {
+  constructor(message) {
+    super(message);
+    this.code = 4;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CLErrorNoSuchAttribute = class CLErrorNoSuchAttribute extends nopaque.corpus_analysis.cqi.errors.CLError {
+  constructor(message) {
+    super(message);
+    this.code = 1025;
+    this.description = "CQi server couldn't open attribute";
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CLErrorWrongAttributeType = class CLErrorWrongAttributeType extends nopaque.corpus_analysis.cqi.errors.CLError {
+  constructor(message) {
+    super(message);
+    this.code = 1026;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CLErrorOutOfRange = class CLErrorOutOfRange extends nopaque.corpus_analysis.cqi.errors.CLError {
+  constructor(message) {
+    super(message);
+    this.code = 1027;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CLErrorRegex = class CLErrorRegex extends nopaque.corpus_analysis.cqi.errors.CLError {
+  constructor(message) {
+    super(message);
+    this.code = 1028;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CLErrorCorpusAccess = class CLErrorCorpusAccess extends nopaque.corpus_analysis.cqi.errors.CLError {
+  constructor(message) {
+    super(message);
+    this.code = 1029;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CLErrorOutOfMemory = class CLErrorOutOfMemory extends nopaque.corpus_analysis.cqi.errors.CLError {
+  constructor(message) {
+    super(message);
+    this.code = 1030;
+    this.description = 'CQi server has run out of memory; try discarding some other corpora and/or subcorpora';
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CLErrorInternal = class CLErrorInternal extends nopaque.corpus_analysis.cqi.errors.CLError {
+  constructor(message) {
+    super(message);
+    this.code = 1031;
+    this.description = "The classical 'please contact technical support' error";
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CQPError = class Error extends nopaque.corpus_analysis.cqi.errors.CQiError {
+  constructor(message) {
+    super(message);
+    this.code = 5;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CQPErrorGeneral = class CQPErrorGeneral extends nopaque.corpus_analysis.cqi.errors.CQPError {
+  constructor(message) {
+    super(message);
+    this.code = 1281;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CQPErrorNoSuchCorpus = class CQPErrorNoSuchCorpus extends nopaque.corpus_analysis.cqi.errors.CQPError {
+  constructor(message) {
+    super(message);
+    this.code = 1282;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CQPErrorInvalidField = class CQPErrorInvalidField extends nopaque.corpus_analysis.cqi.errors.CQPError {
+  constructor(message) {
+    super(message);
+    this.code = 1283;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.CQPErrorOutOfRange = class CQPErrorOutOfRange extends nopaque.corpus_analysis.cqi.errors.CQPError {
+  constructor(message) {
+    super(message);
+    this.code = 1284;
+    this.description = 'A number is out of range';
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.errors.lookup = {
+  2: nopaque.corpus_analysis.cqi.errors.Error,
+  513: nopaque.corpus_analysis.cqi.errors.ErrorGeneralError,
+  514: nopaque.corpus_analysis.cqi.errors.ErrorConnectRefused,
+  515: nopaque.corpus_analysis.cqi.errors.ErrorUserAbort,
+  516: nopaque.corpus_analysis.cqi.errors.ErrorSyntaxError,
+  4: nopaque.corpus_analysis.cqi.errors.CLError,
+  1025: nopaque.corpus_analysis.cqi.errors.CLErrorNoSuchAttribute,
+  1026: nopaque.corpus_analysis.cqi.errors.CLErrorWrongAttributeType,
+  1027: nopaque.corpus_analysis.cqi.errors.CLErrorOutOfRange,
+  1028: nopaque.corpus_analysis.cqi.errors.CLErrorRegex,
+  1029: nopaque.corpus_analysis.cqi.errors.CLErrorCorpusAccess,
+  1030: nopaque.corpus_analysis.cqi.errors.CLErrorOutOfMemory,
+  1031: nopaque.corpus_analysis.cqi.errors.CLErrorInternal,
+  5: nopaque.corpus_analysis.cqi.errors.CQPError,
+  1281: nopaque.corpus_analysis.cqi.errors.CQPErrorGeneral,
+  1282: nopaque.corpus_analysis.cqi.errors.CQPErrorNoSuchCorpus,
+  1283: nopaque.corpus_analysis.cqi.errors.CQPErrorInvalidField,
+  1284: nopaque.corpus_analysis.cqi.errors.CQPErrorOutOfRange
+};
diff --git a/app/static/js/CorpusAnalysis/cqi/index.js b/app/static/js/CorpusAnalysis/cqi/index.js
new file mode 100644
index 00000000..379c5897
--- /dev/null
+++ b/app/static/js/CorpusAnalysis/cqi/index.js
@@ -0,0 +1 @@
+nopaque.corpus_analysis.cqi = {};
diff --git a/app/static/js/cqi/models/attributes.js b/app/static/js/CorpusAnalysis/cqi/models/attributes.js
similarity index 67%
rename from app/static/js/cqi/models/attributes.js
rename to app/static/js/CorpusAnalysis/cqi/models/attributes.js
index 3347146b..a5764c3e 100644
--- a/app/static/js/cqi/models/attributes.js
+++ b/app/static/js/CorpusAnalysis/cqi/models/attributes.js
@@ -1,7 +1,7 @@
-cqi.models.attributes = {};
+nopaque.corpus_analysis.cqi.models.attributes = {};
 
 
-cqi.models.attributes.Attribute = class Attribute extends cqi.models.resource.Model {
+nopaque.corpus_analysis.cqi.models.attributes.Attribute = class Attribute extends nopaque.corpus_analysis.cqi.models.resource.Model {
   /**
    * @returns {string}
    */
@@ -24,7 +24,7 @@ cqi.models.attributes.Attribute = class Attribute extends cqi.models.resource.Mo
   }
 
   /**
-   * @returns {Promise<cqi.status.StatusOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
    */
   async drop() {
     return await this.client.api.cl_drop_attribute(this.apiName);
@@ -32,17 +32,17 @@ cqi.models.attributes.Attribute = class Attribute extends cqi.models.resource.Mo
 };
 
 
-cqi.models.attributes.AttributeCollection = class AttributeCollection extends cqi.models.resource.Collection {
-   /** @type{typeof cqi.models.attributes.Attribute} */
-  static model = cqi.models.attributes.Attribute;
+nopaque.corpus_analysis.cqi.models.attributes.AttributeCollection = class AttributeCollection extends nopaque.corpus_analysis.cqi.models.resource.Collection {
+   /** @type{typeof nopaque.corpus_analysis.cqi.models.attributes.Attribute} */
+  static model = nopaque.corpus_analysis.cqi.models.attributes.Attribute;
 
   /**
-   * @param {cqi.Client} client
-   * @param {cqi.models.corpora.Corpus} corpus
+   * @param {nopaque.corpus_analysis.cqi.Client} client
+   * @param {nopaque.corpus_analysis.cqi.models.corpora.Corpus} corpus
    */
   constructor(client, corpus) {
     super(client);
-     /** @type {cqi.models.corpora.Corpus} */
+     /** @type {nopaque.corpus_analysis.cqi.models.corpora.Corpus} */
     this.corpus = corpus;
   }
 
@@ -62,7 +62,7 @@ cqi.models.attributes.AttributeCollection = class AttributeCollection extends cq
 
   /**
    * @param {string} attributeName
-   * @returns {Promise<cqi.models.attributes.Attribute>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.models.attributes.Attribute>}
    */
   async get(attributeName) {
     return this.prepareModel(await this._get(attributeName));
@@ -70,7 +70,7 @@ cqi.models.attributes.AttributeCollection = class AttributeCollection extends cq
 };
 
 
-cqi.models.attributes.AlignmentAttribute = class AlignmentAttribute extends cqi.models.attributes.Attribute {
+nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute = class AlignmentAttribute extends nopaque.corpus_analysis.cqi.models.attributes.Attribute {
   /**
    * @param {number} id 
    * @returns {Promise<[number, number, number, number]>}
@@ -89,17 +89,17 @@ cqi.models.attributes.AlignmentAttribute = class AlignmentAttribute extends cqi.
 };
 
 
-cqi.models.attributes.AlignmentAttributeCollection = class AlignmentAttributeCollection extends cqi.models.attributes.AttributeCollection {
-   /** @type{typeof cqi.models.attributes.AlignmentAttribute} */
-  static model = cqi.models.attributes.AlignmentAttribute;
+nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttributeCollection = class AlignmentAttributeCollection extends nopaque.corpus_analysis.cqi.models.attributes.AttributeCollection {
+   /** @type{typeof nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute} */
+  static model = nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute;
 
   /**
-   * @returns {Promise<cqi.models.attributes.AlignmentAttribute[]>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute[]>}
    */
   async list() {
      /** @type {string[]} */
      let alignmentAttributeNames = await this.client.api.corpus_alignment_attributes(this.corpus.apiName);
-     /** @type {cqi.models.attributes.AlignmentAttribute[]} */
+     /** @type {nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute[]} */
     let alignmentAttributes = [];
     for (let alignmentAttributeName of alignmentAttributeNames) {
       alignmentAttributes.push(await this.get(alignmentAttributeName));
@@ -109,7 +109,7 @@ cqi.models.attributes.AlignmentAttributeCollection = class AlignmentAttributeCol
 };
 
 
-cqi.models.attributes.PositionalAttribute = class PositionalAttribute extends cqi.models.attributes.Attribute {
+nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute = class PositionalAttribute extends nopaque.corpus_analysis.cqi.models.attributes.Attribute {
   /**
    * @returns {number}
    */
@@ -183,9 +183,9 @@ cqi.models.attributes.PositionalAttribute = class PositionalAttribute extends cq
 };
 
 
-cqi.models.attributes.PositionalAttributeCollection = class PositionalAttributeCollection extends cqi.models.attributes.AttributeCollection {
-   /** @type{typeof cqi.models.attributes.PositionalAttribute} */
-  static model = cqi.models.attributes.PositionalAttribute;
+nopaque.corpus_analysis.cqi.models.attributes.PositionalAttributeCollection = class PositionalAttributeCollection extends nopaque.corpus_analysis.cqi.models.attributes.AttributeCollection {
+   /** @type{typeof nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute} */
+  static model = nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute;
 
   /**
    * @param {string} positionalAttributeName
@@ -198,7 +198,7 @@ cqi.models.attributes.PositionalAttributeCollection = class PositionalAttributeC
   }
 
   /**
-   * @returns {Promise<cqi.models.attributes.PositionalAttribute[]>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute[]>}
    */
   async list() {
     let positionalAttributeNames = await this.client.api.corpus_positional_attributes(this.corpus.apiName);
@@ -211,7 +211,7 @@ cqi.models.attributes.PositionalAttributeCollection = class PositionalAttributeC
 };
 
 
-cqi.models.attributes.StructuralAttribute = class StructuralAttribute extends cqi.models.attributes.Attribute {
+nopaque.corpus_analysis.cqi.models.attributes.StructuralAttribute = class StructuralAttribute extends nopaque.corpus_analysis.cqi.models.attributes.Attribute {
   /**
    * @returns {boolean}
    */
@@ -261,9 +261,9 @@ cqi.models.attributes.StructuralAttribute = class StructuralAttribute extends cq
 };
 
 
-cqi.models.attributes.StructuralAttributeCollection = class StructuralAttributeCollection extends cqi.models.attributes.AttributeCollection {
-   /** @type{typeof cqi.models.attributes.StructuralAttribute} */
-  static model = cqi.models.attributes.StructuralAttribute;
+nopaque.corpus_analysis.cqi.models.attributes.StructuralAttributeCollection = class StructuralAttributeCollection extends nopaque.corpus_analysis.cqi.models.attributes.AttributeCollection {
+   /** @type{typeof nopaque.corpus_analysis.cqi.models.attributes.StructuralAttribute} */
+  static model = nopaque.corpus_analysis.cqi.models.attributes.StructuralAttribute;
 
   /**
    * @param {string} structuralAttributeName
@@ -276,7 +276,7 @@ cqi.models.attributes.StructuralAttributeCollection = class StructuralAttributeC
   }
 
   /**
-   * @returns {Promise<cqi.models.attributes.StructuralAttribute[]>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.models.attributes.StructuralAttribute[]>}
    */
   async list() {
     let structuralAttributeNames = await this.client.api.corpus_structural_attributes(this.corpus.apiName);
diff --git a/app/static/js/cqi/models/corpora.js b/app/static/js/CorpusAnalysis/cqi/models/corpora.js
similarity index 66%
rename from app/static/js/cqi/models/corpora.js
rename to app/static/js/CorpusAnalysis/cqi/models/corpora.js
index 8128c47f..080f29a9 100644
--- a/app/static/js/cqi/models/corpora.js
+++ b/app/static/js/CorpusAnalysis/cqi/models/corpora.js
@@ -1,7 +1,7 @@
-cqi.models.corpora = {};
+nopaque.corpus_analysis.cqi.models.corpora = {};
 
 
-cqi.models.corpora.Corpus = class Corpus extends cqi.models.resource.Model {
+nopaque.corpus_analysis.cqi.models.corpora.Corpus = class Corpus extends nopaque.corpus_analysis.cqi.models.resource.Model {
   /**
    * @returns {string}
    */
@@ -38,35 +38,35 @@ cqi.models.corpora.Corpus = class Corpus extends cqi.models.resource.Model {
   }
 
   /**
-   * @returns {cqi.models.attributes.AlignmentAttributeCollection}
+   * @returns {nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttributeCollection}
    */
   get alignmentAttributes() {
-    return new cqi.models.attributes.AlignmentAttributeCollection(this.client, this);
+    return new nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttributeCollection(this.client, this);
   }
 
   /**
-   * @returns {cqi.models.attributes.PositionalAttributeCollection}
+   * @returns {nopaque.corpus_analysis.cqi.models.attributes.PositionalAttributeCollection}
    */
   get positionalAttributes() {
-    return new cqi.models.attributes.PositionalAttributeCollection(this.client, this);
+    return new nopaque.corpus_analysis.cqi.models.attributes.PositionalAttributeCollection(this.client, this);
   }
 
   /**
-   * @returns {cqi.models.attributes.StructuralAttributeCollection}
+   * @returns {nopaque.corpus_analysis.cqi.models.attributes.StructuralAttributeCollection}
    */
   get structuralAttributes() {
-    return new cqi.models.attributes.StructuralAttributeCollection(this.client, this);
+    return new nopaque.corpus_analysis.cqi.models.attributes.StructuralAttributeCollection(this.client, this);
   }
 
   /**
-   * @returns {cqi.models.subcorpora.SubcorpusCollection}
+   * @returns {nopaque.corpus_analysis.cqi.models.subcorpora.SubcorpusCollection}
    */
   get subcorpora() {
-    return new cqi.models.subcorpora.SubcorpusCollection(this.client, this);
+    return new nopaque.corpus_analysis.cqi.models.subcorpora.SubcorpusCollection(this.client, this);
   }
 
   /**
-   * @returns {Promise<cqi.status.StatusOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
    */
   async drop() {
     return await this.client.api.corpus_drop_corpus(this.apiName);
@@ -75,7 +75,7 @@ cqi.models.corpora.Corpus = class Corpus extends cqi.models.resource.Model {
   /**
    * @param {string} subcorpusName
    * @param {string} query
-   * @returns {Promise<cqi.status.StatusOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
    */
   async query(subcorpusName, query) {
     return await this.client.api.cqp_query(this.apiName, subcorpusName, query);
@@ -96,7 +96,7 @@ cqi.models.corpora.Corpus = class Corpus extends cqi.models.resource.Model {
   }
 
   /**
-   * @returns {cqi.status.StatusOk}
+   * @returns {nopaque.corpus_analysis.cqi.status.StatusOk}
    */
   async updateDb() {
     return await this.client.api.ext_corpus_update_db(this.apiName);
@@ -113,9 +113,9 @@ cqi.models.corpora.Corpus = class Corpus extends cqi.models.resource.Model {
 };
 
 
-cqi.models.corpora.CorpusCollection = class CorpusCollection extends cqi.models.resource.Collection {
-   /** @type {typeof cqi.models.corpora.Corpus} */
-  static model = cqi.models.corpora.Corpus;
+nopaque.corpus_analysis.cqi.models.corpora.CorpusCollection = class CorpusCollection extends nopaque.corpus_analysis.cqi.models.resource.Collection {
+   /** @type {typeof nopaque.corpus_analysis.cqi.models.corpora.Corpus} */
+  static model = nopaque.corpus_analysis.cqi.models.corpora.Corpus;
 
   /**
    * @param {string} corpusName
@@ -144,19 +144,19 @@ cqi.models.corpora.CorpusCollection = class CorpusCollection extends cqi.models.
 
   /**
    * @param {string} corpusName
-   * @returns {Promise<cqi.models.corpora.Corpus>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.models.corpora.Corpus>}
    */
   async get(corpusName) {
     return this.prepareModel(await this._get(corpusName));
   }
 
   /**
-   * @returns {Promise<cqi.models.corpora.Corpus[]>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.models.corpora.Corpus[]>}
    */
   async list() {
      /** @type {string[]} */
     let corpusNames = await this.client.api.corpus_list_corpora();
-     /** @type {cqi.models.corpora.Corpus[]} */
+     /** @type {nopaque.corpus_analysis.cqi.models.corpora.Corpus[]} */
     let corpora = [];
     for (let corpusName of corpusNames) {
       corpora.push(await this.get(corpusName));
diff --git a/app/static/js/CorpusAnalysis/cqi/models/index.js b/app/static/js/CorpusAnalysis/cqi/models/index.js
new file mode 100644
index 00000000..d258f12b
--- /dev/null
+++ b/app/static/js/CorpusAnalysis/cqi/models/index.js
@@ -0,0 +1 @@
+nopaque.corpus_analysis.cqi.models = {};
diff --git a/app/static/js/cqi/models/resource.js b/app/static/js/CorpusAnalysis/cqi/models/resource.js
similarity index 66%
rename from app/static/js/cqi/models/resource.js
rename to app/static/js/CorpusAnalysis/cqi/models/resource.js
index 9d3afde3..3fb3a5b1 100644
--- a/app/static/js/cqi/models/resource.js
+++ b/app/static/js/CorpusAnalysis/cqi/models/resource.js
@@ -1,26 +1,26 @@
-cqi.models.resource = {};
+nopaque.corpus_analysis.cqi.models.resource = {};
 
 
 /**
  * A base class for representing a single object on the server.
  */
-cqi.models.resource.Model = class Model {
+nopaque.corpus_analysis.cqi.models.resource.Model = class Model {
   /**
    * @param {object} attrs
-   * @param {cqi.CQiClient} client
-   * @param {cqi.models.resource.Collection} collection
+   * @param {nopaque.corpus_analysis.cqi.CQiClient} client
+   * @param {nopaque.corpus_analysis.cqi.models.resource.Collection} collection
    */
   constructor(attrs, client, collection) {
      /**
       * A client pointing at the server that this object is on.
       *
-      * @type {cqi.CQiClient}
+      * @type {nopaque.corpus_analysis.cqi.CQiClient}
       */
     this.client = client;
      /**
       * The collection that this model is part of.
       *
-      * @type {cqi.models.resource.Collection}
+      * @type {nopaque.corpus_analysis.cqi.models.resource.Collection}
       */
     this.collection = collection;
      /**
@@ -50,22 +50,22 @@ cqi.models.resource.Model = class Model {
 /**
  * A base class for representing all objects of a particular type on the server.
  */
-cqi.models.resource.Collection = class Collection {
+nopaque.corpus_analysis.cqi.models.resource.Collection = class Collection {
    /** 
     * The type of object this collection represents, set by subclasses
     * 
-    * @type {typeof cqi.models.resource.Model}
+    * @type {typeof nopaque.corpus_analysis.cqi.models.resource.Model}
     */
   static model;
 
   /**
-   * @param {cqi.CQiClient} client
+   * @param {nopaque.corpus_analysis.cqi.CQiClient} client
    */
   constructor(client) {
      /**
       * A client pointing at the server that this object is on.
       *
-      * @type {cqi.CQiClient}
+      * @type {nopaque.corpus_analysis.cqi.CQiClient}
       */
      this.client = client;
   }
@@ -82,7 +82,7 @@ cqi.models.resource.Collection = class Collection {
    * Create a model from a set of attributes.
    * 
    * @param {object} attrs
-   * @returns {cqi.models.resource.Model}
+   * @returns {nopaque.corpus_analysis.cqi.models.resource.Model}
    */
   prepareModel(attrs) {
     return new this.constructor.model(attrs, this.client, this);
diff --git a/app/static/js/cqi/models/subcorpora.js b/app/static/js/CorpusAnalysis/cqi/models/subcorpora.js
similarity index 63%
rename from app/static/js/cqi/models/subcorpora.js
rename to app/static/js/CorpusAnalysis/cqi/models/subcorpora.js
index aeba9485..79af649b 100644
--- a/app/static/js/cqi/models/subcorpora.js
+++ b/app/static/js/CorpusAnalysis/cqi/models/subcorpora.js
@@ -1,7 +1,7 @@
-cqi.models.subcorpora = {};
+nopaque.corpus_analysis.cqi.models.subcorpora = {};
 
 
-cqi.models.subcorpora.Subcorpus = class Subcorpus extends cqi.models.resource.Model {
+nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus = class Subcorpus extends nopaque.corpus_analysis.cqi.models.resource.Model {
   /**
    * @returns {string}
    */
@@ -31,7 +31,7 @@ cqi.models.subcorpora.Subcorpus = class Subcorpus extends cqi.models.resource.Mo
   }
 
   /**
-   * @returns {Promise<cqi.status.StatusOk>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
    */
   async drop() {
     return await this.client.api.cqp_drop_subcorpus(this.apiName);
@@ -55,7 +55,7 @@ cqi.models.subcorpora.Subcorpus = class Subcorpus extends cqi.models.resource.Mo
   /**
    * @param {number} cutoff
    * @param {number} field
-   * @param {cqi.models.attributes.PositionalAttribute} attribute
+   * @param {nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute} attribute
    * @returns {Promise<number[]>}
    */
   async fdist1(cutoff, field, attribute) {
@@ -70,9 +70,9 @@ cqi.models.subcorpora.Subcorpus = class Subcorpus extends cqi.models.resource.Mo
   /**
    * @param {number} cutoff
    * @param {number} field1
-   * @param {cqi.models.attributes.PositionalAttribute} attribute1
+   * @param {nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute} attribute1
    * @param {number} field2
-   * @param {cqi.models.attributes.PositionalAttribute} attribute2
+   * @param {nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute} attribute2
    * @returns {Promise<number[]>}
    */ 
   async fdist2(cutoff, field1, attribute1, field2, attribute2) {
@@ -122,17 +122,17 @@ cqi.models.subcorpora.Subcorpus = class Subcorpus extends cqi.models.resource.Mo
 };
 
 
-cqi.models.subcorpora.SubcorpusCollection = class SubcorpusCollection extends cqi.models.resource.Collection {
-   /** @type {typeof cqi.models.subcorpora.Subcorpus} */
-  static model = cqi.models.subcorpora.Subcorpus;
+nopaque.corpus_analysis.cqi.models.subcorpora.SubcorpusCollection = class SubcorpusCollection extends nopaque.corpus_analysis.cqi.models.resource.Collection {
+   /** @type {typeof nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus} */
+  static model = nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus;
 
   /**
-   * @param {cqi.CQiClient} client
-   * @param {cqi.models.corpora.Corpus} corpus
+   * @param {nopaque.corpus_analysis.cqi.CQiClient} client
+   * @param {nopaque.corpus_analysis.cqi.models.corpora.Corpus} corpus
    */
   constructor(client, corpus) {
     super(client);
-     /** @type {cqi.models.corpora.Corpus} */
+     /** @type {nopaque.corpus_analysis.cqi.models.corpora.Corpus} */
     this.corpus = corpus;
   }
 
@@ -145,17 +145,17 @@ cqi.models.subcorpora.SubcorpusCollection = class SubcorpusCollection extends cq
     let apiName = `${this.corpus.apiName}:${subcorpusName}`;
      /** @type {object} */
     let fields = {};
-    if (await this.client.api.cqp_subcorpus_has_field(apiName, cqi.constants.FIELD_MATCH)) {
-      fields.match = cqi.constants.FIELD_MATCH;
+    if (await this.client.api.cqp_subcorpus_has_field(apiName, nopaque.corpus_analysis.cqi.constants.FIELD_MATCH)) {
+      fields.match = nopaque.corpus_analysis.cqi.constants.FIELD_MATCH;
     }
-    if (await this.client.api.cqp_subcorpus_has_field(apiName, cqi.constants.FIELD_MATCHEND)) {
-      fields.matchend = cqi.constants.FIELD_MATCHEND
+    if (await this.client.api.cqp_subcorpus_has_field(apiName, nopaque.corpus_analysis.cqi.constants.FIELD_MATCHEND)) {
+      fields.matchend = nopaque.corpus_analysis.cqi.constants.FIELD_MATCHEND
     }
-    if (await this.client.api.cqp_subcorpus_has_field(apiName, cqi.constants.FIELD_TARGET)) {
-      fields.target = cqi.constants.FIELD_TARGET
+    if (await this.client.api.cqp_subcorpus_has_field(apiName, nopaque.corpus_analysis.cqi.constants.FIELD_TARGET)) {
+      fields.target = nopaque.corpus_analysis.cqi.constants.FIELD_TARGET
     }
-    if (await this.client.api.cqp_subcorpus_has_field(apiName, cqi.constants.FIELD_KEYWORD)) {
-      fields.keyword = cqi.constants.FIELD_KEYWORD
+    if (await this.client.api.cqp_subcorpus_has_field(apiName, nopaque.corpus_analysis.cqi.constants.FIELD_KEYWORD)) {
+      fields.keyword = nopaque.corpus_analysis.cqi.constants.FIELD_KEYWORD
     }
     return {
       api_name: apiName,
@@ -167,19 +167,19 @@ cqi.models.subcorpora.SubcorpusCollection = class SubcorpusCollection extends cq
 
   /**
    * @param {string} subcorpusName
-   * @returns {Promise<cqi.models.subcorpora.Subcorpus>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus>}
    */
   async get(subcorpusName) {
     return this.prepareModel(await this._get(subcorpusName));
   }
 
   /**
-   * @returns {Promise<cqi.models.subcorpora.Subcorpus[]>}
+   * @returns {Promise<nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus[]>}
    */
   async list() {
      /** @type {string[]} */
     let subcorpusNames = await this.client.api.cqp_list_subcorpora(this.corpus.apiName);
-     /** @type {cqi.models.subcorpora.Subcorpus[]} */
+     /** @type {nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus[]} */
     let subcorpora = [];
     for (let subcorpusName of subcorpusNames) {
       subcorpora.push(await this.get(subcorpusName));
diff --git a/app/static/js/CorpusAnalysis/cqi/status.js b/app/static/js/CorpusAnalysis/cqi/status.js
new file mode 100644
index 00000000..1d6a1fc7
--- /dev/null
+++ b/app/static/js/CorpusAnalysis/cqi/status.js
@@ -0,0 +1,51 @@
+nopaque.corpus_analysis.cqi.status = {};
+
+
+/**
+ * A base class from which all other status inherit.
+ */
+nopaque.corpus_analysis.cqi.status.CQiStatus = class CQiStatus {
+  constructor() {
+    this.code = undefined;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.status.StatusOk = class StatusOk extends nopaque.corpus_analysis.cqi.status.CQiStatus {
+  constructor() {
+    super();
+    this.code = 257;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.status.StatusConnectOk = class StatusConnectOk extends nopaque.corpus_analysis.cqi.status.CQiStatus {
+  constructor() {
+    super();
+    this.code = 258;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.status.StatusByeOk = class StatusByeOk extends nopaque.corpus_analysis.cqi.status.CQiStatus {
+  constructor() {
+    super();
+    this.code = 259;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.status.StatusPingOk = class StatusPingOk extends nopaque.corpus_analysis.cqi.status.CQiStatus {
+  constructor() {
+    super();
+    this.code = 260;
+  }
+};
+
+
+nopaque.corpus_analysis.cqi.status.lookup = {
+  257: nopaque.corpus_analysis.cqi.status.StatusOk,
+  258: nopaque.corpus_analysis.cqi.status.StatusConnectOk,
+  259: nopaque.corpus_analysis.cqi.status.StatusByeOk,
+  260: nopaque.corpus_analysis.cqi.status.StatusPingOk
+};
diff --git a/app/static/js/CorpusAnalysis/index.js b/app/static/js/CorpusAnalysis/index.js
new file mode 100644
index 00000000..a2ec10ca
--- /dev/null
+++ b/app/static/js/CorpusAnalysis/index.js
@@ -0,0 +1 @@
+nopaque.corpus_analysis = {};
diff --git a/app/static/js/cqi/api/index.js b/app/static/js/cqi/api/index.js
deleted file mode 100644
index fb42389b..00000000
--- a/app/static/js/cqi/api/index.js
+++ /dev/null
@@ -1 +0,0 @@
-cqi.api = {};
diff --git a/app/static/js/cqi/constants.js b/app/static/js/cqi/constants.js
deleted file mode 100644
index b12fef88..00000000
--- a/app/static/js/cqi/constants.js
+++ /dev/null
@@ -1,43 +0,0 @@
-cqi.constants = {};
-
-/** @type {number} */
-cqi.constants.FIELD_KEYWORD = 9;
-
-/** @type {number} */
-cqi.constants.FIELD_MATCH = 16;
-
-/** @type {number} */
-cqi.constants.FIELD_MATCHEND = 17;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET = 0;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET_0 = 0;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET_1 = 1;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET_2 = 2;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET_3 = 3;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET_4 = 4;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET_5 = 5;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET_6 = 6;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET_7 = 7;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET_8 = 8;
-
-/** @type {number} */
-cqi.constants.FIELD_TARGET_9 = 9;
diff --git a/app/static/js/cqi/errors.js b/app/static/js/cqi/errors.js
deleted file mode 100644
index c7011eb7..00000000
--- a/app/static/js/cqi/errors.js
+++ /dev/null
@@ -1,185 +0,0 @@
-cqi.errors = {};
-
-
-/**
- * A base class from which all other errors inherit.
- * If you want to catch all errors that the CQi package might throw,
- * catch this base error.
- */
-cqi.errors.CQiError = class CQiError extends Error {
-  constructor(message) {
-    super(message);
-    this.code = undefined;
-    this.description = undefined;
-  }
-};
-
-
-cqi.errors.Error = class Error extends cqi.errors.CQiError {
-  constructor(message) {
-    super(message);
-    this.code = 2;
-  }
-};
-
-
-cqi.errors.ErrorGeneralError = class ErrorGeneralError extends cqi.errors.Error {
-  constructor(message) {
-    super(message);
-    this.code = 513;
-  }
-};
-
-
-cqi.errors.ErrorConnectRefused = class ErrorConnectRefused extends cqi.errors.Error {
-  constructor(message) {
-    super(message);
-    this.code = 514;
-  }
-};
-
-
-cqi.errors.ErrorUserAbort = class ErrorUserAbort extends cqi.errors.Error {
-  constructor(message) {
-    super(message);
-    this.code = 515;
-  }
-};
-
-
-cqi.errors.ErrorSyntaxError = class ErrorSyntaxError extends cqi.errors.Error {
-  constructor(message) {
-    super(message);
-    this.code = 516;
-  }
-};
-
-
-cqi.errors.CLError = class Error extends cqi.errors.CQiError {
-  constructor(message) {
-    super(message);
-    this.code = 4;
-  }
-};
-
-
-cqi.errors.CLErrorNoSuchAttribute = class CLErrorNoSuchAttribute extends cqi.errors.CLError {
-  constructor(message) {
-    super(message);
-    this.code = 1025;
-    this.description = "CQi server couldn't open attribute";
-  }
-};
-
-
-cqi.errors.CLErrorWrongAttributeType = class CLErrorWrongAttributeType extends cqi.errors.CLError {
-  constructor(message) {
-    super(message);
-    this.code = 1026;
-  }
-};
-
-
-cqi.errors.CLErrorOutOfRange = class CLErrorOutOfRange extends cqi.errors.CLError {
-  constructor(message) {
-    super(message);
-    this.code = 1027;
-  }
-};
-
-
-cqi.errors.CLErrorRegex = class CLErrorRegex extends cqi.errors.CLError {
-  constructor(message) {
-    super(message);
-    this.code = 1028;
-  }
-};
-
-
-cqi.errors.CLErrorCorpusAccess = class CLErrorCorpusAccess extends cqi.errors.CLError {
-  constructor(message) {
-    super(message);
-    this.code = 1029;
-  }
-};
-
-
-cqi.errors.CLErrorOutOfMemory = class CLErrorOutOfMemory extends cqi.errors.CLError {
-  constructor(message) {
-    super(message);
-    this.code = 1030;
-    this.description = 'CQi server has run out of memory; try discarding some other corpora and/or subcorpora';
-  }
-};
-
-
-cqi.errors.CLErrorInternal = class CLErrorInternal extends cqi.errors.CLError {
-  constructor(message) {
-    super(message);
-    this.code = 1031;
-    this.description = "The classical 'please contact technical support' error";
-  }
-};
-
-
-cqi.errors.CQPError = class Error extends cqi.errors.CQiError {
-  constructor(message) {
-    super(message);
-    this.code = 5;
-  }
-};
-
-
-cqi.errors.CQPErrorGeneral = class CQPErrorGeneral extends cqi.errors.CQPError {
-  constructor(message) {
-    super(message);
-    this.code = 1281;
-  }
-};
-
-
-cqi.errors.CQPErrorNoSuchCorpus = class CQPErrorNoSuchCorpus extends cqi.errors.CQPError {
-  constructor(message) {
-    super(message);
-    this.code = 1282;
-  }
-};
-
-
-cqi.errors.CQPErrorInvalidField = class CQPErrorInvalidField extends cqi.errors.CQPError {
-  constructor(message) {
-    super(message);
-    this.code = 1283;
-  }
-};
-
-
-cqi.errors.CQPErrorOutOfRange = class CQPErrorOutOfRange extends cqi.errors.CQPError {
-  constructor(message) {
-    super(message);
-    this.code = 1284;
-    this.description = 'A number is out of range';
-  }
-};
-
-
-cqi.errors.lookup = {
-  2: cqi.errors.Error,
-  513: cqi.errors.ErrorGeneralError,
-  514: cqi.errors.ErrorConnectRefused,
-  515: cqi.errors.ErrorUserAbort,
-  516: cqi.errors.ErrorSyntaxError,
-  4: cqi.errors.CLError,
-  1025: cqi.errors.CLErrorNoSuchAttribute,
-  1026: cqi.errors.CLErrorWrongAttributeType,
-  1027: cqi.errors.CLErrorOutOfRange,
-  1028: cqi.errors.CLErrorRegex,
-  1029: cqi.errors.CLErrorCorpusAccess,
-  1030: cqi.errors.CLErrorOutOfMemory,
-  1031: cqi.errors.CLErrorInternal,
-  5: cqi.errors.CQPError,
-  1281: cqi.errors.CQPErrorGeneral,
-  1282: cqi.errors.CQPErrorNoSuchCorpus,
-  1283: cqi.errors.CQPErrorInvalidField,
-  1284: cqi.errors.CQPErrorOutOfRange
-};
diff --git a/app/static/js/cqi/index.js b/app/static/js/cqi/index.js
deleted file mode 100644
index d941a870..00000000
--- a/app/static/js/cqi/index.js
+++ /dev/null
@@ -1 +0,0 @@
-var cqi = {};
diff --git a/app/static/js/cqi/models/index.js b/app/static/js/cqi/models/index.js
deleted file mode 100644
index 4973862f..00000000
--- a/app/static/js/cqi/models/index.js
+++ /dev/null
@@ -1 +0,0 @@
-cqi.models = {};
diff --git a/app/static/js/cqi/status.js b/app/static/js/cqi/status.js
deleted file mode 100644
index 0782ee26..00000000
--- a/app/static/js/cqi/status.js
+++ /dev/null
@@ -1,51 +0,0 @@
-cqi.status = {};
-
-
-/**
- * A base class from which all other status inherit.
- */
-cqi.status.CQiStatus = class CQiStatus {
-  constructor() {
-    this.code = undefined;
-  }
-};
-
-
-cqi.status.StatusOk = class StatusOk extends cqi.status.CQiStatus {
-  constructor() {
-    super();
-    this.code = 257;
-  }
-};
-
-
-cqi.status.StatusConnectOk = class StatusConnectOk extends cqi.status.CQiStatus {
-  constructor() {
-    super();
-    this.code = 258;
-  }
-};
-
-
-cqi.status.StatusByeOk = class StatusByeOk extends cqi.status.CQiStatus {
-  constructor() {
-    super();
-    this.code = 259;
-  }
-};
-
-
-cqi.status.StatusPingOk = class StatusPingOk extends cqi.status.CQiStatus {
-  constructor() {
-    super();
-    this.code = 260;
-  }
-};
-
-
-cqi.status.lookup = {
-  257: cqi.status.StatusOk,
-  258: cqi.status.StatusConnectOk,
-  259: cqi.status.StatusByeOk,
-  260: cqi.status.StatusPingOk
-};
diff --git a/app/static/js/forms/index.js b/app/static/js/forms/index.js
index ffdad4bd..5a382b44 100644
--- a/app/static/js/forms/index.js
+++ b/app/static/js/forms/index.js
@@ -3,7 +3,7 @@ nopaque.forms = {};
 nopaque.forms.AutoInit = () => {
   for (let propertyName in nopaque.forms) {
     let property = nopaque.forms[propertyName];
-    // Call autoInit of all properties that are subclasses of nopaque.forms.BaseForm.
+    // Initialize properties that are subclasses of nopaque.forms.BaseForm.
     // This does not include nopaque.forms.BaseForm itself.
     if (property.prototype instanceof nopaque.forms.BaseForm) {
       // Check if the static htmlClass property is defined.
diff --git a/app/static/js/resource-displays/index.js b/app/static/js/resource-displays/index.js
index 3765fcb2..926f11d6 100644
--- a/app/static/js/resource-displays/index.js
+++ b/app/static/js/resource-displays/index.js
@@ -3,7 +3,7 @@ nopaque.resource_displays = {};
 nopaque.resource_displays.AutoInit = () => {
   for (let propertyName in nopaque.resource_displays) {
     let property = nopaque.resource_displays[propertyName];
-    // Call autoInit of all properties that are subclasses of `nopaque.resource_displays.ResourceDisplay`.
+    // Initialize properties that are subclasses of `nopaque.resource_displays.ResourceDisplay`.
     // This does not include `nopaque.resource_displays.ResourceDisplay` itself.
     if (property.prototype instanceof nopaque.resource_displays.ResourceDisplay) {
       // Check if the static `htmlClass` property is defined.
diff --git a/app/static/js/resource-lists/index.js b/app/static/js/resource-lists/index.js
index ebac0209..c40fc514 100644
--- a/app/static/js/resource-lists/index.js
+++ b/app/static/js/resource-lists/index.js
@@ -3,7 +3,7 @@ nopaque.resource_lists = {};
 nopaque.resource_lists.AutoInit = () => {
   for (let propertyName in nopaque.resource_lists) {
     let property = nopaque.resource_lists[propertyName];
-    // Call autoInit of all properties that are subclasses of `nopaque.resource_lists.ResourceList`.
+    // Initialize properties that are subclasses of `nopaque.resource_lists.ResourceList`.
     // This does not include `nopaque.resource_lists.ResourceList` itself.
     if (property.prototype instanceof nopaque.resource_lists.ResourceList) {
       // Check if the static `htmlClass` property is defined.
diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2
index 152409d3..f361f1dd 100644
--- a/app/templates/_scripts.html.j2
+++ b/app/templates/_scripts.html.j2
@@ -14,25 +14,6 @@
 <script src="{{ ASSET_URL }}"></script>
 {%- endassets %}
 
-{%- assets
-  filters='rjsmin',
-  output='gen/cqi.%(version)s.js',
-  'js/cqi/index.js',
-  'js/cqi/constants.js',
-  'js/cqi/errors.js',
-  'js/cqi/status.js',
-  'js/cqi/api/index.js',
-  'js/cqi/api/client.js',
-  'js/cqi/models/index.js',
-  'js/cqi/models/resource.js',
-  'js/cqi/models/attributes.js',
-  'js/cqi/models/subcorpora.js',
-  'js/cqi/models/corpora.js',
-  'js/cqi/client.js'
-%}
-<script src="{{ ASSET_URL }}"></script>
-{%- endassets %}
-
 {%- assets
   filters='rjsmin',
   output='gen/Forms.%(version)s.js',
@@ -94,7 +75,20 @@
 
 {%- assets
   filters='rjsmin',
-  output='gen/CorpusAnalysis.%(version)s.js',
+  output='gen/corpus-analysis.%(version)s.js',
+  'js/CorpusAnalysis/index.js',
+  'js/CorpusAnalysis/cqi/index.js',
+  'js/CorpusAnalysis/cqi/constants.js',
+  'js/CorpusAnalysis/cqi/errors.js',
+  'js/CorpusAnalysis/cqi/status.js',
+  'js/CorpusAnalysis/cqi/api/index.js',
+  'js/CorpusAnalysis/cqi/api/client.js',
+  'js/CorpusAnalysis/cqi/models/index.js',
+  'js/CorpusAnalysis/cqi/models/resource.js',
+  'js/CorpusAnalysis/cqi/models/attributes.js',
+  'js/CorpusAnalysis/cqi/models/subcorpora.js',
+  'js/CorpusAnalysis/cqi/models/corpora.js',
+  'js/CorpusAnalysis/cqi/client.js',
   'js/CorpusAnalysis/query-builder/index.js',
   'js/CorpusAnalysis/query-builder/element-references.js',
   'js/CorpusAnalysis/query-builder/general-query-builder-functions.js',
-- 
GitLab