Repository: ganga-devs/ganga (language: python)

Issue:
Remove the non-functional GUI code 
The GUI code in `ganga` was never developed into a functional thing. It is not realistic for somebody to pick up on this code and develop it further. Hence we are better off backing it out of Ganga


Discussion / hints:

Fix patch:
diff --git a/bin/ganga-gui b/bin/ganga-gui
deleted file mode 100755
index 4aa5f46c53..0000000000
--- a/bin/ganga-gui
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env python3
-
-"""
-Starts Ganga GUI with integrated terminal
-"""
-
-import argparse
-import sys
-import os
-
-# Insert the path to Ganga itself - this is required for the installations without pip
-exeDir = os.path.abspath(os.path.normpath(os.path.dirname(os.path.realpath(__file__))))
-gangaDir = os.path.join(os.path.dirname(exeDir), 'ganga')
-sys.path.insert(0, gangaDir)
-
-from ganga.GangaGUI.gui.routes import start_web_cli
-
-# Command line options
-parser = argparse.ArgumentParser(
-    description="Start Ganga GUI with integrated Ganga CLI. This will also start a Ganga session with the arguments passed as a string to --ganga-args flag.")
-parser.add_argument('--host', action='store', dest='host', default='0.0.0.0',
-                    help='Host to start the server on. Default is 0.0.0.0')
-parser.add_argument('--port', action='store', dest='port', default=5500,
-                    help='Port to start the web gui server on. Default is 5500.')
-parser.add_argument('--internal-port', action='store', dest='internal_port', default=5000,
-                    help='Port to start internal API server on, which is used by web gui server internally to communicate with Ganga. Default is 5000.')
-parser.add_argument('--quiet', action='store_true', default=False,
-                    help='Disables logging of GUI server output to the stdout.')
-parser.add_argument('--ganga-args', action='store', dest='ganga_args', default="",
-                    help="Arguments to pass to ganga. Pass arguments as a string. Arguments must start with a space, or use an equals. Eg. --ganga-args ' --very-quiet' or --ganga-args='--very-quiet'")
-
-# Parse command line arguments
-args = parser.parse_args()
-
-# Parse command line arguments
-web_cli_host = args.host
-web_cli_port = int(args.port)
-internal_server_port = int(args.internal_port)
-ganga_args = args.ganga_args
-log_output = not args.quiet
-
-# Start the web cli - this will also start a Ganga Session
-start_web_cli(host=web_cli_host, port=web_cli_port, internal_port=internal_server_port, ganga_args=ganga_args,
-              log_output=log_output)
diff --git a/ganga/GangaCore/Core/InternalServices/ShutdownManager.py b/ganga/GangaCore/Core/InternalServices/ShutdownManager.py
index 01ff9a3c9a..6e24d92b7a 100755
--- a/ganga/GangaCore/Core/InternalServices/ShutdownManager.py
+++ b/ganga/GangaCore/Core/InternalServices/ShutdownManager.py
@@ -16,8 +16,9 @@
 from GangaCore.Utility import stacktracer
 from GangaCore.Utility.logging import getLogger, requires_shutdown, final_shutdown
 from GangaCore.Utility.Config import setConfigOption
-from GangaCore.Core.MonitoringComponent.Local_GangaMC_Service import getStackTrace, _purge_actions_queue,\
-    stop_and_free_thread_pool
+from GangaCore.Core.MonitoringComponent.Local_GangaMC_Service import (getStackTrace,
+                                                                      _purge_actions_queue,
+                                                                      stop_and_free_thread_pool)
 from GangaCore.GPIDev.Lib.Tasks import stopTasks
 from GangaCore.GPIDev.Credentials import CredentialStore
 from GangaCore.Core.GangaRepository.SessionLock import removeGlobalSessionFiles, removeGlobalSessionFileHandlers
@@ -60,15 +61,6 @@ def _unprotected_ganga_exitfuncs():
     # Set the disk timeout to 1 sec, sacrifice stability for quicker exit
     setConfigOption('Configuration', 'DiskIOTimeout', 1)
 
-    # Stop APIServerThread - GangaGUI
-    from GangaGUI import guistate
-    if guistate.get_api_server() is not None:
-        from GangaGUI.start import stop_gui
-        try:
-            stop_gui()
-        except Exception as err:
-            logger.exception("Exception raised while stopping GUI: {}".format(err))
-
     # Stop the monitoring loop from iterating further
     if monitoring_component is not None:
         try:
diff --git a/ganga/GangaCore/Runtime/bootstrap.py b/ganga/GangaCore/Runtime/bootstrap.py
index 954c715043..c1fe2a5742 100644
--- a/ganga/GangaCore/Runtime/bootstrap.py
+++ b/ganga/GangaCore/Runtime/bootstrap.py
@@ -273,15 +273,12 @@ def parseOptions(self):
         parser.add_option("-i", dest="force_interactive", action="store_true",
                           help='enter interactive mode after running script')
 
-        parser.add_option("--webgui", dest="webgui", action="store_true", default='False',
-                          help='starts web GUI monitoring server')
-
         parser.add_option("--config", dest="config_file", action="store", metavar="FILE", default=None,
                           help=('read user configuration from FILE, overrides the GANGA_CONFIG_FILE environment variable. '
                                 'Default: ~/.gangarc'))
 
         parser.add_option("--config-path", dest='config_path', action="store", default=None,
-                          help=('site/experiment config customization path, overrides GANGA_CONFIG_PATH environment variable. '
+                          help=('site/experiment config customization path, overrides GANGA_CONFIG_PATH.'
                                 'The relative paths are resolved wrt to the release directory. '
                                 'To use a specific file you should specify the absolute path. Default: None'))
 
@@ -314,7 +311,8 @@ def parseOptions(self):
                                'to setup runtime plugin modules (affects LD_LIBRARY_PATH)')
 
         parser.add_option("--test", dest='TEST', action="store_true", default=False,
-                          help=('run Ganga test(s) using internal test-runner. It requires GangaTest package to be installed. '
+                          help=('run Ganga test(s) using internal test-runner. '
+                                'It requires GangaTest package to be installed.'
                                 'Usage example: *ganga --test Ganga/old_test/MyTestcase* . '
                                 'Refer to [TestingFramework] section in Ganga config for more '
                                 'information on how to configure the test runner.'))
@@ -1018,10 +1016,6 @@ def run(self, local_ns=None):
 
         sys.path.insert(0, '')
 
-        if self.options.webgui is True:
-            from GangaGUI.start import start_gui
-            start_gui()
-
         if local_ns is None:
             import __main__
             local_ns = __main__.__dict__
@@ -1564,4 +1558,4 @@ def launch_IPython(local_ns):
 # added docstrings for GPI objects and an interactive ganga help system based on pydoc
 #
 #
-#
\ No newline at end of file
+#
diff --git a/ganga/GangaCore/__init__.py b/ganga/GangaCore/__init__.py
index 8fdb3bb1af..efdd7e983d 100644
--- a/ganga/GangaCore/__init__.py
+++ b/ganga/GangaCore/__init__.py
@@ -160,7 +160,7 @@ def getLCGRootPath():
 If an element of the path is just a name (like in the example below)
 then the plugins will be loaded using current python path. This means that
 some packages such as GangaTest may be taken from the release area.""",
-    examples="""RUNTIME_PATH = GangaGUI
+    examples="""RUNTIME_PATH = GangaDirac
 RUNTIME_PATH = /my/SpecialExtensions:GangaTest""",
 )
 
@@ -697,14 +697,6 @@ def getLCGRootPath():
     ),
 )
 
-# config.addOption('bulk_submit_time','random.uniform(1,2)',('python expression which returns the time it takes (in seconds) '
-#        'to complete the submission of a single job within the Grid.native_master_submit() command'))
-# config.addOption('bulk_submit_failure_rate',0.0,'probabilty that the Grid.native_master_submit() fails')
-
-# config.addOption('bulk_cancel_time','random.uniform(1,2)',('python expression which returns the time it takes (in seconds) '
-#        'to complete the cancellation of a single job within the Grid.native_master_cancel() command'))
-# config.addOption('bulk_cancel_failure_rate',0.0,'probabilty that the Grid.native_master_cancel() fails')
-
 gridsim_config.addOption(
     'job_id_resolved_time',
     'random.uniform(1,2)',
diff --git a/ganga/GangaGUI/BOOT.py b/ganga/GangaGUI/BOOT.py
deleted file mode 100644
index 478aa755e7..0000000000
--- a/ganga/GangaGUI/BOOT.py
+++ /dev/null
@@ -1,7 +0,0 @@
-"""Set RUNTIME_PATH = GangaGUI into order to export the following function the GPI"""
-
-from GangaCore.Runtime.GPIexport import exportToGPI
-from GangaGUI.start import start_gui, stop_gui
-
-exportToGPI("start_gui", start_gui, "Functions")
-exportToGPI("stop_gui", stop_gui, "Functions")
\ No newline at end of file
diff --git a/ganga/GangaGUI/__init__.py b/ganga/GangaGUI/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/ganga/GangaGUI/api/__init__.py b/ganga/GangaGUI/api/__init__.py
deleted file mode 100644
index 536cb3879a..0000000000
--- a/ganga/GangaGUI/api/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from flask import Flask
-import sys
-import os
-import logging
-
-# Disable development server warning (as it is not applicable to our GUI Flask App)
-cli = sys.modules['flask.cli']
-cli.show_server_banner = lambda *x: None
-
-# Only error cases are logged
-log = logging.getLogger('werkzeug')
-log.setLevel(logging.ERROR)
-
-# Flask app for APIs
-internal = Flask(__name__)
-internal.config['SECRET_KEY'] = os.urandom(24)
-
-from GangaGUI.api import routes
diff --git a/ganga/GangaGUI/api/routes.py b/ganga/GangaGUI/api/routes.py
deleted file mode 100644
index 3541afe2b5..0000000000
--- a/ganga/GangaGUI/api/routes.py
+++ /dev/null
@@ -1,1110 +0,0 @@
-import json
-import io
-from itertools import chain
-from time import time
-from flask import jsonify, request, make_response
-from GangaGUI.api import internal
-
-
-# ******************** Internal Job API Routes ******************** #
-
-# Single job information
-@internal.route("/internal/jobs/<int:job_id>", methods=["GET"])
-def job_information(job_id: int):
-    """
-    Gets job information from the Ganga, and returns it in JSON format.
-    :param job_id: int
-    :return: json
-    """
-
-    try:
-        # Get the general info of the job
-        job_info = get_job_info(job_id)
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(job_info)
-
-
-# Single job attribute information
-@internal.route("/internal/jobs/<int:job_id>/<attribute>", methods=["GET"])
-def job_attribute(job_id: int, attribute: str):
-    """
-    returns information about the job attribute in JSON format.
-    :param job_id: int
-    :param attribute: str
-    :return: json
-    """
-
-    from GangaCore.GPI import jobs
-
-    try:
-        # Get job attribute information
-        j = jobs(job_id)
-        job_attribute_info = {attribute: str(getattr(j, attribute))}
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(job_attribute_info)
-
-
-# Full print of the job
-@internal.route("/internal/jobs/<int:job_id>/full-print", methods=["GET"])
-def job_full_print(job_id: int):
-    """
-    Return full print of the job.
-    :param job_id: int
-    :return: json
-    """
-
-    from GangaCore.GPI import jobs, full_print
-
-    try:
-        # Store full print of the job in a file like object
-        print_output = io.StringIO()
-        full_print(jobs(job_id), out=print_output)
-        full_print_info = print_output.getvalue()
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(full_print_info)
-
-
-# Create job using template
-@internal.route("/internal/jobs/create", methods=["POST"])
-def job_create():
-    """
-    Create job using the template information provided as json in the request body.
-    :return: json
-    """
-
-    from GangaCore.GPI import templates, Job
-
-    # Parse request body
-    request_json = request.json if request.json else {}
-    template_id = request_json.get("template_id")
-    job_name = request_json.get("job_name")
-
-    try:
-        # Create job using template
-        j = Job(templates[int(template_id)])
-        if job_name is not None:
-            j.name = job_name
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify({"success": True,
-                    "message": f"Job with ID {j.id} created successfully using the template with ID {template_id}"})
-
-
-# Copy job
-@internal.route("/internal/jobs/<int:job_id>/copy", methods=["PUT"])
-def job_copy(job_id: int):
-    """
-    Create a copy the the job.
-    :param job_id: int
-    :return: json
-    """
-
-    from GangaCore.GPI import jobs
-
-    try:
-        # Copy job
-        j = jobs(job_id)
-        new_j = j.copy()
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify({"success": True, "message": f"Successfully created a new copy with ID {new_j.id}"})
-
-
-# Job action
-@internal.route("/internal/jobs/<int:job_id>/<action>", methods=["PUT"])
-def job_action(job_id: int, action: str):
-    """
-    Perform action on the job using the arguments provided as json in the request body.
-    :param job_id: int
-    :param action: str
-    :return: json
-    """
-
-    from GangaCore.GPI import jobs
-    from GangaCore.GPIDev.Lib.Job import Job
-
-    # Store request data in a dictionary
-    request_data = request.json if request.json else {}
-
-    # Action validity check
-    if action not in chain(Job._exportmethods, Job._schema.allItemNames()):
-        return jsonify({"success": False, "message": f"{action} not supported or does not exist"}), 400
-
-    # Action on Job Methods
-    if action in Job._exportmethods:
-        try:
-
-            # Get job to perform action on
-            j = jobs(job_id)
-
-            # Check for arguments in the request body for passing in the method
-            if action in request_data.keys():
-                args = request_data[action]
-                if isinstance(args, type([])):
-                    getattr(j, action)(*args)
-                elif isinstance(args, type({})):
-                    getattr(j, action)(**args)
-                else:
-                    getattr(j, action)(args)
-            else:
-                getattr(j, action)()
-
-        except Exception as err:
-            return jsonify({"success": False, "message": str(err)}), 400
-
-    # Action on Job Attribute
-    if action in Job._schema.allItemNames():
-        try:
-
-            # Get job to perform action on
-            j = jobs(job_id)
-
-            # Check for the value to set in the request body
-            if action in request_data.keys():
-                arg = request_data[action]
-                setattr(j, action, arg)
-            else:
-                return jsonify(
-                    {"success": False, "message": f"Please provide the value for {action} in the request body"}), 400
-
-        except Exception as err:
-            return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(
-        {"success": True, "message": f"Successfully completed the action {action} on the Job with ID {job_id}"})
-
-
-# Delete job
-@internal.route("/internal/jobs/<int:job_id>", methods=["DELETE"])
-def job_delete(job_id: int):
-    """
-    Delete job from the repository.
-    :param job_id: int
-    :return: json
-    """
-
-    from GangaCore.GPI import jobs
-
-    try:
-        # Remove job
-        j = jobs(job_id)
-        j.remove()
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify({"success": True, "message": "Job with ID {} removed successfully".format(job_id)})
-
-
-# Export the job
-@internal.route("/internal/jobs/<int:job_id>/export", methods=["GET"])
-def job_export(job_id: int):
-    """
-    Exports the job to the path provided in the request argument.
-    :param job_id: int
-    :return: json
-    """
-
-    from GangaCore.GPI import jobs, export
-
-    # Export save path
-    save_path = request.args.get("path")
-
-    try:
-        # Export job
-        export(jobs(job_id), save_path)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify({"success": True, "message": "Successfully exported the job."})
-
-
-# ******************** Internal Subjobs API Routes ******************** #
-
-# Get jobs information
-@internal.route("/internal/jobs/<int:job_id>/subjobs", methods=["GET"])
-def subjobs_information(job_id: int):
-    """
-    Return a list of subjobs information in JSON format according to select filter and range filter. Read GUI API docstring for more information.
-    :param job_id: int
-    :return: json
-    """
-
-    from GangaCore.GPI import jobs
-
-    # Subjob filter
-    subjobs_filter = {
-        "status": request.args.get("status"),
-        "application": request.args.get("application"),
-        "backend": request.args.get("backend")
-    }
-
-    # Range filter
-    range_filter = {
-        "recent": request.args.get("recent"),
-        "length": request.args.get("length"),
-        "offset": request.args.get("offset") if request.args.get("offset") is not None else 0,
-    }
-
-    # To store subjobs information
-    subjobs_info = []
-
-    # Selective subjobs info
-    if "ids" in request.args:
-
-        subjob_ids = json.loads(request.args["ids"])
-
-        try:
-            # Store specific subjobs information
-            for sjid in subjob_ids:
-                subjobs_info.append(get_subjob_info(job_id=job_id, subjob_id=sjid))
-
-            return jsonify(subjobs_info)
-
-        except Exception as err:
-            return jsonify({"success": False, "message": str(err)}), 400
-
-    # All subjobs info
-    try:
-        # Filter subjobs
-        subjobs_filtered = list(
-            jobs[job_id].subjobs.select(**{key: subjobs_filter[key] for key in subjobs_filter.keys() if
-                                           subjobs_filter[key] not in ["any", None]}))
-
-        # Reverse if recent is present in params
-        if range_filter["recent"] is not None:
-            subjobs_filtered.reverse()
-
-        # Apply range filters
-        if range_filter["length"] is None:
-            subjobs_slice = slice(None, None)
-        else:
-            start = int(range_filter["offset"]) * int(range_filter["length"])
-            end = start + int(range_filter["length"])
-            subjobs_slice = slice(start, end)
-
-        # Store subjobs information
-        for sj in subjobs_filtered[subjobs_slice]:
-            subjobs_info.append(get_subjob_info(job_id=job_id, subjob_id=sj.id))
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(subjobs_info)
-
-
-# Get subjobs length
-@internal.route("/internal/jobs/<int:job_id>/subjobs/length", methods=["GET"])
-def subjobs_length(job_id: int):
-    """
-    returns total number of subjobs of a job after applying the filter.
-    :param job_id: int
-    :return: json
-    """
-
-    from GangaCore.GPI import jobs
-
-    subjobs_filter = {
-        "status": request.args.get("status"),
-        "application": request.args.get("application"),
-        "backend": request.args.get("backend")
-    }
-
-    try:
-        # Get subjobs length
-        subjobs_len = len(jobs[job_id].subjobs.select(**{key: subjobs_filter[key] for key in subjobs_filter.keys() if
-                                                         subjobs_filter[key] not in ["any", None]}))
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(subjobs_len)
-
-
-# Single subjob infomation
-@internal.route("/internal/jobs/<int:job_id>/subjobs/<int:subjob_id>", methods=["GET"])
-def subjob_information(job_id: int, subjob_id: int):
-    """
-    Return general information about a subjob.
-    :param job_id: int
-    :param subjob_id: int
-    """
-
-    try:
-        # Get the general info of the job
-        subjob_info = get_subjob_info(job_id=job_id, subjob_id=subjob_id)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(subjob_info)
-
-
-# Subjob attribute
-@internal.route("/internal/jobs/<int:job_id>/subjobs/<int:subjob_id>/<attribute>", methods=["GET"])
-def subjob_attribute(job_id: int, subjob_id: int, attribute: str):
-    """
-    Returns information about subjob attribute in JSON format.
-    :param job_id: int
-    :param subjob_id: int
-    :param attribute: str
-    """
-
-    from GangaCore.GPI import jobs
-
-    try:
-        # Get subjob attribute info
-        j = jobs[int(job_id)]
-        sj = j.subjobs[int(subjob_id)]
-        subjob_attribute_info = {attribute: str(getattr(sj, attribute))}
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(subjob_attribute_info)
-
-
-# Subjob copy
-@internal.route("/internal/jobs/<int:job_id>/subjobs/<int:subjob_id>/copy", methods=["PUT"])
-def subjob_copy(job_id: int, subjob_id: int):
-    """
-    Create a copy of subjob to a new job.
-    :param job_id: int
-    :param subjob_id: int
-    """
-
-    from GangaCore.GPI import jobs
-
-    try:
-        # Copy subjob
-        j = jobs[job_id]
-        sj = j.subjobs[subjob_id]
-        new_j = sj.copy()
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify({"success": True, "message": f"Successfully created a new copy with ID {new_j.id}"})
-
-
-# Subjob full print
-@internal.route("/internal/jobs/<int:job_id>/subjobs/<int:subjob_id>/full-print", methods=["GET"])
-def subjob_full_print(job_id: int, subjob_id: int):
-    """
-    Returns full print information of the subjob.
-    :param job_id: int
-    :param subjob_id: int
-    """
-
-    from GangaCore.GPI import jobs, full_print
-
-    try:
-        # A file like object to store full print information
-        print_output = io.StringIO()
-        full_print(jobs(job_id).subjobs(subjob_id), out=print_output)
-        full_print_info = print_output.getvalue()
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(full_print_info)
-
-
-# ******************** Internal Jobs API Routes ******************** #
-
-# Get jobs information
-@internal.route("/internal/jobs", methods=["GET"])
-def jobs_information():
-    """
-    Return a list of jobs information in JSON format according to select filter and range filter. Read GUI API docstring for more information.
-    """
-
-    from GangaCore.GPI import jobs
-
-    # Job select filter
-    jobs_filter = {
-        "status": request.args.get("status"),
-        "application": request.args.get("application"),
-        "backend": request.args.get("backend")
-    }
-
-    # Range filter
-    range_filter = {
-        "recent": request.args.get("recent"),
-        "length": request.args.get("length"),
-        "offset": request.args.get("offset") if request.args.get("offset") is not None else 0,
-    }
-
-    # Auto validate ids provided in the ids parameter. if not None, it will skip the non existent ids
-    auto_validate_ids = request.args.get("auto-validate-ids")
-
-    # Store jobs information
-    jobs_info = []
-
-    # Selective jobs info
-    if "ids" in request.args:
-        request_ids = json.loads(request.args["ids"])
-        job_ids = request_ids if auto_validate_ids is None else [jid for jid in request_ids if jid in jobs.ids()]
-        try:
-            for jid in job_ids:
-                jobs_info.append(get_job_info(jid))
-            return jsonify(jobs_info)
-        except Exception as err:
-            return jsonify({"success": False, "message": str(err)}), 400
-
-    # All jobs info
-    try:
-        # Filter jobs according to the jobs filter
-        jobs_filtered = list(jobs.select(**{key: jobs_filter[key] for key in jobs_filter.keys() if
-                                            jobs_filter[key] not in ["any", None]}))
-
-        # Reverse if list if recent parameter in url is present
-        if range_filter["recent"] is not None:
-            jobs_filtered.reverse()
-
-        # Jobs range filter
-        if range_filter["length"] is None:
-            jobs_slice = slice(None, None)
-        else:
-            start = int(range_filter["offset"]) * int(range_filter["length"])
-            end = start + int(range_filter["length"])
-            jobs_slice = slice(start, end)
-
-        # Add job information in the list
-        for j in jobs_filtered[jobs_slice]:
-            jobs_info.append(get_job_info(j.id))
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(jobs_info)
-
-
-# Get jobs length
-@internal.route("/internal/jobs/length", methods=["GET"])
-def jobs_length():
-    """
-    Return the number of jobs after applying the select filter.
-    :return: json
-    """
-
-    from GangaCore.GPI import jobs
-
-    # Jobs filter
-    jobs_filter = {
-        "status": request.args.get("status"),
-        "application": request.args.get("application"),
-        "backend": request.args.get("backend")
-    }
-
-    try:
-        # Number of jobs in the filter
-        jobs_len = len(jobs.select(**{key: jobs_filter[key] for key in jobs_filter.keys() if
-                                      jobs_filter[key] not in ["any", None]}))
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(jobs_len)
-
-
-# Jobs statistics
-@internal.route("/internal/jobs/statistics", methods=["GET"])
-def jobs_statistics():
-    from GangaCore.GPI import jobs
-
-    statistics = {}
-
-    try:
-        # Store statistics
-        for stat in ["new", "running", "completed", "failed", "killed"]:
-            statistics[stat] = len(jobs.select(status=stat))
-            if stat == "completed":
-                statistics[stat] += len(jobs.select(status="completed_frozen"))
-            elif stat == "failed":
-                statistics[stat] += len(jobs.select(status="failed_frozen"))
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(statistics)
-
-# Queue Information
-@internal.route("/internal/queue", methods=["GET"])
-def queue_api():
-
-    from GangaCore.Core.GangaThread.WorkerThreads import _global_queues as queues
-
-    queues_info=[]
-    com="idle"
-    for elem in queues._user_threadpool.get_queue():
-        user_queue={}
-        user_queue["user_threadpool"]=str(elem).strip("'<>() ").replace('\'', '\"')
-        queues_info.append(user_queue)
-
-    for elem in queues._monitoring_threadpool.get_queue():
-        monitor_queue={}
-        monitor_queue["monitoring_threadpool"]=str(elem).strip("'<>() ").replace('\'', '\"')
-        queues_info.append(monitor_queue)
-
-    for u, m in zip(queues._user_threadpool.worker_status(), queues._monitoring_threadpool.worker_status()):
-        queue_info={}
-        queue_info["name_user"]=str(u[0]).strip("'<>() ").replace('\'', '\"')
-        queue_info["name_monitor"]=str(m[0]).strip("'<>() ").replace('\'', '\"')
-
-        if u[1] is None:
-            queue_info["user_condition"]=str(com).strip("'<>() ").replace('\'', '\"')
-        elif u[1] is not None:
-            queue_info["user_condition"]=str(u[1]).strip("'<>() ").replace('\'', '\"')
-        if m[1] is None:
-            queue_info["monitor_condition"]=str(com).strip("'<>() ").replace('\'', '\"')
-        elif m[1] is not None:
-            queue_info["monitor_condition"]=str(m[1]).strip("'<>() ").replace('\'', '\"')
-        
-        queue_info["user_timeout"]=str(u[2]).strip("'<>() ").replace('\'', '\"')
-        queue_info["monitor_timeout"]=str(m[2]).strip("'<>() ").replace('\'', '\"')
-        queues_info.append(queue_info)
-        
-    return jsonify(queues_info)
-
-@internal.route("/internal/queue/data", methods=["GET", "POST"])
-def queue_chart_api():
-
-    from GangaCore.Core.GangaThread.WorkerThreads import _global_queues as queues
-    cdata = []
-    com="idle"
-    for u, m in zip(queues._user_threadpool.worker_status(), queues._monitoring_threadpool.worker_status()):
-        c_info={}
-        if u[1] is None:
-            c_info["user_condition"]=str(com).strip("'<>() ").replace('\'', '\"')
-        elif u[1] is not None:
-            c_info["user_condition"]=str(u[1]).strip("'<>() ").replace('\'', '\"')
-        cdata.append(c_info)
-        
-
-    count=0
-    for i in range(len(cdata)):
-        flag=cdata[0]
-        if flag["user_condition"] == com:
-            count+=1
-
-    dat = [time() * 1000, (len(cdata)-count)]
-    response = make_response(json.dumps(dat))
-    response.content_type = 'application/json'
-    return response
-
-
-# Incomplete jobs ids
-@internal.route("/internal/jobs/incomplete-ids", methods=["GET"])
-def jobs_incomplete_ids():
-    from GangaCore.GPI import jobs
-
-    try:
-        # Incomplete IDs list
-        incomplete_ids_list = list(jobs.incomplete_ids())
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(incomplete_ids_list)
-
-
-# Recent jobs
-@internal.route("/internal/jobs/recent", methods=["GET"])
-def jobs_recent():
-    """
-    Returns information about 10 recent jobs in JSON format
-    :return: json
-    """
-
-    from GangaCore.GPI import jobs
-
-    recent_jobs_info = []
-
-    try:
-        # Store information of 10 recent jobs
-        recent_jobs = jobs[-10:]
-        for j in recent_jobs:
-            recent_jobs_info.append(get_job_info(j.id))
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(recent_jobs_info)
-
-
-# ******************** Internal Config API Routes ******************** #
-
-# Config information
-@internal.route("/internal/config", methods=["GET"], defaults={"section": ""})
-@internal.route("/internal/config/<section>", methods=["GET"])
-def config_information(section: str):
-    """
-    Returns config information like section, section docstring, options, options docstring and their effective value in JSON format.
-    :param section: str
-    :return: json
-    """
-
-    from GangaCore.GPI import config
-    from GangaCore.Utility.Config import getConfig
-
-    # To store info of config
-    config_info = []
-
-    # List of config sections
-    sections_list = config
-
-    if section != "" and section in config:
-        sections_list = [section]
-
-    # Get each section information and append to the list
-    for section in sections_list:
-
-        config_section = getConfig(section)
-        options_list = []
-
-        # Get options information for the particular config section
-        for o in config_section.options.keys():
-            options_list.append({
-                "name": str(config_section.options[o].name),
-                "value": str(config_section.options[o].value),
-                "docstring": str(config_section.options[o].docstring),
-            })
-
-        # Append config section data to the list
-        config_info.append({
-            "name": str(config_section.name),
-            "docstring": str(config_section.docstring),
-            "options": options_list,
-        })
-
-    return jsonify(config_info)
-
-
-# ******************** Internal Templates API Routes ******************** #
-
-# Get templates information
-@internal.route("/internal/templates", methods=["GET"])
-def templates_information():
-    """
-    Return a list of templates information in JSON format according to select filter and range filter. Read GUI API docstring for more information.
-    :return: json
-    """
-
-    from GangaCore.GPI import templates
-
-    # Templates select filter
-    templates_filter = {
-        "application": request.args.get("application"),
-        "backend": request.args.get("backend")
-    }
-
-    # Range filter
-    range_filter = {
-        "recent": request.args.get("recent"),
-        "length": request.args.get("length"),
-        "offset": request.args.get("offset") if request.args.get("offset") is not None else 0,
-    }
-
-    templates_info = []
-
-    try:
-        # Filtered templates according to templates select filter
-        templates_filtered = list(templates.select(**{key: templates_filter[key] for key in templates_filter.keys() if
-                                                      templates_filter[key] not in ["any", None]}))
-
-        # Reverse if recent parameter is present
-        if range_filter["recent"] is not None:
-            templates_filtered.reverse()
-
-        # Templates range filter
-        if range_filter["length"] is None:
-            templates_slice = slice(None, None)
-        else:
-            start = int(range_filter["offset"]) * int(range_filter["length"])
-            end = start + int(range_filter["length"])
-            templates_slice = slice(start, end)
-
-        # Add individual templates information to the list
-        for t in templates_filtered[templates_slice]:
-            templates_info.append(get_template_info(t.id))
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(templates_info)
-
-
-# Full print of the template
-@internal.route("/internal/templates/<int:template_id>/full-print", methods=["GET"])
-def template_full_print(template_id: int):
-    """
-    Return full print of the template.
-    :param template_id: int
-    :return: json
-    """
-
-    from GangaCore.GPI import templates, full_print
-
-    try:
-        # Store full print of the template in a file like object
-        print_output = io.StringIO()
-        full_print(templates(template_id), out=print_output)
-        full_print_info = print_output.getvalue()
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(full_print_info)
-
-
-# Templates length
-@internal.route("/internal/templates/length", methods=["GET"])
-def templates_length():
-    """
-    Returns length of templates after applying the select filter
-    """
-
-    from GangaCore.GPI import templates
-
-    # Templates filter
-    templates_filter = {
-        "application": request.args.get("application"),
-        "backend": request.args.get("backend")
-    }
-
-    try:
-        # Length of templates using the templates select filter
-        templates_len = len(templates.select(**{key: templates_filter[key] for key in templates_filter.keys() if
-                                                templates_filter[key] not in ["any", None]}))
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(templates_len)
-
-
-# Template delete
-@internal.route("/internal/templates/<int:template_id>", methods=["DELETE"])
-def template_delete(template_id: int):
-    """
-    Delete template from the template repository.
-    :param template_id: int
-    """
-
-    from GangaCore.GPI import templates
-
-    try:
-        # Remove template
-        t = templates[template_id]
-        t.remove()
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify({"success": True, "message": "Template with ID {} removed successfully".format(template_id)})
-
-
-# ******************** Internal Credentials API Routes ******************** #
-
-# Credentials information
-@internal.route("/internal/credentials", methods=["GET"])
-def credentials_information():
-    """
-    Return credentials information in JSON format.
-    :return: json
-    """
-
-    from GangaCore.GPI import credential_store
-
-    # Store credential store info in a list
-    credentials_info = []
-
-    try:
-        for c in credential_store:
-            credential_info = {}
-            credential_info["location"] = str(c.location)
-            credential_info["time_left"] = str(c.time_left())
-            credential_info["expiry_time"] = str(c.expiry_time())
-            credential_info["is_valid"] = str(c.is_valid())
-            credential_info["exists"] = str(c.exists())
-            credentials_info.append(credential_info)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(credentials_info)
-
-
-# Renew credentials
-@internal.route("/internal/credentials/renew", methods=["PUT"])
-def credentials_renew():
-    """
-    Renew credentials
-    :return: json
-    """
-
-    from GangaCore.GPI import credential_store
-
-    try:
-        # Renew credentials
-        credential_store.renew()
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify({"success": True, "message": "Credentials successfully renewed"})
-
-
-# ******************** Job Tree API ******************** #
-
-# Job tree
-@internal.route("/internal/jobtree", methods=["GET"])
-def jobtree_information():
-    """
-    Return the job tree folder structure as the json format of python dict.
-    """
-
-    from GangaCore.GPI import jobtree
-
-    try:
-        # Reset job tree to root of job repository
-        jobtree.cd()
-
-        # Return the jobtree folder structure
-        return jsonify(jobtree.folders)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-
-# ******************** Internal Plugins API Routes ******************** #
-
-# Get plugins information
-@internal.route("/internal/plugins", methods=["GET"])
-def plugins_information():
-    """
-    Returns information of plugins catergory and plugins in JSON format.
-    :return: json
-    """
-
-    from GangaCore.GPI import plugins
-
-    try:
-        # Get plugins information
-        plugins_info = plugins()
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(plugins_info)
-
-
-@internal.route("/internal/plugins/<plugin_name>", methods=["GET"])
-def plugin_information(plugin_name: str):
-    """
-    Returns specific information about the plugin like name and docstring
-
-    :param plugin_name: str
-    :return: json
-    """
-
-    from GangaCore import GPI
-
-    try:
-        # Get plugin
-        plugin = getattr(GPI, plugin_name)
-        plugin_info = {
-            "name": plugin_name,
-            "docstring": plugin.__doc__
-        }
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(plugin_info)
-
-
-# ******************** Internal Other API Routes ******************** #
-
-# Job actions list
-@internal.route("/internal/jobs/actions", methods=["GET"])
-def actions():
-    """
-    Returns information about the attribute and methods available for the Job object.
-    :return: json
-    """
-
-    from GangaCore.GPIDev.Lib.Job import Job
-
-    try:
-        # Get attribute and method information from the scheme of the Job class
-        actions = {
-            "attributes": Job._schema.allItemNames(),
-            "methods": Job._exportmethods
-        }
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(actions)
-
-
-# Load file using the load function from GPI
-@internal.route("/internal/load", methods=["GET"])
-def load_file():
-    """
-    Load the ganga object from the file path provided in the parameter.
-    NOTE: Need to provide 'path' as a parameter to the request
-    :return: json
-    """
-
-    from GangaCore.GPI import load
-
-    # Path from the request argument
-    path = request.args.get("path")
-
-    try:
-        # Load using the load function of ganga GPI
-        load(path)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify({"success": True, "message": "Successfully loaded the file."})
-
-
-# Run file using the runfile function from GPI
-@internal.route("/internal/runfile", methods=["GET"])
-def run_file():
-    """
-    Run the file from the path provided in the request argument.
-    Note: you need to provide the 'path' of the file to the request as parameter.
-    :return:
-    """
-
-    from GangaCore.GPI import runfile
-
-    # Get file path from the request argument
-    path = request.args.get("path")
-
-    try:
-        # Run file using the runfile funcition on ganga GPI
-        runfile(path)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify({"success": True, "message": "Successfully ran the file."})
-
-
-# Ping route to check if server is online
-@internal.route("/ping")
-def ping():
-    return jsonify(True)
-
-
-# ******************** Helper Functions ******************** #
-
-def get_job_info(job_id: int) -> dict:
-    """
-    Given the job_id, return a dict containing
-    [id, fqid, status, name, subjobs, application, backend, backend.actualCE, comments, subjob_statuses, outputdir, inputdir] info of the job.
-
-    :param job_id: int
-    :return: dict
-    """
-
-    from GangaCore.GPI import jobs
-
-    j = jobs[int(job_id)]
-
-    # Store job info in a dict
-    job_info = {}
-    for attr in ["id", "fqid", "status", "name", "subjobs", "application", "backend", "comment", "outputdir",
-                 "inputdir"]:
-        job_info[attr] = str(getattr(j, attr))
-    job_info["backend.actualCE"] = str(j.backend.actualCE)
-    job_info["subjob_statuses"] = str(j.returnSubjobStatuses())
-    job_info["subjobs"] = str(len(j.subjobs))
-
-    return job_info
-
-
-def get_subjob_info(job_id: int, subjob_id: int) -> dict:
-    """
-    Given job_id and subjob_id, return a dict container general information about the subjob.
-
-    :param job_id: int
-    :param subjob_id: int
-    :return: dict
-    """
-
-    from GangaCore.GPI import jobs
-
-    j = jobs(int(job_id))
-    sj = j.subjobs[int(subjob_id)]
-
-    # Store subjob info in a dict
-    subjob_info = {}
-    for attr in ["id", "fqid", "status", "name", "application", "backend", "comment", "outputdir", "inputdir"]:
-        subjob_info[attr] = str(getattr(sj, attr))
-    subjob_info["backend.actualCE"] = str(sj.backend.actualCE)
-
-    return subjob_info
-
-
-def get_template_info(template_id: int) -> dict:
-    """
-    Given the template_id, return a dict containing general info of the template.
-
-    :param template_id: int
-    :return: dict
-    """
-
-    from GangaCore.GPI import jobs, templates
-
-    t = templates[int(template_id)]
-
-    # Store template info in a dict
-    template_info = {}
-    for attr in ["id", "fqid", "name", "application", "backend", "comment"]:
-        template_info[attr] = str(getattr(t, attr))
-    template_info["backend.actualCE"] = str(t.backend.actualCE)
-
-    return template_info
-
-
-# ******************** Shutdown Function ******************** #
-
-# Route used to shutdown the Internal API flask server running on GangaThread [INTERNAL ROUTE DONT USE, USE /shutdown GET ROUTE]
-@internal.route("/shutdown", methods=["POST"])
-def _shutdown():
-    func = request.environ.get("werkzeug.server.shutdown")
-    func()
-    response_data = {"success": True, "message": "Shutting down the server..."}
-    return jsonify(response_data)
-
-
-# Route used to shutdown the Internal API flask server and GUI server. [USE THIS]
-@internal.route("/shutdown", methods=["GET"])
-def shutdown():
-
-    from GangaGUI.start import stop_gui
-    stop_gui()
-
-    return jsonify({"success": True, "message": "Shutdown Successful."})
-
-# ******************** EOF ******************** #
diff --git a/ganga/GangaGUI/gui/__init__.py b/ganga/GangaGUI/gui/__init__.py
deleted file mode 100644
index 8b13789179..0000000000
--- a/ganga/GangaGUI/gui/__init__.py
+++ /dev/null
@@ -1,1 +0,0 @@
-
diff --git a/ganga/GangaGUI/gui/config.py b/ganga/GangaGUI/gui/config.py
deleted file mode 100644
index 8d84fbb3a1..0000000000
--- a/ganga/GangaGUI/gui/config.py
+++ /dev/null
@@ -1,52 +0,0 @@
-"""Contains the configuration settings for the GUI Flask App"""
-
-import os
-
-from GangaCore import getConfig
-
-# Directories
-gangadir = getConfig("Configuration")["gangadir"]
-ganga_logfile = getConfig("Logging")["_logfile"]
-gangarc_file = getConfig("System")["GANGA_CONFIG_FILE"]
-gui_dir = os.path.join(gangadir, "gui")
-
-# Make GUI folder if doesn't exist
-if not os.path.exists(gui_dir):
-    os.makedirs(gui_dir)
-
-# Make GUI essential folders
-for dir_name in ["upload", "logs", "storage"]:
-    dir_path = os.path.join(gui_dir, dir_name)
-    if not os.path.exists(dir_path):
-        os.makedirs(dir_path)
-
-
-class Config(object):
-    SECRET_KEY = os.urandom(24)
-
-    # Database related configuration
-    SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(gui_dir, "gui.sqlite")
-    SQLALCHEMY_TRACK_MODIFICATIONS = False
-
-    # GUI specific config
-    UPLOAD_FOLDER = os.path.join(gui_dir, "upload")
-    GUI_FOLDER = gui_dir
-    LOGS_FOLDER = os.path.join(gui_dir, "logs")
-    STORAGE_FOLDER = os.path.join(gui_dir, "storage")
-    
-
-    # Logs config
-    ACCESS_LOG = os.path.join(LOGS_FOLDER, "gui_access.log")
-    ERROR_LOG = os.path.join(LOGS_FOLDER, "gui_error.log")
-    GANGA_RC = gangarc_file
-    GANGA_LOG = os.path.expanduser(ganga_logfile)
-    
-
-    # Web CLI related config
-    WEB_CLI = False
-    GANGA_ARGS = ""
-    INTERNAL_PORT = None
-
-    # To store pseudo terminal file descriptor (connected to the child’s controlling terminal) and child pid
-    FD = None
-    CHILD_PID = None
diff --git a/ganga/GangaGUI/gui/routes.py b/ganga/GangaGUI/gui/routes.py
deleted file mode 100644
index 335823de3e..0000000000
--- a/ganga/GangaGUI/gui/routes.py
+++ /dev/null
@@ -1,1963 +0,0 @@
-import os
-import jwt
-import json
-import requests
-import time
-import select
-import termios
-import struct
-import fcntl
-import subprocess
-import pty
-import sys
-import datetime
-from functools import wraps
-from werkzeug.utils import secure_filename, safe_join
-from werkzeug.security import generate_password_hash, check_password_hash
-from flask import Flask, request, jsonify, render_template, flash, redirect, url_for, session, send_file, make_response
-from flask_login import login_user, login_required, logout_user, current_user, UserMixin
-from flask_sqlalchemy import SQLAlchemy
-from flask_login import LoginManager
-from flask_socketio import SocketIO
-from GangaGUI.gui.config import Config
-
-# ******************** Initialisation of Flask App for GUI ******************** #
-
-
-# GUI Flask App and set configuration from ./config.py file
-gui = Flask(__name__)
-gui.config.from_object(Config)
-
-# Database object which is used to interact with the "gui.sqlite" in gangadir/gui folder
-# NOTE: IT HAS NO RELATION WITH THE GANGA PERSISTENT DATABASE
-db = SQLAlchemy(gui)
-
-# Login manage for the view routes
-login = LoginManager(gui)
-login.login_view = "login"
-login.login_message = "Please Login to Access this Page."
-login.login_message_category = "warning"
-
-# For websocket, for communication between frontend and backend
-socketio = SocketIO(gui)
-
-
-# ******************** The user class for database and authentication ******************** #
-
-# ORM Class to represent Users - used to access the GUI & API resources
-class User(UserMixin, db.Model):
-    __tablename__ = "users"
-    id = db.Column(db.Integer, primary_key=True)
-    public_id = db.Column(db.String(64), unique=True)
-    user = db.Column(db.String(32), unique=True)
-    password_hash = db.Column(db.String(64))
-    role = db.Column(db.String(32))
-    pinned_jobs = db.Column(db.Text)
-
-    def store_password_hash(self, password: str):
-        self.password_hash = generate_password_hash(password)
-
-    def verify_password(self, password: str) -> bool:
-        return check_password_hash(self.password_hash, password)
-
-    def generate_auth_token(self, expires_in_days: int = 5) -> str:
-        return jwt.encode(
-            {"public_id": self.public_id, "exp": datetime.datetime.utcnow() + datetime.timedelta(days=expires_in_days)},
-            gui.config["SECRET_KEY"], algorithm="HS256")
-
-    def __repr__(self):
-        return "User {}: {} (Public ID: {}, Role: {})".format(self.id, self.user, self.public_id, self.role)
-
-
-# User Loader Function for Flask Login
-@login.user_loader
-def load_user(user_id):
-    return User.query.get(int(user_id))
-
-
-# ******************** Global Variables ******************** #
-
-
-# Colors showed for different job statuses in the GUI based on Bootstrap CSS
-status_color = {
-    "new": "info",
-    "completed": "success",
-    "completed_frozen" : "success",
-    "failed": "danger",
-    "failed_frozen" : "danger",
-    "running": "primary",
-    "submitted": "secondary",
-    "killed": "warning"
-}
-
-# Allowed extensions when uploading any files to GUI
-ALLOWED_EXTENSIONS = {"txt", "py"}
-
-# Variables to globally store plugins and actions
-actions = {}
-plugins = {}
-
-
-# ******************** Run Before First Request ******************** #
-
-
-# Execute before first request
-@gui.before_first_request
-def initial_run():
-    """
-    This function runs before first request. It stores actions and plugins information from the ganga. It create default session cookies. If WEB_CLI is also started then it also starts a Ganga session.
-    """
-
-    global actions, plugins
-
-    # Start ganga if WEB_CLI mode is True
-    if gui.config['WEB_CLI'] is True:
-        start_ganga(gui.config['INTERNAL_PORT'], args=gui.config["GANGA_ARGS"])
-        session["WEB_CLI"] = True
-    elif gui.config['INTERNAL_PORT'] is None:
-        gui.config['INTERNAL_PORT'] = os.environ['INTERNAL_PORT']
-
-    # If user is authenticated, log them out. This happens after a fresh start of the GUI server.
-    if current_user.is_authenticated:
-        logout_user()
-
-    # Create user session defaults
-    create_session_defaults()
-
-    # Check if internal server is online, exit after 20s of retrying
-    if not ping_internal():
-        print("INTERNAL SERVER UNAVAILABLE, TERMINATING...")
-        sys.exit(1)
-
-    # Get job actions and plugins information from ganga
-    try:
-        # Get actions and plugins data once
-        actions = query_internal_api("/internal/jobs/actions", "get")
-        plugins = query_internal_api("/internal/plugins", "get")
-    except Exception as err:
-        flash(str(err), "danger")
-        return redirect(url_for("dashboard"))
-
-
-# ******************** View Routes ******************** #
-
-
-# Login View
-@gui.route("/login", methods=["GET", "POST"])
-def login():
-    """
-    Handles login route of the GUI.
-    """
-
-    # If already authenticated, logout
-    if current_user.is_authenticated:
-        return redirect(url_for("dashboard"))
-
-    # Login user
-    if request.method == "POST":
-
-        # Form data
-        username = request.form.get("username")
-        password = request.form.get("password")
-
-        # Database query
-        user = User.query.filter_by(user=username).first()
-
-        # If valid user, login
-        if user and user.verify_password(password):
-            login_user(user, True)
-            flash("Login successful", "success")
-            return redirect(url_for("dashboard"))
-
-        flash("Error identifying the user", "danger")
-
-    # Get users from the database
-    users = User.query.all()
-
-    return render_template("login.html", title="Login", users=users)
-
-
-# Logout View
-@gui.route("/logout", methods=["GET"])
-def logout():
-    """
-    Logout user from GUI
-    """
-
-    # Logout
-    if current_user.is_authenticated:
-        logout_user()
-
-    return redirect(url_for("login"))
-
-
-# Dashboard view
-@gui.route("/")
-@login_required
-def dashboard():
-    """
-    Handles the dashboard route of the GUI.
-    """
-
-    quick_statistics = {}
-    recent_jobs_info = []
-    pinned_jobs_info = []
-
-    try:
-        # Query overall statistics
-        quick_statistics = query_internal_api("/internal/jobs/statistics", "get")
-
-        # Query recent 10 jobs
-        recent_jobs_info = query_internal_api("/internal/jobs/recent", "get")
-
-        # Query pinned jobs
-        u = current_user
-        pinned_jobs_info = query_internal_api("/internal/jobs", "get", params={
-            "ids": u.pinned_jobs if u.pinned_jobs is not None else json.dumps([]),
-            "auto-validate-ids": True})
-
-    except Exception as err:
-        # Flash the error in the GUI
-        flash(str(err), "danger")
-
-    return render_template("dashboard.html",
-                           title="Dashboard",
-                           quick_statistics=quick_statistics,
-                           recent_jobs_info=recent_jobs_info,
-                           pinned_jobs_info=pinned_jobs_info,
-                           status_color=status_color)
-
-
-# Config view
-@gui.route("/config", methods=["GET", "POST"])
-@login_required
-def config_page():
-    """
-    Handles the config route of the GUI.
-    """
-
-    full_config_info = []
-    config_info = []
-    section = None
-
-    # When GUI request for specific section
-    if request.method == "POST":
-        # Get section name for request form data
-        section = request.form.get("section")
-        section = None if section in ["", None] else section
-
-    try:
-        # Query full config
-        full_config_info = query_internal_api("/internal/config", "get")
-
-        # If asked for specific section, add only that for displaying
-        config_info = full_config_info if section is None else [s for s in full_config_info if s["name"] == section]
-
-    except Exception as err:
-        # Flash the error in the GUI
-        flash(str(err), "danger")
-
-    return render_template("config.html", title="Config", full_config_info=full_config_info, config_info=config_info)
-
-#Edit gangarc
-@gui.route("/config_edit",methods=["GET", "POST"])
-@login_required
-def edit_config_page():
-    """
-    Edit gangarc file from the GUI
-    """
-    gui_rc = gui.config["GANGA_RC"]
-    with open(gui_rc, "rt") as f:
-        ganga_config = f.read()
-    if request.method == 'POST':
-        config_ganga = request.form['config-data']
-        with open(gui_rc, 'w') as f1:
-            f1.write(str(config_ganga))
-        flash(".gangarc Edited", "success")
-        with open(gui_rc, "rt") as f2:
-            ganga_config = f2.read()
-    return render_template("config_edit.html", title="Edit gangarc", ganga_config=ganga_config)
-    
-@login_required
-# Create view
-@gui.route("/create", methods=["GET", "POST"])
-def create_page():
-    """
-    Handles create route of the GUI.
-    """
-
-    # Handle file uploads
-    if request.method == "POST":
-
-        # Load from the uploaded file
-        if "loadfile" in request.files:
-            loadfile = request.files["loadfile"]
-            if loadfile.filename == "":
-                flash("No file selected", "warning")
-                return redirect(request.url)
-
-            # If valid file, the save the file
-            if loadfile and allowed_file(loadfile.filename):
-                save_path = os.path.join(gui.config["UPLOAD_FOLDER"], "loadfile.txt")
-                loadfile.save(save_path)
-
-                # Load the file
-                try:
-                    # Query to load the file
-                    response_info = query_internal_api("/internal/load", "get", params={"path": save_path})
-
-                except Exception as err:
-                    # Display error in the GUI
-                    flash(str(err), "danger")
-                    return redirect(request.url)
-
-                # Success message
-                flash(response_info.get("message"), "success")
-                return redirect(request.url)
-
-        # Run file using the runfile GPI function
-        if "runfile" in request.files:
-            runfile = request.files["runfile"]
-            if runfile.filename == "":
-                flash("No file selected", "warning")
-                return redirect(request.url)
-
-            # If valid file, save the file
-            if runfile and allowed_file(runfile.filename):
-                save_path = os.path.join(gui.config["UPLOAD_FOLDER"], "runfile.py")
-                runfile.save(save_path)
-
-                # Run the file
-                try:
-                    # Query ganga to run the file
-                    response_info = query_internal_api("/internal/runfile", "get", params={"path": save_path})
-
-                except Exception as err:
-                    # Display error back to GUI
-                    flash(str(err), "danger")
-                    return redirect(request.url)
-
-                # Success message
-                flash(response_info.get("message"), "success")
-                return redirect(request.url)
-
-        # No file case
-        flash("No file, retry!", "warning")
-        return redirect(request.url)
-
-    try:
-        # Query templates info
-        templates_info = query_internal_api("/internal/templates", "get",
-                                            params={"recent": True, "length": "6"})
-
-    except Exception as err:
-        # Display error to GUI
-        flash(str(err), "danger")
-        return redirect(url_for("dashboard"))
-
-    return render_template("create.html", title="Create", templates_info=templates_info)
-
-
-# Runfile view
-@gui.route("/create/runfile", methods=["GET", "POST"])
-@login_required
-def runfile_page():
-    """
-    Quick create a runfile to be run using the runfile GPI function.
-    """
-
-    # Runfile path
-    runfile_path = os.path.join(gui.config["UPLOAD_FOLDER"], "runfile.py")
-
-    # Save runfile data from frontend
-    if request.method == "POST":
-        runfile_data = request.form.get("runfile-data")
-        with open(runfile_path, "w+") as f:
-            f.write(runfile_data)
-
-        # Run the file
-        try:
-            # Query ganga to run the file
-            response_info = query_internal_api("/internal/runfile", "get", params={"path": runfile_path})
-            flash(response_info["message"], "success")
-
-        except Exception as err:
-            # Display error back in the GUI
-            flash(str(err), "danger")
-            return redirect(request.url)
-
-    return render_template("runfile.html", title="Runfile")
-
-
-# Templates view
-@gui.route("/templates", methods=["GET", "POST"])
-@login_required
-def templates_page():
-    """
-    Handles the templates route of the GUI. Displays templates in a tabular form.
-    """
-
-    # Update filter values
-    if request.method == "POST":
-        # Add filter data to user session
-        session["templates_per_page"] = int(request.form.get("templates-per-page"))
-        session["templates_filter"] = {key: request.form.get(form_name) for key, form_name in
-                                       zip(["application", "backend"], ["template-application", "template-backend"])}
-
-    # Current page
-    current_page = int(request.args.get("page")) if request.args.get("page") is not None else 0
-
-    # Get user defined value from session
-    templates_per_page = session["templates_per_page"]
-
-    try:
-
-        # Query total number of templates
-        templates_length = query_internal_api("/internal/templates/length", "get", params=session["templates_filter"])
-
-        # Calculate number of max pages
-        number_of_pages = (int(templates_length) // int(templates_per_page)) + 1
-
-        # if current page exceeds last possible page, redirect to last page
-        if current_page >= number_of_pages:
-            return redirect(url_for("templates_page", page=number_of_pages - 1))
-
-        # Add templates filters and range options for query params
-        params = session["templates_filter"].copy()
-        params.update({
-            "recent": True,
-            "length": templates_per_page,
-            "offset": current_page
-        })
-
-        # Query templates information
-        templates_info = query_internal_api("/internal/templates", "get", params=params)
-
-    except Exception as err:
-        # Flash error if any
-        flash(str(err), "danger")
-        return redirect(url_for("create_page"))
-
-    return render_template("templates.html",
-                           title="Templates",
-                           number_of_pages=number_of_pages,
-                           current_page=current_page,
-                           backends=plugins["backends"],
-                           applications=plugins["applications"],
-                           templates_info=templates_info)
-
-
-# Jobs view
-@gui.route("/jobs", methods=["GET", "POST"])
-@login_required
-def jobs_page():
-    """
-    Handles jobs route of the GUI. Displays jobs in a tabular view.
-    """
-
-    # Update filter values
-    if request.method == "POST":
-        # Add form data to user session
-        session["jobs_per_page"] = int(request.form.get("jobs-per-page"))
-        session["jobs_filter"] = {key: request.form.get(form_name) for key, form_name in
-                                  zip(["status", "application", "backend"],
-                                      ["job-status", "job-application", "job-backend"])}
-
-    # Current page
-    current_page = int(request.args.get("page")) if request.args.get("page") is not None else 0
-
-    # Get user defined value from user session
-    jobs_per_page = session["jobs_per_page"]
-
-    try:
-
-        # Query total number of jobs
-        jobs_length = query_internal_api("/internal/jobs/length", "get", params=session["jobs_filter"])
-
-        # Calculate number of max pages
-        number_of_pages = (int(jobs_length) // int(jobs_per_page)) + 1
-
-        # if current page exceeds last possible page, redirect to last page
-        if current_page >= number_of_pages:
-            return redirect(url_for("jobs_page", page=number_of_pages - 1))
-
-        # Add jobs filters and range options for query params
-        params = session["jobs_filter"].copy()
-        params.update({
-            "recent": True,
-            "length": jobs_per_page,
-            "offset": current_page
-        })
-
-        # Query jobs information
-        jobs_info = query_internal_api("/internal/jobs", "get", params=params)
-
-    except Exception as err:
-        # Display error back to GUI
-        flash(str(err), "danger")
-        return redirect(url_for("dashboard"))
-
-    return render_template("jobs.html",
-                           title="Jobs",
-                           jobs_info=jobs_info,
-                           backends=plugins["backends"],
-                           applications=plugins["applications"],
-                           number_of_pages=number_of_pages,
-                           current_page=current_page,
-                           status_color=status_color)
-
-
-# Job view
-@gui.route('/jobs/<int:job_id>')
-@login_required
-def job_page(job_id: int):
-    """
-    Handles job route of the GUI. Displays all the information about the job.
-    :param job_id: int
-    """
-
-    stdout = None
-    stderr = None
-
-    try:
-
-        # Query job information
-        job_info = query_internal_api(f"/internal/jobs/{job_id}", "get")
-
-        # Query full print of the job
-        full_print_info = query_internal_api(f"/internal/jobs/{job_id}/full-print", "get")
-
-        # stdout and stderr path
-        stdout_path = os.path.join(job_info["outputdir"], "stdout")
-        stderr_path = os.path.join(job_info["outputdir"], "stderr")
-
-        # Get stdout
-        if os.path.exists(stdout_path):
-            with open(stdout_path) as f:
-                stdout = f.read()
-
-        # Get stderr
-        if os.path.exists(stderr_path):
-            with open(stderr_path) as f:
-                stderr = f.read()
-
-    except Exception as err:
-        # Display error on the GUI
-        flash(str(err), "danger")
-        return redirect(url_for("jobs_page"))
-
-    return render_template("job.html",
-                           title=f"Job {job_id}",
-                           job_info=job_info,
-                           status_color=status_color,
-                           attribute_actions=actions.get("attributes"),
-                           method_actions=actions.get("methods"),
-                           stdout=stdout,
-                           stderr=stderr,
-                           full_print_info=full_print_info)
-
-
-# Export job
-@gui.route("/jobs/<int:job_id>/export")
-@login_required
-def job_export(job_id: int):
-    """
-    Sends the job file which is generated using export function of GPI.
-    :param job_id: int
-    """
-
-    # Path to save file using export GPI function
-    export_path = os.path.join(gui.config["UPLOAD_FOLDER"], f"export.txt")
-
-    try:
-
-        # Query to export the job at export path
-        response_info = query_internal_api(f"/internal/jobs/{job_id}/export", "get", params={"path": export_path})
-
-        # Send file
-        return send_file(export_path, as_attachment=True, cache_timeout=0, attachment_filename=f"Job_{job_id}.txt")
-
-    except Exception as err:
-        # Display error back to GUI
-        flash(str(err), "danger")
-
-    return redirect(url_for("job_page", job_id=job_id))
-
-
-# Edit job
-@gui.route("/jobs/<int:job_id>/edit", methods=["GET", "POST"])
-@login_required
-def job_edit(job_id: int):
-    """
-    Show the exported job text on the GUI for it to be edited and submit. Will create a new job after submission.
-    :param job_id: int
-    """
-
-    # Save paths
-    loadfile_path = os.path.join(gui.config["UPLOAD_FOLDER"], "loadfile.txt")
-    export_path = os.path.join(gui.config["UPLOAD_FOLDER"], "export.txt")
-
-    # Create a new job with the submitted information
-    if request.method == "POST":
-
-        # Save the edited job info
-        edited_job_info = request.form.get("edited-job-info")
-        with open(loadfile_path, "w+") as f:
-            f.write(edited_job_info)
-
-        # Load the file
-        try:
-            # Query to load the job
-            response_info = query_internal_api("/internal/load", "get", params={"path": loadfile_path})
-            flash(response_info["message"], "success")
-
-        except Exception as err:
-            # Display error on the GUI
-            flash(str(err), "danger")
-            return redirect(request.url)
-
-    try:
-        # Query to export the job text
-        response_info = query_internal_api(f"/internal/jobs/{job_id}/export", "get", params={"path": export_path})
-
-        # Read exported job file to display
-        with open(export_path) as f:
-            exported_data = f.read()
-
-    except Exception as err:
-        # Display error on the GUI
-        flash(str(err), "danger")
-        return redirect(url_for("job_page", job_id=job_id))
-
-    return render_template("edit_job.html", title=f"Edit Job {job_id}", job_id=job_id, exported_data=exported_data)
-
-
-# Browse job directory
-@gui.route("/job/<int:job_id>/browse", defaults={"path": ""})
-@gui.route("/job/<int:job_id>/browse/<path:path>")
-@login_required
-def job_browse(job_id: int, path):
-    """
-    Browse directory of the job.
-    :param job_id: int
-    :param path: str
-    """
-
-    try:
-        # Query job information
-        job_info = query_internal_api(f"/internal/jobs/{job_id}", "get")
-
-        # Base directory of the job
-        job_base_dir = os.path.dirname(os.path.dirname(job_info["outputdir"]))
-
-    except Exception as err:
-        # Display error on the GUI
-        flash(str(err), "danger")
-        return redirect(url_for("job_page", job_id=job_id))
-
-    # Join the base and the requested path
-    abs_path = safe_join(job_base_dir, path)
-
-    # URL path variable for going back
-    back_path = os.path.dirname(abs_path).replace(job_base_dir, "")
-
-    # If path doesn't exist
-    if not os.path.exists(abs_path):
-        flash("Directory for this job does not exist.", "warning")
-        return redirect(url_for("job_page", job_id=job_id))
-
-    # Check if path is a file and send
-    if os.path.isfile(abs_path):
-        return send_file(abs_path)
-
-    files_info = []
-
-    # Show directory contents
-    files = os.listdir(abs_path)
-
-    # Store directory information
-    for file in files:
-        files_info.append({
-            "file": file,
-            "directory": os.path.isdir(os.path.join(abs_path, file))
-        })
-
-    return render_template('job_dir.html', title=f"Job {job_id} Directory",
-                           job_id=job_id,
-                           abs_path=abs_path,
-                           files_info=files_info,
-                           back_path=back_path)
-
-
-# Subjobs view
-@gui.route("/jobs/<int:job_id>/subjobs", methods=["GET", "POST"])
-@login_required
-def subjobs_page(job_id: int):
-    """
-    Handles subjobs view of the GUI. Displays subjobs of a job in a tabular form.
-    :param job_id: int
-    """
-
-    # Change filter values
-    if request.method == "POST":
-        # Add form data to client session
-        session["subjobs_per_page"] = int(request.form.get("subjobs-per-page"))
-        session["subjobs_filter"] = {key: request.form.get(form_name) for key, form_name in
-                                     zip(["status", "application", "backend"],
-                                         ["subjob-status", "subjob-application", "subjob-backend"])}
-
-    # Current page
-    current_page = int(request.args.get("page")) if request.args.get("page") is not None else 0
-
-    # Get user defined value from session
-    subjobs_per_page = session["subjobs_per_page"]
-
-    try:
-        # Query total number of subjobs
-        subjobs_length = query_internal_api(f"/internal/jobs/{job_id}/subjobs/length", "get",
-                                            params=session["subjobs_filter"])
-
-        # Calculate number of max pages
-        number_of_pages = (int(subjobs_length) // int(subjobs_per_page)) + 1
-
-        # if current page exceeds last possible page, redirect to last page
-        if current_page >= number_of_pages:
-            return redirect(url_for("subjobs_page", page=number_of_pages - 1, job_id=job_id))
-
-        # Add subjobs filters and range options for query params
-        params = session["subjobs_filter"].copy()
-        params.update({
-            "recent": True,
-            "length": subjobs_per_page,
-            "offset": current_page
-        })
-
-        # Query subjobs information
-        subjobs_info = query_internal_api(f"/internal/jobs/{job_id}/subjobs", "get", params=params)
-
-    except Exception as err:
-        flash(str(err), "danger")
-        return redirect(url_for("job_page", job_id=job_id))
-
-    return render_template("subjobs.html",
-                           title=f"Subjobs - Job {job_id}",
-                           status_color=status_color,
-                           number_of_pages=number_of_pages,
-                           current_page=current_page,
-                           backends=plugins["backends"],
-                           applications=plugins["applications"],
-                           subjobs_info=subjobs_info,
-                           job_id=job_id)
-
-
-# Subjob view
-@gui.route("/jobs/<int:job_id>/subjobs/<int:subjob_id>", methods=["GET"])
-@login_required
-def subjob_page(job_id: int, subjob_id: int):
-    """
-    Handles subjob route of the GUI. Displays extensive details of a subjob.
-    :param job_id: int
-    :param subjob_id: int
-    """
-
-    stdout = None
-    stderr = None
-
-    try:
-
-        # Query job information
-        job_outputdir = query_internal_api(f"/internal/jobs/{job_id}/outputdir", "get")
-
-        # Query subjob information
-        subjob_info = query_internal_api(f"/internal/jobs/{job_id}/subjobs/{subjob_id}", "get")
-
-        # Query full print of the job
-        full_print_info = query_internal_api(f"/internal/jobs/{job_id}/subjobs/{subjob_id}/full-print", "get")
-
-        # Extract browse path that can be used by job_browse route
-        job_dir_basepath = os.path.dirname(os.path.dirname(job_outputdir["outputdir"]))
-        subjob_dir_basepath = os.path.dirname(os.path.dirname(subjob_info["outputdir"]))
-        browse_path = subjob_dir_basepath.replace(job_dir_basepath, "")
-
-        # stdout and stderr path
-        stdout_path = os.path.join(subjob_info["outputdir"], "stdout")
-        stderr_path = os.path.join(subjob_info["outputdir"], "stderr")
-
-        # Get stdout
-        if os.path.exists(stdout_path):
-            with open(stdout_path) as f:
-                stdout = f.read()
-
-        # Get stderr
-        if os.path.exists(stderr_path):
-            with open(stderr_path) as f:
-                stderr = f.read()
-
-    except Exception as err:
-        # Display error on the GUI
-        flash(str(err), "danger")
-        return redirect(url_for("subjobs_page", job_id=job_id))
-
-    return render_template("subjob.html",
-                           title=f"Subjob {subjob_id} - Job {job_id}",
-                           subjob_info=subjob_info,
-                           status_color=status_color,
-                           attribute_actions=actions["attributes"],
-                           method_actions=actions["methods"],
-                           stdout=stdout,
-                           stderr=stderr,
-                           full_print_info=full_print_info,
-                           job_id=job_id,
-                           browse_path=browse_path)
-
-
-# Credential view
-@gui.route("/credentials")
-@login_required
-def credentials_page():
-    """
-    Handles credential store view of the GUI. Displays credentials in a tabular form.
-    """
-
-    try:
-        # Query credential store information
-        credentials_info = query_internal_api("/internal/credentials", "get")
-
-    except Exception as err:
-        # Display error on the GUI
-        flash(str(err), "danger")
-        return redirect(url_for("dashboard"))
-
-    return render_template('credentials.html', credential_info_list=credentials_info)
-
-@gui.route("/queue", methods=["GET"])
-@login_required
-def queue_page():
-    """
-    Displays queues information
-    """
-    try:
-        queue_info = query_internal_api("/internal/queue", "get")
-    except Exception as err:
-        flash(str(err), "danger")
-        return redirect(url_for("dashboard"))
-
-    return render_template('queue.html', queue_info_list=queue_info)
-
-# Plugins view
-@gui.route('/plugins')
-@login_required
-def plugins_page():
-    """
-    Handles plugins route of the GUI. Displays the list of plugins.
-    """
-
-    try:
-        # Store plugins information
-        plugins_info = plugins
-
-    except Exception as err:
-        # Display error on the GUI
-        flash(str(err), "danger")
-        return redirect(url_for("dashboard"))
-
-    return render_template('plugins.html', plugins_info=plugins_info)
-
-
-# Plugin view
-@gui.route("/plugin/<plugin_name>")
-@login_required
-def plugin_page(plugin_name: str):
-    """
-    Displays information about the plugin like it's docstring.
-    :param plugin_name: str
-    """
-
-    try:
-        # Query plugin information
-        plugin_info = query_internal_api(f"/internal/plugins/{plugin_name}", "get")
-
-    except Exception as err:
-        # Display error on the GUI
-        flash(str(err), "danger")
-        return redirect(url_for("plugins_page"))
-
-    return render_template("plugin.html", title=f"{plugin_name}", plugin_info=plugin_info)
-
-
-# Ganga logs view
-@gui.route("/logs")
-@login_required
-def logs_page():
-    """
-    Diplay ganga log file.
-    :return:
-    """
-
-    ganga_log_path = gui.config["GANGA_LOG"]
-    gui_accesslog_path = gui.config["ACCESS_LOG"]
-    gui_errorlog_path = gui.config["ERROR_LOG"]
-
-    try:
-        # Get ganga log
-        with open(ganga_log_path, "rt") as f:
-            ganga_log_data = f.read()
-
-        # Get GUI access log
-        with open(gui_accesslog_path, "rt") as f:
-            gui_accesslog_data = f.read()
-
-        # Get GUI error log
-        with open(gui_errorlog_path, "rt") as f:
-            gui_errorlog_data = f.read()
-
-    except Exception as err:
-        flash(str(err), "danger")
-        return redirect(url_for("dashboard"))
-
-    return render_template("logs.html", title="Logs", ganga_log_data=ganga_log_data,
-                           gui_accesslog_data=gui_accesslog_data, gui_errorlog_data=gui_errorlog_data)
-
-
-@gui.route("/storage", defaults={"path": ""}, methods=["GET", "POST"])
-@gui.route("/storage/<path:path>", methods=["GET", "POST"])
-@login_required
-def storage_page(path):
-    """
-    A convenience feature to store some file remotely in gangadir/storage
-    """
-
-    # Storage folder path
-    storage_folder = gui.config["STORAGE_FOLDER"]
-
-    # Join the storage path and the requested path
-    abs_path = os.path.join(storage_folder, path)
-
-    # Handle file uploads
-    if request.method == "POST":
-
-        # Uploaded file
-        if "storagefile" in request.files:
-            storagefile = request.files["storagefile"]
-            if storagefile.filename == "":
-                flash("No file selected", "warning")
-                return redirect(request.url)
-
-            # If valid file, the save the file
-            if storagefile:
-                # Directory check
-                if not os.path.isdir(abs_path):
-                    flash("Error while uploading the file", "danger")
-                    return redirect(request.url)
-
-                filename = secure_filename(storagefile.filename)
-                save_path = os.path.join(abs_path, filename)
-                storagefile.save(save_path)
-
-                # Success message
-                flash("Successfully uploaded the file.", "success")
-                return redirect(request.url)
-
-        # No file case
-        flash("No file, retry!", "warning")
-        return redirect(request.url)
-
-    # URL path variable for going back
-    back_path = os.path.dirname(abs_path).replace(storage_folder, "")
-
-    # If path doesn't exist
-    if not os.path.exists(abs_path):
-        flash("Directory does not exist.", "warning")
-        return redirect(url_for("dashboard"))
-
-    # Check if path is a file and send
-    if os.path.isfile(abs_path):
-        return send_file(abs_path)
-
-    files_info = []
-
-    # Show directory contents
-    files = os.listdir(abs_path)
-
-    # Store directory information
-    for file in files:
-        files_info.append({
-            "file": file,
-            "directory": os.path.isdir(os.path.join(abs_path, file))
-        })
-
-    return render_template("storage.html", title="Storage",
-                           abs_path=abs_path,
-                           files_info=files_info,
-                           back_path=back_path)
-
-
-# Serve CLI
-@gui.route("/cli")
-@login_required
-def serve_cli():
-    return render_template("cli.html")
-
-
-# Establish a websocket connection from the frontend to the server
-@socketio.on("connect", namespace="/pty")
-def connect():
-    """
-    New client connected, start reading and writing from the pseudo terminal.
-    """
-
-    if gui.config["CHILD_PID"] and current_user.is_authenticated:
-        # Start background reading and emitting the output of the pseudo terminal
-        socketio.start_background_task(target=read_and_forward_pty_output)
-        return
-
-
-# Input from the frontend
-@socketio.on("pty-input", namespace="/pty")
-def pty_input(data):
-    """
-    Write to the child pty. The pty sees this as if you are typing in a real terminal.
-    """
-
-    if gui.config["FD"] and current_user.is_authenticated:
-        os.write(gui.config["FD"], data["input"].encode())
-
-
-# Resize the pseudo terminal when the frontend is resized
-@socketio.on("resize", namespace="/pty")
-def resize(data):
-    """
-    Resize the pseudo terminal according to the dimension at the frontend.
-    :param data: contains information about rows and cols of the frontend terminal.
-    """
-
-    if gui.config["FD"] and current_user.is_authenticated:
-        set_windowsize(gui.config["FD"], data["rows"], data["cols"])
-
-
-# ******************** Token Based Authentication ******************** #
-
-# Generate token for API authentication - token validity 5 days
-@gui.route("/token", methods=["POST"])
-def generate_token():
-    """
-    Using the 'user' and 'password' data from the form body, validates the user and returns a JSON Web Token (JWT).
-    """
-
-    # Request form data
-    request_json = request.json if request.json else {}
-    request_user = request_json.get("username")
-    request_password = request_json.get("password")
-
-    # Handle no user or no password case
-    if not request_user or not request_password:
-        response_data = {"success": False, "message": "Could not verify user."}
-        return jsonify(response_data), 401
-
-    # Verify user and accordingly return the token
-    user = User.query.filter_by(user=request_user).first()
-    if user and user.verify_password(request_password):
-        token = user.generate_auth_token()
-        response_data = {"token": token}
-        return jsonify(response_data)
-
-    # If authentication fails, return 401 HTTP code
-    response_data = {"success": False, "message": "Could not verify user."}
-    return jsonify(response_data), 401
-
-
-# ******************** Token Authentication Decorator ******************** #
-
-# Decorator for token protected routes
-def token_required(f):
-    """
-    Decorator which validates the request header token in 'X-Acess-Token' field, and returns the user.
-    """
-
-    @wraps(f)
-    def decorated(*args, **kwargs):
-
-        token = None
-
-        # Extract token from headers
-        if "X-Access-Token" in request.headers:
-            token = request.headers["X-Access-Token"]
-
-        if not token:
-            return jsonify({"success": False, "message": "Token is missing"}), 401
-
-        # Decode the token and subsequently identify the user
-        try:
-            data = jwt.decode(token, gui.config["SECRET_KEY"], algorithms=["HS256"])
-            current_api_user = User.query.filter_by(public_id=data["public_id"]).first()
-            if current_api_user is None:
-                return jsonify({"success": False, "message": "Token is old. Please renew"}), 401
-        except jwt.ExpiredSignatureError:
-            return jsonify({"success": False, "message": "Token is expired"}), 401
-        except jwt.InvalidTokenError:
-            return jsonify({"success": False, "message": "Token is invalid"}), 401
-        except:
-            return jsonify({"success": False, "message": "Could not verify token"}), 401
-
-        return f(current_api_user, *args, **kwargs)
-
-    return decorated
-
-
-# ******************** Job API ******************** #
-
-
-# Single job information API - GET Method
-@gui.route("/api/jobs/<int:job_id>", methods=["GET"])
-@token_required
-def job_endpoint(current_api_user, job_id: int):
-    """
-    Given the job_id, returns the general information related to the job in JSON format.
-
-    :param job_id: int
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query job information to the GPI
-        job_info = query_internal_api(f"/internal/jobs/{job_id}", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(job_info)
-
-
-# Single job attribute information API - GET Method
-@gui.route("/api/jobs/<int:job_id>/<attribute>", methods=["GET"])
-@token_required
-def job_attribute_endpoint(current_api_user, job_id: int, attribute: str):
-    """
-    Given the job_id and attribute, returns the attribute information in the JSON format.
-
-    :param job_id: int
-    :param attribute: str
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query job attribute information from ganga
-        job_attribute_info = query_internal_api(f"/internal/jobs/{job_id}/{attribute}", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(job_attribute_info)
-
-
-# Single job full print API - GET Method
-@gui.route("/api/jobs/<int:job_id>/full-print", methods=["GET"])
-@token_required
-def job_full_print_endpoint(current_api_user, job_id: int):
-    """
-    Return full print of the job.
-
-    :param job_id: int
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query job full print from ganga
-        full_print_info = query_internal_api(f"/internal/jobs/{job_id}/full-print", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(full_print_info)
-
-
-# Create job using template API - POST Method
-@gui.route("/api/jobs/create", methods=["POST"])
-@token_required
-def job_create_endpoint(current_api_user):
-    """
-    Create a new job using the existing template.
-
-    IMPORTANT: template_id NEEDS to be provided in the request body. job_name can optionally be provided in the request body.
-
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    # Request data
-    data = {
-        "template_id": request.json.get("template_id"),
-        "job_name": request.json.get("job_name")
-    }
-
-    try:
-        # Query ganga to create a job using the template id
-        response_info = query_internal_api("/internal/jobs/create", "post", json=data)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(response_info)
-
-
-# Copy job API - PUT Method
-@gui.route("/api/jobs/<int:job_id>/copy", methods=["PUT"])
-@token_required
-def job_copy_endpoint(current_api_user, job_id: int):
-    """
-    Create a copy of the job.
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    :param job_id: int
-    """
-
-    try:
-        # Query ganga to copy the job
-        response_info = query_internal_api(f"/internal/jobs/{job_id}/copy", "put")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(response_info)
-
-
-# Job action API - PUT Method
-@gui.route("/api/jobs/<int:job_id>/<action>", methods=["PUT"])
-@token_required
-def job_action_endpoint(current_api_user, job_id: int, action: str):
-    """
-    Given the job_id and action in the endpoint, perform the action on the job.
-
-    The action can be any method or attribute change that can be called on the Job object.
-
-    Example:
-    1)
-        PUT http://localhost:5000/job/13/resubmit
-
-        The above request will resubmit the job with ID 13.
-
-    2)
-        PUT http://localhost:5000/job/13/force_status
-        {"force_status":"failed"}
-
-        The above request will force status of the job with ID 13 to killed. If unsuccessful will return back the error.
-
-    3)
-        PUT http://localhost:5000/job/13/name
-        {"name"="New Name"}
-
-        The above request will change the name of the job with ID 13 to "New Name". Notice how the required values
-        are passed in the request body with the same name as action.
-
-    NOTE: It is NECESSARY to send body in JSON format for the request to be parsed in JSON.
-
-    :param job_id: int
-    :param action: str
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    # Request data
-    request_data = request.json
-
-    try:
-        # Query ganga to perform the action
-        response_info = query_internal_api(f"/internal/jobs/{job_id}/{action}", "put", json=request_data)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(response_info)
-
-
-# Job delete API - DELETE Method
-@gui.route("/api/jobs/<int:job_id>", methods=["DELETE"])
-@token_required
-def job_delete_endpoint(current_api_user, job_id: int):
-    """
-    Given the job id, removes the job from the job repository.
-
-    :param job_id: int
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga to delete the job
-        response_info = query_internal_api(f"/internal/jobs/{job_id}", "delete")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(response_info)
-
-
-# Pin the Job
-@gui.route("/api/jobs/<int:job_id>/pin", methods=["PUT"])
-@token_required
-def job_pin_endpoint(current_api_user, job_id: int):
-    """
-    Pin the given job, which is then shown in the dashboard.
-    :param job_id: int
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    # Get current user
-    u = current_user
-
-    # Load pinned jobs of the user from the database
-    pinned_jobs = json.loads(u.pinned_jobs) if u.pinned_jobs is not None else []
-
-    # Pin job
-    if job_id not in pinned_jobs:
-        pinned_jobs.append(job_id)
-
-    # Add new pinned jobs to the database
-    u.pinned_jobs = json.dumps(pinned_jobs)
-    db.session.add(u)
-    db.session.commit()
-
-    return jsonify({"success": True, "message": f"Successfully pinned Job (ID={job_id})."})
-
-
-# Unpin the job
-@gui.route("/api/jobs/<int:job_id>/unpin", methods=["PUT"])
-@token_required
-def job_unpin_endpoint(current_api_user, job_id: int):
-    """
-    Unpin the job, and make the required change to the GUI database.
-    :param job_id: int
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    # Get the user from the database
-    u = current_user
-
-    # Load user's pinned job from the database
-    pinned_jobs = json.loads(u.pinned_jobs) if u.pinned_jobs is not None else []
-
-    # Unpin the job
-    if job_id in pinned_jobs:
-        pinned_jobs.remove(job_id)
-
-    # Commit changes to the database
-    u.pinned_jobs = json.dumps(pinned_jobs)
-    db.session.add(u)
-    db.session.commit()
-
-    return jsonify({"success": True, "message": f"Successfully unpinned Job (ID={job_id})."})
-
-
-# ******************** Subjobs API ******************** #
-
-# Subjobs API - GET Method
-@gui.route("/api/jobs/<int:job_id>/subjobs", methods=["GET"])
-@token_required
-def subjobs_endpoint(current_api_user, job_id: int):
-    """
-    Returns a list subjobs of a particular job in a similar way as Jobs API.
-
-    The parameter accepted are:
-    * ids: provide a JSON string of list of IDs
-    * status: provide subjob status as a string for filter
-    * application: provide subjob application as a string for filter
-    * backend: provide backend application as a string for filter
-    * recent: if provided, starts a list from recent subjobs to old
-    * length: number of subjobs to be returned, provide as a int
-    * offset: how many subjobs to skip before returning the specified length of subjobs. Provide as int.
-        offset works as: number of subjobs skipped = offset * length
-
-    :param job_id: int
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    params = {
-        "ids": request.args.get("ids"),
-        "status": request.args.get("status"),
-        "application": request.args.get("application"),
-        "backend": request.args.get("backend"),
-        "recent": request.args.get("recent"),
-        "length": request.args.get("length"),
-        "offset": request.args.get("offset")
-    }
-
-    try:
-        # Query ganga for subjobs information
-        subjobs_info = query_internal_api(f"/internal/jobs/{job_id}/subjobs", "get", params=params)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(subjobs_info)
-
-
-# Single subjob info API - GET Method
-@gui.route("/api/jobs/<int:job_id>/subjobs/<int:subjob_id>", methods=["GET"])
-@token_required
-def subjob_endpoint(current_api_user, job_id: int, subjob_id: int):
-    """
-    Returns information of a single subjob related to a particular job
-
-    :param job_id: int
-    :param subjob_id: int
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query subjob information to ganga
-        subjob_info = query_internal_api(f"/internal/jobs/{job_id}/subjobs/{subjob_id}", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(subjob_info)
-
-
-# Single Subjob Attribute Info API - GET Method
-@gui.route("/api/jobs/<int:job_id>/subjobs/<int:subjob_id>/<attribute>", methods=["GET"])
-@token_required
-def subjob_attribute_endpoint(current_api_user, job_id: int, subjob_id: int, attribute: str):
-    """
-    Given the job id, subjob id and attribute; return the attribute information in the string format via JSON.
-
-    :param job_id: int
-    :param subjob_id: int
-    :param attribute: str
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query attribute information from ganga
-        subjob_attribute_info = query_internal_api(f"/internal/jobs/{job_id}/subjobs/{subjob_id}/{attribute}", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(subjob_attribute_info)
-
-
-# Single subjob full print API - GET Method
-@gui.route("/api/jobs/<int:job_id>/subjobs/<int:subjob_id>/full-print", methods=["GET"])
-@token_required
-def subjob_full_print_endpoint(current_api_user, job_id: int, subjob_id: int):
-    """
-    Return full print of the subjob.
-
-    :param subjob_id: int
-    :param job_id: int
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query subjob full print from ganga
-        full_print_info = query_internal_api(f"/internal/jobs/{job_id}/subjobs/{subjob_id}/full-print", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(full_print_info)
-
-
-# Copy subjob API - PUT Method
-@gui.route("/api/jobs/<int:job_id>/subjobs/<int:subjob_id>/copy", methods=["PUT"])
-@token_required
-def subjob_copy_endpoint(current_api_user, job_id: int, subjob_id: int):
-    """
-    Create a copy of the subjob into a new job.
-    :param job_id:
-    :param subjob_id:
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga to copy subjob
-        response_info = query_internal_api(f"/internal/jobs/{job_id}/subjobs/{subjob_id}/copy", "put")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(response_info)
-
-
-# ******************** Jobs API ******************** #
-
-# Jobs API - GET Method
-@gui.route("/api/jobs", methods=["GET"])
-@token_required
-def jobs_endpoint(current_api_user):
-    """
-    Returns a list of jobs with general information in JSON format.
-
-    The parameter accepted are:
-    * ids: provide a JSON string of list of IDs
-    * status: provide job status as a string for filter
-    * application: provide job application as a string for filter
-    * backend: provide backend application as a string for filter
-    * recent: if provided, starts a list from recent job to old
-    * length: number of job to be returned, provide as a int
-    * offset: how many job to skip before returning the specified length of job. Provide as int.
-        offset works like: number of job skipped = offset * length
-    * auto-validate-ids: If ids provided in ids parameters does not exist in job repository, then skip those ids.
-
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    params = {
-        "ids": request.args.get("ids"),
-        "status": request.args.get("status"),
-        "application": request.args.get("application"),
-        "backend": request.args.get("backend"),
-        "recent": request.args.get("recent"),
-        "length": request.args.get("length"),
-        "offset": request.args.get("offset"),
-        "auto-validate-ids": request.args.get("auto-validate-ids")
-    }
-
-    try:
-        # Get jobs information according to select filter and range filter
-        jobs_info = query_internal_api(f"/internal/jobs", "get", params=params)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(jobs_info)
-
-
-# Jobs statistics API - GET Method
-@gui.route("/api/jobs/statistics", methods=["GET"])
-@token_required
-def jobs_statistics_endpoint(current_api_user):
-    """
-    Returns the number of jobs in new, running, completed, killed, failed status.
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga to get statistics information
-        statistics = query_internal_api("/internal/jobs/statistics", "get")
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(statistics)
-
-@gui.route("/api/queue", methods=["GET"])
-@token_required
-def queue_endpoint(current_api_user):
-
-    try:
-        queue_info = query_internal_api("/internal/queue", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(queue_info)
-
-@gui.route("/api/queue/chart", methods=["GET","POST"])
-def queue_chart_endpoint():
-
-    
-    chart_info = query_internal_api("/internal/queue/data", "get")
-    response = make_response(json.dumps(chart_info))
-    response.content_type = 'application/json'
-    return response
-
-# Job incomplete ids API - GET Method
-@gui.route("/api/jobs/incomplete_ids", methods=["GET"])
-@token_required
-def jobs_incomplete_ids_endpoint(current_api_user):
-    """
-    Returns a list of incomplete job ids in JSON format.
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga to get incomplete ids list
-        incomplete_ids_list = query_internal_api("/internal/jobs/incomplete-ids", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(incomplete_ids_list)
-
-
-# ******************** Config API ******************** #
-
-# Config API - GET Method
-@gui.route("/api/config", methods=["GET"], defaults={"section": ""})
-@gui.route("/api/config/<section>", methods=["GET"])
-@token_required
-def config_endpoint(current_api_user, section: str):
-    """
-    Returns a list of all the section of the configuration and their options as well as the values in JSON format.
-
-    If section is provide, returns information about the section in JSON format.
-
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga to get config information
-        if section != "":
-            config_info = query_internal_api(f"/internal/config/{section}", "get")
-        else:
-            config_info = query_internal_api("/internal/config", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(config_info)
-
-
-# ******************** Templates API ******************** #
-
-# Templates API - GET Method
-@gui.route("/api/templates", methods=["GET"])
-@token_required
-def templates_endpoint(current_api_user):
-    """
-    Returns a list of objects containing template info in JSON format.
-
-    * ids: provide a JSON string of list of IDs
-    * status: provide template status as a string for filter
-    * application: provide template application as a string for filter
-    * backend: provide backend application as a string for filter
-    * recent: if provided, starts a list from recent template to old
-    * length: number of template to be returned, provide as a int
-    * offset: how many template to skip before returning the specified length of template. Provide as int.
-        offset works like: number of template skipped = offset * length
-
-    :param current_api_user: Information of the current_user based on the request's JWT token
-    """
-
-    params = {
-        "application": request.args.get("application"),
-        "backend": request.args.get("backend"),
-        "recent": request.args.get("recent"),
-        "length": request.args.get("length"),
-        "offset": request.args.get("offset"),
-    }
-
-    try:
-        # Query ganga for templates information
-        templates_info = query_internal_api("/internal/templates", "get", params=params)
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(templates_info)
-
-
-# Single template full print API - GET Method
-@gui.route("/api/templates/<int:template_id>/full-print", methods=["GET"])
-@token_required
-def template_full_print_endpoint(current_api_user, template_id: int):
-    """
-    Return full print of the template.
-
-    :param template_id: int
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query template full print from ganga
-        full_print_info = query_internal_api(f"/internal/templates/{template_id}/full-print", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(full_print_info)
-
-
-# Template API - DELETE Method
-@gui.route("/api/templates/<int:template_id>", methods=["DELETE"])
-@token_required
-def delete_template_endpoint(current_api_user, template_id: int):
-    """
-
-    Given the templates id, delete it from the template repository.
-
-    :param template_id: int
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga to remove the template
-        response_info = query_internal_api(f"/internal/templates/{template_id}", "delete")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(response_info)
-
-
-# ******************** Credentials API ******************** #
-
-# Credential store API - GET Method
-@gui.route("/api/credentials", methods=["GET"])
-@token_required
-def credentials_endpoint(current_api_user):
-    """
-    Return a list of credentials and their information in JSON format.
-
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga for credentials information
-        credentials_info = query_internal_api("/internal/credentials", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(credentials_info)
-
-
-# Credential Store API - PUT Method - Renew all credentials
-@gui.route("/api/credentials/renew", methods=["PUT"])
-@token_required
-def credentials_renew_endpoint(current_api_user):
-    """
-    Renew all the credentials in the credential store.
-
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga to renew credentials
-        response_info = query_internal_api("/internal/credentials/renew", "put")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(response_info)
-
-
-# ******************** Job Tree API ******************** #
-
-# Job tree API - GET Method
-@gui.route("/api/jobtree", methods=["GET"])
-@token_required
-def jobtree_endpoint(current_api_user):
-    """
-    Return the job tree folder structure as the json format of python dict.
-
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga to get job tree information
-        jobtree_info = query_internal_api("/internal/jobtree", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(jobtree_info)
-
-
-# ******************** Job Tree API ******************** #
-
-# Plugins API - GET Method
-@gui.route("/api/plugins", methods=["GET"])
-@token_required
-def plugins_endpoint(current_api_user):
-    """
-    Return plugins information, category and names of the plugins in the category.
-
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga to get plugins information
-        plugins_info = query_internal_api("/internal/plugins", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(plugins_info)
-
-
-# Plugin API - GET Method
-@gui.route("/api/plugins/<plugin_name>", methods=["GET"])
-@token_required
-def plugin_endpoint(current_api_user, plugin_name: str):
-    """
-    Return single plugin information like name and docstring.
-
-    :param plugin_name: str
-    :param current_api_user: Information of the current_api_user based on the request's JWT token
-    """
-
-    try:
-        # Query ganga to get plugin information
-        plugin_info = query_internal_api(f"/internal/plugins/{plugin_name}", "get")
-
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return jsonify(plugin_info)
-
-
-# ******************** Helper Functions ******************** #
-
-# Validate uploaded filename.
-def allowed_file(filename):
-    return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS
-
-
-# Make HTTP request to the Internal Flask Server which is running on a GangaThread which has access to ganga namespace.
-def query_internal_api(route: str, method: str, **kwargs):
-    """
-    :param route: str
-    :param method: str
-    :param kwargs: dict
-    :return: dict
-
-    Make a HTTP request to the Internal API Flask server which runs on a GangaThread to query data from Ganga.
-    Check response status code and extract the data or raise an exception accordingly.
-
-    kwargs can be param, json, etc. Any attribute that is supported by the requests module.
-    """
-
-    # Internal url for communicating with API server running on a GangaThread
-    INTERNAL_URL = f"http://localhost:{gui.config['INTERNAL_PORT']}"
-
-    # Raise error if HTTP method not supported
-    if method not in ["get", "post", "put", "delete"]:
-        raise Exception(f"Unsupported method: {method}")
-
-    # Made the HTTP requests, along with whatever arguments provided
-    res = getattr(requests, method)(INTERNAL_URL + route, **kwargs)
-
-    # Check is request is OK
-    if res.status_code != 200:
-        raise Exception(res.json().get("message"))
-
-    # Return request data
-    return res.json()
-
-
-def create_session_defaults():
-    """
-    Create user session defaults and assign default values to them.
-    """
-
-    # Set session defaults for templates filter
-    if "templates_per_page" not in session:
-        session["templates_per_page"] = 10
-    if "templates_filter" not in session:
-        session["templates_filter"] = {key: "any" for key in ["application", "backend"]}
-
-    # Set session defaults for jobs filter
-    if "jobs_per_page" not in session:
-        session["jobs_per_page"] = 10
-    if "jobs_filter" not in session:
-        session["jobs_filter"] = {key: "any" for key in ["status", "application", "backend"]}
-
-    # Set session defaults for subjobs filter
-    if "subjobs_per_page" not in session:
-        session["subjobs_per_page"] = 10
-    if "subjobs_filter" not in session:
-        session["subjobs_filter"] = {key: "any" for key in ["status", "application", "backend"]}
-
-
-# Ping internal API server
-def ping_internal():
-    """
-    Ping internal API server if it is running
-    """
-
-    trials = 0
-    while True:
-        try:
-            ping = query_internal_api("/ping", "get")
-            if ping is True:
-                return True
-        except:
-            time.sleep(2)
-
-        print("Internal API server not online (mostly because Ganga is booting up), retrying...")
-        trials += 1
-        if trials > 20:
-            return False
-
-
-def start_ganga(internal_port: int, args: str = ""):
-    """
-    Start a ganga session in a pseudo terminal and stores the file descriptor of the terminal as well as the PID of the ganga session.
-    :param args: str - str of arguments to provide to ganga
-    :param internal_port: int
-    """
-
-    # Create child process attached to a pty that we can read from and write to
-    (child_pid, fd) = pty.fork()
-
-    if child_pid == 0:
-        # This is the child process fork. Anything printed here will show up in the pty, including the output of this subprocess
-        ganga_env = os.environ.copy()
-        ganga_env["WEB_CLI"] = "True"
-        ganga_env["INTERNAL_PORT"] = str(internal_port)
-        subprocess.run(f"ganga --webgui {args}", shell=True, env=ganga_env)
-    else:
-        # This is the parent process fork. Store fd (connected to the child’s controlling terminal) and child pid
-        gui.config["FD"] = fd
-        gui.config["CHILD_PID"] = child_pid
-        set_windowsize(fd, 50, 50)
-        print("Ganga started, PID: ", child_pid)
-
-
-# Set the window size of the pseudo terminal according to the size in the frontend
-def set_windowsize(fd, row, col, xpix=0, ypix=0):
-    winsize = struct.pack("HHHH", row, col, xpix, ypix)
-    fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)
-
-
-# Read and forward that data from the pseudo terminal to the frontend
-def read_and_forward_pty_output():
-    max_read_bytes = 1024 * 20
-    while True:
-        socketio.sleep(0.01)
-        if gui.config["FD"]:
-            timeout_sec = 0
-            (data_ready, _, _) = select.select([gui.config["FD"]], [], [], timeout_sec)
-            if data_ready:
-                output = os.read(gui.config["FD"], max_read_bytes).decode()
-                socketio.emit("pty-output", {"output": output}, namespace="/pty")
-
-
-def start_web_cli(host: str, port: int, internal_port: int, log_output=True, ganga_args: str = ""):
-    """
-    Start the web server on eventlet serving the terminal on the specified port. (Production ready server)
-    :param ganga_args: str - arguments to be passed to ganga
-    :param host: str
-    :param port: int
-    :param internal_port: int
-    """
-
-    from GangaGUI.start import create_default_user
-
-    # Create default user
-    gui_user, gui_password = create_default_user()
-
-    print(f"Starting the GUI server on http://{host}:{port}")
-    print(f"You login information for the GUI is: Username: {gui_user.user} Password: {gui_password}")
-
-    gui.config["INTERNAL_PORT"] = internal_port
-    gui.config["WEB_CLI"] = True
-    gui.config["GANGA_ARGS"] = ganga_args
-    socketio.run(gui, host=host, port=port, log_output=log_output)  # TODO
-
-
-# ******************** Shutdown Function ******************** #
-
-# Route used to shutdown the Internal API server and GUI server
-@gui.route("/shutdown", methods=["GET"])
-def shutdown():
-
-    if gui.config["WEB_CLI"] is True:
-        flash("WEB CLI Mode is on, cannot self shutdown server. Consider doing manually.", "warning")
-        return redirect(url_for("dashboard"))
-
-    try:
-        response_info = query_internal_api("/shutdown", "get")
-    except Exception as err:
-        return jsonify({"success": False, "message": str(err)}), 400
-
-    return "GUI Shutdown Successful."
-
-# ******************** EOF ******************** #
diff --git a/ganga/GangaGUI/gui/static/css/style.css b/ganga/GangaGUI/gui/static/css/style.css
deleted file mode 100644
index b38dbdd4d5..0000000000
--- a/ganga/GangaGUI/gui/static/css/style.css
+++ /dev/null
@@ -1,9275 +0,0 @@
-
-:root {
-  --blue: #4e73df;
-  --purple: #6f42c1;
-  --red: #e74a3b;
-  --green: #1cc88a;
-  --white: #fff;
-  --gray: #858796;
-  --gray-dark: #5a5c69;
-  --primary: #4e73df;
-  --secondary: #858796;
-  --success: #1cc88a;
-  --info: #36b9cc;
-  --warning: #f6c23e;
-  --danger: #e74a3b;
-  --light: #f8f9fc;
-  --dark: #5a5c69;
-  --breakpoint-xs: 0;
-  --breakpoint-sm: 576px;
-  --breakpoint-md: 768px;
-  --breakpoint-lg: 992px;
-  --breakpoint-xl: 1200px;
-  --font-family-sans-serif: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
-  --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
-}
-
-*,
-*::before,
-*::after {
-  box-sizing: border-box;
-}
-
-html {
-  font-family: sans-serif;
-  line-height: 1.15;
-  -webkit-text-size-adjust: 100%;
-  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-}
-table.dataTable thead .sorting:after,
-table.dataTable thead .sorting:before,
-table.dataTable thead .sorting_asc:after,
-table.dataTable thead .sorting_asc:before,
-table.dataTable thead .sorting_asc_disabled:after,
-table.dataTable thead .sorting_asc_disabled:before,
-table.dataTable thead .sorting_desc:after,
-table.dataTable thead .sorting_desc:before,
-table.dataTable thead .sorting_desc_disabled:after,
-table.dataTable thead .sorting_desc_disabled:before {
-bottom: .5em;
-}
-
-
-footer, header , nav {
-  display: block;
-}
-.sort:hover {
-  background-color:#f3f3f3;
-}
-
-.sort.asc > i.material-icons::after {
-  content: "arrow_drop_up";
-}
-.sort.desc > i.material-icons::after {
-  content: "arrow_drop_down";
-}
-
-body {
-  margin: 0;
-  font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
-  font-size: 1rem;
-  font-weight: 400;
-  line-height: 1.5;
-  color: #858796;
-  text-align: left;
-  background-color: #fff;
-}
-
-[tabindex="-1"]:focus:not(:focus-visible) {
-  outline: 0 !important;
-}
-
-hr {
-  box-sizing: content-box;
-  height: 0;
-  overflow: visible;
-}
-
-h1, h2, h3, h4, h5, h6 {
-  margin-top: 0;
-  margin-bottom: 0.5rem;
-}
-
-p {
-  margin-top: 0;
-  margin-bottom: 1rem;
-}
-
-abbr[title],
-abbr[data-original-title] {
-  text-decoration: underline;
-  -webkit-text-decoration: underline dotted;
-  text-decoration: underline dotted;
-  cursor: help;
-  border-bottom: 0;
-  -webkit-text-decoration-skip-ink: none;
-  text-decoration-skip-ink: none;
-}
-
-
-ol,
-ul,
-dl {
-  margin-top: 0;
-  margin-bottom: 1rem;
-}
-
-ol ol,
-ul ul,
-ol ul,
-ul ol {
-  margin-bottom: 0;
-}
-
-
-b,
-strong {
-  font-weight: bolder;
-}
-
-small {
-  font-size: 80%;
-}
-
-
-
-a {
-  color: #4e73df;
-  text-decoration: none;
-  background-color: transparent;
-}
-
-a:hover {
-  color: #224abe;
-  text-decoration: underline;
-}
-
-a:not([href]):not([class]) {
-  color: inherit;
-  text-decoration: none;
-}
-
-a:not([href]):not([class]):hover {
-  color: inherit;
-  text-decoration: none;
-}
-
-
-img {
-  vertical-align: middle;
-  border-style: none;
-}
-
-
-
-table {
-  border-collapse: collapse;
-}
-
-
-
-th {
-  text-align: inherit;
-  text-align: -webkit-match-parent;
-}
-
-label {
-  display: inline-block;
-  margin-bottom: 0.5rem;
-}
-
-button {
-  border-radius: 0;
-}
-
-button:focus:not(:focus-visible) {
-  outline: 0;
-}
-
-input,
-button,
-select,
-optgroup,
-textarea {
-  margin: 0;
-  font-family: inherit;
-  font-size: inherit;
-  line-height: inherit;
-}
-
-button,
-input {
-  overflow: visible;
-}
-
-button,
-select {
-  text-transform: none;
-}
-
-[role="button"] {
-  cursor: pointer;
-}
-
-select {
-  word-wrap: normal;
-}
-
-button,
-[type="button"],
-[type="reset"],
-[type="submit"] {
-  -webkit-appearance: button;
-}
-
-button:not(:disabled),
-[type="button"]:not(:disabled),
-[type="reset"]:not(:disabled),
-[type="submit"]:not(:disabled) {
-  cursor: pointer;
-}
-
-button::-moz-focus-inner,
-[type="button"]::-moz-focus-inner,
-[type="reset"]::-moz-focus-inner,
-[type="submit"]::-moz-focus-inner {
-  padding: 0;
-  border-style: none;
-}
-
-
-
-textarea {
-  overflow: auto;
-  resize: vertical;
-}
-
-
-h1, h2, h3, h4, h5, h6,
-.h1, .h2, .h3, .h4, .h5, .h6 {
-  margin-bottom: 0.5rem;
-  font-weight: 700;
-  line-height: 1.2;
-}
-
-h1, .h1 {
-  font-size: 2.5rem;
-}
-
-h2, .h2 {
-  font-size: 2rem;
-}
-
-h3, .h3 {
-  font-size: 1.75rem;
-}
-
-h4, .h4 {
-  font-size: 1.5rem;
-}
-
-h5, .h5 {
-  font-size: 1.25rem;
-}
-
-h6, .h6 {
-  font-size: 1rem;
-}
-
-
-hr {
-  margin-top: 1rem;
-  margin-bottom: 1rem;
-  border: 0;
-  border-top: 1px solid rgba(0, 0, 0, 0.1);
-}
-
-small,
-.small {
-  font-size: 80%;
-  font-weight: 400;
-}
-
-
-
-
-.pre-scrollable {
-  max-height: 340px;
-  overflow-y: scroll;
-}
-
-.container,
-.container-fluid,
-.container-sm,
-.container-md,
-.container-lg,
-.container-xl {
-  width: 100%;
-  padding-right: 0.75rem;
-  padding-left: 0.75rem;
-  margin-right: auto;
-  margin-left: auto;
-}
-
-@media (min-width: 576px) {
-  .container, .container-sm {
-    max-width: 540px;
-  }
-}
-
-@media (min-width: 768px) {
-  .container, .container-sm, .container-md {
-    max-width: 720px;
-  }
-}
-
-@media (min-width: 992px) {
-  .container, .container-sm, .container-md, .container-lg {
-    max-width: 960px;
-  }
-}
-
-@media (min-width: 1200px) {
-  .container, .container-sm, .container-md, .container-lg, .container-xl {
-    max-width: 1140px;
-  }
-}
-
-.row {
-  display: flex;
-  flex-wrap: wrap;
-  margin-right: -0.75rem;
-  margin-left: -0.75rem;
-}
-
-.no-gutters {
-  margin-right: 0;
-  margin-left: 0;
-}
-
-.no-gutters > .col,
-.no-gutters > [class*="col-"] {
-  padding-right: 0;
-  padding-left: 0;
-}
-
-.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col,
-.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm,
-.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md,
-.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg,
-.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl,
-.col-xl-auto {
-  position: relative;
-  width: 100%;
-  padding-right: 0.75rem;
-  padding-left: 0.75rem;
-}
-
-.col {
-  flex-basis: 0;
-  flex-grow: 1;
-  max-width: 100%;
-}
-
-.row-cols-1 > * {
-  flex: 0 0 100%;
-  max-width: 100%;
-}
-
-.row-cols-2 > * {
-  flex: 0 0 50%;
-  max-width: 50%;
-}
-
-.row-cols-3 > * {
-  flex: 0 0 33.33333%;
-  max-width: 33.33333%;
-}
-
-.row-cols-4 > * {
-  flex: 0 0 25%;
-  max-width: 25%;
-}
-
-.row-cols-5 > * {
-  flex: 0 0 20%;
-  max-width: 20%;
-}
-
-.row-cols-6 > * {
-  flex: 0 0 16.66667%;
-  max-width: 16.66667%;
-}
-
-.col-auto {
-  flex: 0 0 auto;
-  width: auto;
-  max-width: 100%;
-}
-
-.col-1 {
-  flex: 0 0 8.33333%;
-  max-width: 8.33333%;
-}
-
-.col-2 {
-  flex: 0 0 16.66667%;
-  max-width: 16.66667%;
-}
-
-.col-3 {
-  flex: 0 0 25%;
-  max-width: 25%;
-}
-
-.col-4 {
-  flex: 0 0 33.33333%;
-  max-width: 33.33333%;
-}
-
-.col-5 {
-  flex: 0 0 41.66667%;
-  max-width: 41.66667%;
-}
-
-.col-6 {
-  flex: 0 0 50%;
-  max-width: 50%;
-}
-
-.col-7 {
-  flex: 0 0 58.33333%;
-  max-width: 58.33333%;
-}
-
-.col-8 {
-  flex: 0 0 66.66667%;
-  max-width: 66.66667%;
-}
-
-.col-9 {
-  flex: 0 0 75%;
-  max-width: 75%;
-}
-
-.col-10 {
-  flex: 0 0 83.33333%;
-  max-width: 83.33333%;
-}
-
-.col-11 {
-  flex: 0 0 91.66667%;
-  max-width: 91.66667%;
-}
-
-.col-12 {
-  flex: 0 0 100%;
-  max-width: 100%;
-}
-
-
-
-.offset-1 {
-  margin-left: 8.33333%;
-}
-
-.offset-2 {
-  margin-left: 16.66667%;
-}
-
-.offset-3 {
-  margin-left: 25%;
-}
-
-.offset-4 {
-  margin-left: 33.33333%;
-}
-
-.offset-5 {
-  margin-left: 41.66667%;
-}
-
-.offset-6 {
-  margin-left: 50%;
-}
-
-.offset-7 {
-  margin-left: 58.33333%;
-}
-
-.offset-8 {
-  margin-left: 66.66667%;
-}
-
-.offset-9 {
-  margin-left: 75%;
-}
-
-.offset-10 {
-  margin-left: 83.33333%;
-}
-
-.offset-11 {
-  margin-left: 91.66667%;
-}
-
-@media (min-width: 576px) {
-  .col-sm {
-    flex-basis: 0;
-    flex-grow: 1;
-    max-width: 100%;
-  }
-  .row-cols-sm-1 > * {
-    flex: 0 0 100%;
-    max-width: 100%;
-  }
-  .row-cols-sm-2 > * {
-    flex: 0 0 50%;
-    max-width: 50%;
-  }
-  .row-cols-sm-3 > * {
-    flex: 0 0 33.33333%;
-    max-width: 33.33333%;
-  }
-  .row-cols-sm-4 > * {
-    flex: 0 0 25%;
-    max-width: 25%;
-  }
-  .row-cols-sm-5 > * {
-    flex: 0 0 20%;
-    max-width: 20%;
-  }
-  .row-cols-sm-6 > * {
-    flex: 0 0 16.66667%;
-    max-width: 16.66667%;
-  }
-  .col-sm-auto {
-    flex: 0 0 auto;
-    width: auto;
-    max-width: 100%;
-  }
-  .col-sm-1 {
-    flex: 0 0 8.33333%;
-    max-width: 8.33333%;
-  }
-  .col-sm-2 {
-    flex: 0 0 16.66667%;
-    max-width: 16.66667%;
-  }
-  .col-sm-3 {
-    flex: 0 0 25%;
-    max-width: 25%;
-  }
-  .col-sm-4 {
-    flex: 0 0 33.33333%;
-    max-width: 33.33333%;
-  }
-  .col-sm-5 {
-    flex: 0 0 41.66667%;
-    max-width: 41.66667%;
-  }
-  .col-sm-6 {
-    flex: 0 0 50%;
-    max-width: 50%;
-  }
-  .col-sm-7 {
-    flex: 0 0 58.33333%;
-    max-width: 58.33333%;
-  }
-  .col-sm-8 {
-    flex: 0 0 66.66667%;
-    max-width: 66.66667%;
-  }
-  .col-sm-9 {
-    flex: 0 0 75%;
-    max-width: 75%;
-  }
-  .col-sm-10 {
-    flex: 0 0 83.33333%;
-    max-width: 83.33333%;
-  }
-  .col-sm-11 {
-    flex: 0 0 91.66667%;
-    max-width: 91.66667%;
-  }
-  .col-sm-12 {
-    flex: 0 0 100%;
-    max-width: 100%;
-  }
-  .order-sm-first {
-    order: -1;
-  }
-  .order-sm-last {
-    order: 13;
-  }
-  .order-sm-0 {
-    order: 0;
-  }
-  .order-sm-1 {
-    order: 1;
-  }
-  .order-sm-2 {
-    order: 2;
-  }
-  .order-sm-3 {
-    order: 3;
-  }
-  .order-sm-4 {
-    order: 4;
-  }
-  .order-sm-5 {
-    order: 5;
-  }
-  .order-sm-6 {
-    order: 6;
-  }
-  .order-sm-7 {
-    order: 7;
-  }
-  .order-sm-8 {
-    order: 8;
-  }
-  .order-sm-9 {
-    order: 9;
-  }
-  .order-sm-10 {
-    order: 10;
-  }
-  .order-sm-11 {
-    order: 11;
-  }
-  .order-sm-12 {
-    order: 12;
-  }
-  .offset-sm-0 {
-    margin-left: 0;
-  }
-  .offset-sm-1 {
-    margin-left: 8.33333%;
-  }
-  .offset-sm-2 {
-    margin-left: 16.66667%;
-  }
-  .offset-sm-3 {
-    margin-left: 25%;
-  }
-  .offset-sm-4 {
-    margin-left: 33.33333%;
-  }
-  .offset-sm-5 {
-    margin-left: 41.66667%;
-  }
-  .offset-sm-6 {
-    margin-left: 50%;
-  }
-  .offset-sm-7 {
-    margin-left: 58.33333%;
-  }
-  .offset-sm-8 {
-    margin-left: 66.66667%;
-  }
-  .offset-sm-9 {
-    margin-left: 75%;
-  }
-  .offset-sm-10 {
-    margin-left: 83.33333%;
-  }
-  .offset-sm-11 {
-    margin-left: 91.66667%;
-  }
-}
-
-@media (min-width: 768px) {
-  .col-md {
-    flex-basis: 0;
-    flex-grow: 1;
-    max-width: 100%;
-  }
-  .row-cols-md-1 > * {
-    flex: 0 0 100%;
-    max-width: 100%;
-  }
-  .row-cols-md-2 > * {
-    flex: 0 0 50%;
-    max-width: 50%;
-  }
-  .row-cols-md-3 > * {
-    flex: 0 0 33.33333%;
-    max-width: 33.33333%;
-  }
-  .row-cols-md-4 > * {
-    flex: 0 0 25%;
-    max-width: 25%;
-  }
-  .row-cols-md-5 > * {
-    flex: 0 0 20%;
-    max-width: 20%;
-  }
-  .row-cols-md-6 > * {
-    flex: 0 0 16.66667%;
-    max-width: 16.66667%;
-  }
-  .col-md-auto {
-    flex: 0 0 auto;
-    width: auto;
-    max-width: 100%;
-  }
-  .col-md-1 {
-    flex: 0 0 8.33333%;
-    max-width: 8.33333%;
-  }
-  .col-md-2 {
-    flex: 0 0 16.66667%;
-    max-width: 16.66667%;
-  }
-  .col-md-3 {
-    flex: 0 0 25%;
-    max-width: 25%;
-  }
-  .col-md-4 {
-    flex: 0 0 33.33333%;
-    max-width: 33.33333%;
-  }
-  .col-md-5 {
-    flex: 0 0 41.66667%;
-    max-width: 41.66667%;
-  }
-  .col-md-6 {
-    flex: 0 0 50%;
-    max-width: 50%;
-  }
-  .col-md-7 {
-    flex: 0 0 58.33333%;
-    max-width: 58.33333%;
-  }
-  .col-md-8 {
-    flex: 0 0 66.66667%;
-    max-width: 66.66667%;
-  }
-  .col-md-9 {
-    flex: 0 0 75%;
-    max-width: 75%;
-  }
-  .col-md-10 {
-    flex: 0 0 83.33333%;
-    max-width: 83.33333%;
-  }
-  .col-md-11 {
-    flex: 0 0 91.66667%;
-    max-width: 91.66667%;
-  }
-  .col-md-12 {
-    flex: 0 0 100%;
-    max-width: 100%;
-  }
-  .order-md-first {
-    order: -1;
-  }
-  .order-md-last {
-    order: 13;
-  }
-  .order-md-0 {
-    order: 0;
-  }
-  .order-md-1 {
-    order: 1;
-  }
-  .order-md-2 {
-    order: 2;
-  }
-  .order-md-3 {
-    order: 3;
-  }
-  .order-md-4 {
-    order: 4;
-  }
-  .order-md-5 {
-    order: 5;
-  }
-  .order-md-6 {
-    order: 6;
-  }
-  .order-md-7 {
-    order: 7;
-  }
-  .order-md-8 {
-    order: 8;
-  }
-  .order-md-9 {
-    order: 9;
-  }
-  .order-md-10 {
-    order: 10;
-  }
-  .order-md-11 {
-    order: 11;
-  }
-  .order-md-12 {
-    order: 12;
-  }
-  .offset-md-0 {
-    margin-left: 0;
-  }
-  .offset-md-1 {
-    margin-left: 8.33333%;
-  }
-  .offset-md-2 {
-    margin-left: 16.66667%;
-  }
-  .offset-md-3 {
-    margin-left: 25%;
-  }
-  .offset-md-4 {
-    margin-left: 33.33333%;
-  }
-  .offset-md-5 {
-    margin-left: 41.66667%;
-  }
-  .offset-md-6 {
-    margin-left: 50%;
-  }
-  .offset-md-7 {
-    margin-left: 58.33333%;
-  }
-  .offset-md-8 {
-    margin-left: 66.66667%;
-  }
-  .offset-md-9 {
-    margin-left: 75%;
-  }
-  .offset-md-10 {
-    margin-left: 83.33333%;
-  }
-  .offset-md-11 {
-    margin-left: 91.66667%;
-  }
-}
-
-@media (min-width: 992px) {
-  .col-lg {
-    flex-basis: 0;
-    flex-grow: 1;
-    max-width: 100%;
-  }
-  .row-cols-lg-1 > * {
-    flex: 0 0 100%;
-    max-width: 100%;
-  }
-  .row-cols-lg-2 > * {
-    flex: 0 0 50%;
-    max-width: 50%;
-  }
-  .row-cols-lg-3 > * {
-    flex: 0 0 33.33333%;
-    max-width: 33.33333%;
-  }
-  .row-cols-lg-4 > * {
-    flex: 0 0 25%;
-    max-width: 25%;
-  }
-  .row-cols-lg-5 > * {
-    flex: 0 0 20%;
-    max-width: 20%;
-  }
-  .row-cols-lg-6 > * {
-    flex: 0 0 16.66667%;
-    max-width: 16.66667%;
-  }
-  .col-lg-auto {
-    flex: 0 0 auto;
-    width: auto;
-    max-width: 100%;
-  }
-  .col-lg-1 {
-    flex: 0 0 8.33333%;
-    max-width: 8.33333%;
-  }
-  .col-lg-2 {
-    flex: 0 0 16.66667%;
-    max-width: 16.66667%;
-  }
-  .col-lg-3 {
-    flex: 0 0 25%;
-    max-width: 25%;
-  }
-  .col-lg-4 {
-    flex: 0 0 33.33333%;
-    max-width: 33.33333%;
-  }
-  .col-lg-5 {
-    flex: 0 0 41.66667%;
-    max-width: 41.66667%;
-  }
-  .col-lg-6 {
-    flex: 0 0 50%;
-    max-width: 50%;
-  }
-  .col-lg-7 {
-    flex: 0 0 58.33333%;
-    max-width: 58.33333%;
-  }
-  .col-lg-8 {
-    flex: 0 0 66.66667%;
-    max-width: 66.66667%;
-  }
-  .col-lg-9 {
-    flex: 0 0 75%;
-    max-width: 75%;
-  }
-  .col-lg-10 {
-    flex: 0 0 83.33333%;
-    max-width: 83.33333%;
-  }
-  .col-lg-11 {
-    flex: 0 0 91.66667%;
-    max-width: 91.66667%;
-  }
-  .col-lg-12 {
-    flex: 0 0 100%;
-    max-width: 100%;
-  }
-  .order-lg-first {
-    order: -1;
-  }
-  .order-lg-last {
-    order: 13;
-  }
-  .order-lg-0 {
-    order: 0;
-  }
-  .order-lg-1 {
-    order: 1;
-  }
-  .order-lg-2 {
-    order: 2;
-  }
-  .order-lg-3 {
-    order: 3;
-  }
-  .order-lg-4 {
-    order: 4;
-  }
-  .order-lg-5 {
-    order: 5;
-  }
-  .order-lg-6 {
-    order: 6;
-  }
-  .order-lg-7 {
-    order: 7;
-  }
-  .order-lg-8 {
-    order: 8;
-  }
-  .order-lg-9 {
-    order: 9;
-  }
-  .order-lg-10 {
-    order: 10;
-  }
-  .order-lg-11 {
-    order: 11;
-  }
-  .order-lg-12 {
-    order: 12;
-  }
-  .offset-lg-0 {
-    margin-left: 0;
-  }
-  .offset-lg-1 {
-    margin-left: 8.33333%;
-  }
-  .offset-lg-2 {
-    margin-left: 16.66667%;
-  }
-  .offset-lg-3 {
-    margin-left: 25%;
-  }
-  .offset-lg-4 {
-    margin-left: 33.33333%;
-  }
-  .offset-lg-5 {
-    margin-left: 41.66667%;
-  }
-  .offset-lg-6 {
-    margin-left: 50%;
-  }
-  .offset-lg-7 {
-    margin-left: 58.33333%;
-  }
-  .offset-lg-8 {
-    margin-left: 66.66667%;
-  }
-  .offset-lg-9 {
-    margin-left: 75%;
-  }
-  .offset-lg-10 {
-    margin-left: 83.33333%;
-  }
-  .offset-lg-11 {
-    margin-left: 91.66667%;
-  }
-}
-
-@media (min-width: 1200px) {
-  .col-xl {
-    flex-basis: 0;
-    flex-grow: 1;
-    max-width: 100%;
-  }
-  .row-cols-xl-1 > * {
-    flex: 0 0 100%;
-    max-width: 100%;
-  }
-  .row-cols-xl-2 > * {
-    flex: 0 0 50%;
-    max-width: 50%;
-  }
-  .row-cols-xl-3 > * {
-    flex: 0 0 33.33333%;
-    max-width: 33.33333%;
-  }
-  .row-cols-xl-4 > * {
-    flex: 0 0 25%;
-    max-width: 25%;
-  }
-  .row-cols-xl-5 > * {
-    flex: 0 0 20%;
-    max-width: 20%;
-  }
-  .row-cols-xl-6 > * {
-    flex: 0 0 16.66667%;
-    max-width: 16.66667%;
-  }
-  .col-xl-auto {
-    flex: 0 0 auto;
-    width: auto;
-    max-width: 100%;
-  }
-  .col-xl-1 {
-    flex: 0 0 8.33333%;
-    max-width: 8.33333%;
-  }
-  .col-xl-2 {
-    flex: 0 0 16.66667%;
-    max-width: 16.66667%;
-  }
-  .col-xl-3 {
-    flex: 0 0 25%;
-    max-width: 25%;
-  }
-  .col-xl-4 {
-    flex: 0 0 33.33333%;
-    max-width: 33.33333%;
-  }
-  .col-xl-5 {
-    flex: 0 0 41.66667%;
-    max-width: 41.66667%;
-  }
-  .col-xl-6 {
-    flex: 0 0 50%;
-    max-width: 50%;
-  }
-  .col-xl-7 {
-    flex: 0 0 58.33333%;
-    max-width: 58.33333%;
-  }
-  .col-xl-8 {
-    flex: 0 0 66.66667%;
-    max-width: 66.66667%;
-  }
-  .col-xl-9 {
-    flex: 0 0 75%;
-    max-width: 75%;
-  }
-  .col-xl-10 {
-    flex: 0 0 83.33333%;
-    max-width: 83.33333%;
-  }
-  .col-xl-11 {
-    flex: 0 0 91.66667%;
-    max-width: 91.66667%;
-  }
-  .col-xl-12 {
-    flex: 0 0 100%;
-    max-width: 100%;
-  }
-  .order-xl-first {
-    order: -1;
-  }
-  .order-xl-last {
-    order: 13;
-  }
-  .order-xl-0 {
-    order: 0;
-  }
-  .order-xl-1 {
-    order: 1;
-  }
-  .order-xl-2 {
-    order: 2;
-  }
-  .order-xl-3 {
-    order: 3;
-  }
-  .order-xl-4 {
-    order: 4;
-  }
-  .order-xl-5 {
-    order: 5;
-  }
-  .order-xl-6 {
-    order: 6;
-  }
-  .order-xl-7 {
-    order: 7;
-  }
-  .order-xl-8 {
-    order: 8;
-  }
-  .order-xl-9 {
-    order: 9;
-  }
-  .order-xl-10 {
-    order: 10;
-  }
-  .order-xl-11 {
-    order: 11;
-  }
-  .order-xl-12 {
-    order: 12;
-  }
-  .offset-xl-0 {
-    margin-left: 0;
-  }
-  .offset-xl-1 {
-    margin-left: 8.33333%;
-  }
-  .offset-xl-2 {
-    margin-left: 16.66667%;
-  }
-  .offset-xl-3 {
-    margin-left: 25%;
-  }
-  .offset-xl-4 {
-    margin-left: 33.33333%;
-  }
-  .offset-xl-5 {
-    margin-left: 41.66667%;
-  }
-  .offset-xl-6 {
-    margin-left: 50%;
-  }
-  .offset-xl-7 {
-    margin-left: 58.33333%;
-  }
-  .offset-xl-8 {
-    margin-left: 66.66667%;
-  }
-  .offset-xl-9 {
-    margin-left: 75%;
-  }
-  .offset-xl-10 {
-    margin-left: 83.33333%;
-  }
-  .offset-xl-11 {
-    margin-left: 91.66667%;
-  }
-}
-
-.table {
-  width: 100%;
-  margin-bottom: 1rem;
-  color: #858796;
-}
-
-.table th,
-.table td {
-  padding: 0.75rem;
-  vertical-align: top;
-  border-top: 1px solid #e3e6f0;
-}
-
-.table thead th {
-  vertical-align: bottom;
-  border-bottom: 2px solid #e3e6f0;
-}
-
-.table tbody + tbody {
-  border-top: 2px solid #e3e6f0;
-}
-
-.table-sm th,
-.table-sm td {
-  padding: 0.3rem;
-}
-
-.table-bordered {
-  border: 1px solid #e3e6f0;
-}
-
-.table-bordered th,
-.table-bordered td {
-  border: 1px solid #e3e6f0;
-}
-
-.table-bordered thead th,
-.table-bordered thead td {
-  border-bottom-width: 2px;
-}
-
-.table-borderless th,
-.table-borderless td,
-.table-borderless thead th,
-.table-borderless tbody + tbody {
-  border: 0;
-}
-
-.table-striped tbody tr:nth-of-type(odd) {
-  background-color: rgba(0, 0, 0, 0.05);
-}
-
-.table-hover tbody tr:hover {
-  color: #858796;
-  background-color: rgba(0, 0, 0, 0.075);
-}
-
-.table-primary,
-.table-primary > th,
-.table-primary > td {
-  background-color: #cdd8f6;
-}
-
-.table-primary th,
-.table-primary td,
-.table-primary thead th,
-.table-primary tbody + tbody {
-  border-color: #a3b6ee;
-}
-
-.table-hover .table-primary:hover {
-  background-color: #b7c7f2;
-}
-
-.table-hover .table-primary:hover > td,
-.table-hover .table-primary:hover > th {
-  background-color: #b7c7f2;
-}
-
-.table-secondary,
-.table-secondary > th,
-.table-secondary > td {
-  background-color: #dddde2;
-}
-
-.table-secondary th,
-.table-secondary td,
-.table-secondary thead th,
-.table-secondary tbody + tbody {
-  border-color: #c0c1c8;
-}
-
-.table-hover .table-secondary:hover {
-  background-color: #cfcfd6;
-}
-
-.table-hover .table-secondary:hover > td,
-.table-hover .table-secondary:hover > th {
-  background-color: #cfcfd6;
-}
-
-.table-success,
-.table-success > th,
-.table-success > td {
-  background-color: #bff0de;
-}
-
-.table-success th,
-.table-success td,
-.table-success thead th,
-.table-success tbody + tbody {
-  border-color: #89e2c2;
-}
-
-.table-hover .table-success:hover {
-  background-color: #aaebd3;
-}
-
-.table-hover .table-success:hover > td,
-.table-hover .table-success:hover > th {
-  background-color: #aaebd3;
-}
-
-.table-info,
-.table-info > th,
-.table-info > td {
-  background-color: #c7ebf1;
-}
-
-.table-info th,
-.table-info td,
-.table-info thead th,
-.table-info tbody + tbody {
-  border-color: #96dbe4;
-}
-
-.table-hover .table-info:hover {
-  background-color: #b3e4ec;
-}
-
-.table-hover .table-info:hover > td,
-.table-hover .table-info:hover > th {
-  background-color: #b3e4ec;
-}
-
-.table-warning,
-.table-warning > th,
-.table-warning > td {
-  background-color: #fceec9;
-}
-
-.table-warning th,
-.table-warning td,
-.table-warning thead th,
-.table-warning tbody + tbody {
-  border-color: #fadf9b;
-}
-
-.table-hover .table-warning:hover {
-  background-color: #fbe6b1;
-}
-
-.table-hover .table-warning:hover > td,
-.table-hover .table-warning:hover > th {
-  background-color: #fbe6b1;
-}
-
-.table-danger,
-.table-danger > th,
-.table-danger > td {
-  background-color: #f8ccc8;
-}
-
-.table-danger th,
-.table-danger td,
-.table-danger thead th,
-.table-danger tbody + tbody {
-  border-color: #f3a199;
-}
-
-.table-hover .table-danger:hover {
-  background-color: #f5b7b1;
-}
-
-.table-hover .table-danger:hover > td,
-.table-hover .table-danger:hover > th {
-  background-color: #f5b7b1;
-}
-
-.table-light,
-.table-light > th,
-.table-light > td {
-  background-color: #fdfdfe;
-}
-
-.table-light th,
-.table-light td,
-.table-light thead th,
-.table-light tbody + tbody {
-  border-color: #fbfcfd;
-}
-
-.table-hover .table-light:hover {
-  background-color: #ececf6;
-}
-
-.table-hover .table-light:hover > td,
-.table-hover .table-light:hover > th {
-  background-color: #ececf6;
-}
-
-.table-dark,
-.table-dark > th,
-.table-dark > td {
-  background-color: #d1d1d5;
-}
-
-.table-dark th,
-.table-dark td,
-.table-dark thead th,
-.table-dark tbody + tbody {
-  border-color: #a9aab1;
-}
-
-.table-hover .table-dark:hover {
-  background-color: #c4c4c9;
-}
-
-.table-hover .table-dark:hover > td,
-.table-hover .table-dark:hover > th {
-  background-color: #c4c4c9;
-}
-
-.table-active,
-.table-active > th,
-.table-active > td {
-  background-color: rgba(0, 0, 0, 0.075);
-}
-
-.table-hover .table-active:hover {
-  background-color: rgba(0, 0, 0, 0.075);
-}
-
-.table-hover .table-active:hover > td,
-.table-hover .table-active:hover > th {
-  background-color: rgba(0, 0, 0, 0.075);
-}
-
-.table .thead-dark th {
-  color: #fff;
-  background-color: #5a5c69;
-  border-color: #6c6e7e;
-}
-
-.table .thead-light th {
-  color: #6e707e;
-  background-color: #eaecf4;
-  border-color: #e3e6f0;
-}
-
-.table-dark {
-  color: #fff;
-  background-color: #5a5c69;
-}
-
-.table-dark th,
-.table-dark td,
-.table-dark thead th {
-  border-color: #6c6e7e;
-}
-
-.table-dark.table-bordered {
-  border: 0;
-}
-
-.table-dark.table-striped tbody tr:nth-of-type(odd) {
-  background-color: rgba(255, 255, 255, 0.05);
-}
-
-.table-dark.table-hover tbody tr:hover {
-  color: #fff;
-  background-color: rgba(255, 255, 255, 0.075);
-}
-
-@media (max-width: 575.98px) {
-  .table-responsive-sm {
-    display: block;
-    width: 100%;
-    overflow-x: auto;
-    -webkit-overflow-scrolling: touch;
-  }
-  .table-responsive-sm > .table-bordered {
-    border: 0;
-  }
-}
-
-@media (max-width: 767.98px) {
-  .table-responsive-md {
-    display: block;
-    width: 100%;
-    overflow-x: auto;
-    -webkit-overflow-scrolling: touch;
-  }
-  .table-responsive-md > .table-bordered {
-    border: 0;
-  }
-}
-
-@media (max-width: 991.98px) {
-  .table-responsive-lg {
-    display: block;
-    width: 100%;
-    overflow-x: auto;
-    -webkit-overflow-scrolling: touch;
-  }
-  .table-responsive-lg > .table-bordered {
-    border: 0;
-  }
-}
-
-@media (max-width: 1199.98px) {
-  .table-responsive-xl {
-    display: block;
-    width: 100%;
-    overflow-x: auto;
-    -webkit-overflow-scrolling: touch;
-  }
-  .table-responsive-xl > .table-bordered {
-    border: 0;
-  }
-}
-
-.table-responsive {
-  display: block;
-  width: 100%;
-  overflow-x: auto;
-  -webkit-overflow-scrolling: touch;
-}
-
-.table-responsive > .table-bordered {
-  border: 0;
-}
-
-.form-control {
-  display: block;
-  width: 100%;
-  height: calc(1.5em + 0.75rem + 2px);
-  padding: 0.375rem 0.75rem;
-  font-size: 1rem;
-  font-weight: 400;
-  line-height: 1.5;
-  color: #6e707e;
-  background-color: #fff;
-  background-clip: padding-box;
-  border: 1px solid #d1d3e2;
-  border-radius: 0.35rem;
-  transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
-}
-
-@media (prefers-reduced-motion: reduce) {
-  .form-control {
-    transition: none;
-  }
-}
-
-.form-control::-ms-expand {
-  background-color: transparent;
-  border: 0;
-}
-
-.form-control:-moz-focusring {
-  color: transparent;
-  text-shadow: 0 0 0 #6e707e;
-}
-
-.form-control:focus {
-  color: #6e707e;
-  background-color: #fff;
-  border-color: #bac8f3;
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.25);
-}
-
-.form-control::-webkit-input-placeholder {
-  color: #858796;
-  opacity: 1;
-}
-
-.form-control::-moz-placeholder {
-  color: #858796;
-  opacity: 1;
-}
-
-.form-control:-ms-input-placeholder {
-  color: #858796;
-  opacity: 1;
-}
-
-.form-control::-ms-input-placeholder {
-  color: #858796;
-  opacity: 1;
-}
-
-.form-control::placeholder {
-  color: #858796;
-  opacity: 1;
-}
-
-.form-control:disabled, .form-control[readonly] {
-  background-color: #eaecf4;
-  opacity: 1;
-}
-
-input[type="date"].form-control,
-input[type="time"].form-control,
-input[type="datetime-local"].form-control,
-input[type="month"].form-control {
-  -webkit-appearance: none;
-  -moz-appearance: none;
-  appearance: none;
-}
-
-select.form-control:focus::-ms-value {
-  color: #6e707e;
-  background-color: #fff;
-}
-
-.form-control-file,
-.form-control-range {
-  display: block;
-  width: 100%;
-}
-
-.col-form-label {
-  padding-top: calc(0.375rem + 1px);
-  padding-bottom: calc(0.375rem + 1px);
-  margin-bottom: 0;
-  font-size: inherit;
-  line-height: 1.5;
-}
-
-.col-form-label-lg {
-  padding-top: calc(0.5rem + 1px);
-  padding-bottom: calc(0.5rem + 1px);
-  font-size: 1.25rem;
-  line-height: 1.5;
-}
-
-.col-form-label-sm {
-  padding-top: calc(0.25rem + 1px);
-  padding-bottom: calc(0.25rem + 1px);
-  font-size: 0.875rem;
-  line-height: 1.5;
-}
-
-.form-control-plaintext {
-  display: block;
-  width: 100%;
-  padding: 0.375rem 0;
-  margin-bottom: 0;
-  font-size: 1rem;
-  line-height: 1.5;
-  color: #858796;
-  background-color: transparent;
-  border: solid transparent;
-  border-width: 1px 0;
-}
-
-.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg {
-  padding-right: 0;
-  padding-left: 0;
-}
-
-.form-control-sm {
-  height: calc(1.5em + 0.5rem + 2px);
-  padding: 0.25rem 0.5rem;
-  font-size: 0.875rem;
-  line-height: 1.5;
-  border-radius: 0.2rem;
-}
-
-.form-control-lg {
-  height: calc(1.5em + 1rem + 2px);
-  padding: 0.5rem 1rem;
-  font-size: 1.25rem;
-  line-height: 1.5;
-  border-radius: 0.3rem;
-}
-
-select.form-control[size], select.form-control[multiple] {
-  height: auto;
-}
-
-textarea.form-control {
-  height: auto;
-}
-
-.form-group {
-  margin-bottom: 1rem;
-}
-
-.form-text {
-  display: block;
-  margin-top: 0.25rem;
-}
-
-.form-row {
-  display: flex;
-  flex-wrap: wrap;
-  margin-right: -5px;
-  margin-left: -5px;
-}
-
-.form-row > .col,
-.form-row > [class*="col-"] {
-  padding-right: 5px;
-  padding-left: 5px;
-}
-
-.form-check {
-  position: relative;
-  display: block;
-  padding-left: 1.25rem;
-}
-
-.form-check-input {
-  position: absolute;
-  margin-top: 0.3rem;
-  margin-left: -1.25rem;
-}
-
-.form-check-input[disabled] ~ .form-check-label,
-.form-check-input:disabled ~ .form-check-label {
-  color: #858796;
-}
-
-.form-check-label {
-  margin-bottom: 0;
-}
-
-.form-check-inline {
-  display: inline-flex;
-  align-items: center;
-  padding-left: 0;
-  margin-right: 0.75rem;
-}
-
-.form-check-inline .form-check-input {
-  position: static;
-  margin-top: 0;
-  margin-right: 0.3125rem;
-  margin-left: 0;
-}
-
-
-
-
-.btn {
-  display: inline-block;
-  font-weight: 400;
-  color: #858796;
-  text-align: center;
-  vertical-align: middle;
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-  user-select: none;
-  background-color: transparent;
-  border: 1px solid transparent;
-  padding: 0.375rem 0.75rem;
-  font-size: 1rem;
-  line-height: 1.5;
-  border-radius: 0.35rem;
-  transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
-}
-
-@media (prefers-reduced-motion: reduce) {
-  .btn {
-    transition: none;
-  }
-}
-
-.btn:hover {
-  color: #858796;
-  text-decoration: none;
-}
-
-.btn:focus, .btn.focus {
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.25);
-}
-
-.btn.disabled, .btn:disabled {
-  opacity: 0.65;
-}
-
-.btn:not(:disabled):not(.disabled) {
-  cursor: pointer;
-}
-
-a.btn.disabled,
-fieldset:disabled a.btn {
-  pointer-events: none;
-}
-
-.btn-primary {
-  color: #fff;
-  background-color: #4e73df;
-  border-color: #4e73df;
-}
-
-.btn-primary:hover {
-  color: #fff;
-  background-color: #2e59d9;
-  border-color: #2653d4;
-}
-
-.btn-primary:focus, .btn-primary.focus {
-  color: #fff;
-  background-color: #2e59d9;
-  border-color: #2653d4;
-  box-shadow: 0 0 0 0.2rem rgba(105, 136, 228, 0.5);
-}
-
-.btn-primary.disabled, .btn-primary:disabled {
-  color: #fff;
-  background-color: #4e73df;
-  border-color: #4e73df;
-}
-
-.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active,
-.show > .btn-primary.dropdown-toggle {
-  color: #fff;
-  background-color: #2653d4;
-  border-color: #244ec9;
-}
-
-.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus,
-.show > .btn-primary.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(105, 136, 228, 0.5);
-}
-
-.btn-secondary {
-  color: #fff;
-  background-color: #858796;
-  border-color: #858796;
-}
-
-.btn-secondary:hover {
-  color: #fff;
-  background-color: #717384;
-  border-color: #6b6d7d;
-}
-
-.btn-secondary:focus, .btn-secondary.focus {
-  color: #fff;
-  background-color: #717384;
-  border-color: #6b6d7d;
-  box-shadow: 0 0 0 0.2rem rgba(151, 153, 166, 0.5);
-}
-
-.btn-secondary.disabled, .btn-secondary:disabled {
-  color: #fff;
-  background-color: #858796;
-  border-color: #858796;
-}
-
-.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active,
-.show > .btn-secondary.dropdown-toggle {
-  color: #fff;
-  background-color: #6b6d7d;
-  border-color: #656776;
-}
-
-.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus,
-.show > .btn-secondary.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(151, 153, 166, 0.5);
-}
-
-.btn-success {
-  color: #fff;
-  background-color: #1cc88a;
-  border-color: #1cc88a;
-}
-
-.btn-success:hover {
-  color: #fff;
-  background-color: #17a673;
-  border-color: #169b6b;
-}
-
-.btn-success:focus, .btn-success.focus {
-  color: #fff;
-  background-color: #17a673;
-  border-color: #169b6b;
-  box-shadow: 0 0 0 0.2rem rgba(62, 208, 156, 0.5);
-}
-
-.btn-success.disabled, .btn-success:disabled {
-  color: #fff;
-  background-color: #1cc88a;
-  border-color: #1cc88a;
-}
-
-.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active,
-.show > .btn-success.dropdown-toggle {
-  color: #fff;
-  background-color: #169b6b;
-  border-color: #149063;
-}
-
-.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus,
-.show > .btn-success.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(62, 208, 156, 0.5);
-}
-
-.btn-info {
-  color: #fff;
-  background-color: #36b9cc;
-  border-color: #36b9cc;
-}
-
-.btn-info:hover {
-  color: #fff;
-  background-color: #2c9faf;
-  border-color: #2a96a5;
-}
-
-.btn-info:focus, .btn-info.focus {
-  color: #fff;
-  background-color: #2c9faf;
-  border-color: #2a96a5;
-  box-shadow: 0 0 0 0.2rem rgba(84, 196, 212, 0.5);
-}
-
-.btn-info.disabled, .btn-info:disabled {
-  color: #fff;
-  background-color: #36b9cc;
-  border-color: #36b9cc;
-}
-
-.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active,
-.show > .btn-info.dropdown-toggle {
-  color: #fff;
-  background-color: #2a96a5;
-  border-color: #278c9b;
-}
-
-.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus,
-.show > .btn-info.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(84, 196, 212, 0.5);
-}
-
-.btn-warning {
-  color: #fff;
-  background-color: #f6c23e;
-  border-color: #f6c23e;
-}
-
-.btn-warning:hover {
-  color: #fff;
-  background-color: #f4b619;
-  border-color: #f4b30d;
-}
-
-.btn-warning:focus, .btn-warning.focus {
-  color: #fff;
-  background-color: #f4b619;
-  border-color: #f4b30d;
-  box-shadow: 0 0 0 0.2rem rgba(247, 203, 91, 0.5);
-}
-
-.btn-warning.disabled, .btn-warning:disabled {
-  color: #fff;
-  background-color: #f6c23e;
-  border-color: #f6c23e;
-}
-
-.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active,
-.show > .btn-warning.dropdown-toggle {
-  color: #fff;
-  background-color: #f4b30d;
-  border-color: #e9aa0b;
-}
-
-.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus,
-.show > .btn-warning.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(247, 203, 91, 0.5);
-}
-
-.btn-danger {
-  color: #fff;
-  background-color: #e74a3b;
-  border-color: #e74a3b;
-}
-
-.btn-danger:hover {
-  color: #fff;
-  background-color: #e02d1b;
-  border-color: #d52a1a;
-}
-
-.btn-danger:focus, .btn-danger.focus {
-  color: #fff;
-  background-color: #e02d1b;
-  border-color: #d52a1a;
-  box-shadow: 0 0 0 0.2rem rgba(235, 101, 88, 0.5);
-}
-
-.btn-danger.disabled, .btn-danger:disabled {
-  color: #fff;
-  background-color: #e74a3b;
-  border-color: #e74a3b;
-}
-
-.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active,
-.show > .btn-danger.dropdown-toggle {
-  color: #fff;
-  background-color: #d52a1a;
-  border-color: #ca2819;
-}
-
-.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus,
-.show > .btn-danger.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(235, 101, 88, 0.5);
-}
-
-.btn-light {
-  color: #3a3b45;
-  background-color: #f8f9fc;
-  border-color: #f8f9fc;
-}
-
-.btn-light:hover {
-  color: #3a3b45;
-  background-color: #dde2f1;
-  border-color: #d4daed;
-}
-
-.btn-light:focus, .btn-light.focus {
-  color: #3a3b45;
-  background-color: #dde2f1;
-  border-color: #d4daed;
-  box-shadow: 0 0 0 0.2rem rgba(220, 221, 225, 0.5);
-}
-
-.btn-light.disabled, .btn-light:disabled {
-  color: #3a3b45;
-  background-color: #f8f9fc;
-  border-color: #f8f9fc;
-}
-
-.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active,
-.show > .btn-light.dropdown-toggle {
-  color: #3a3b45;
-  background-color: #d4daed;
-  border-color: #cbd3e9;
-}
-
-.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus,
-.show > .btn-light.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(220, 221, 225, 0.5);
-}
-
-.btn-dark {
-  color: #fff;
-  background-color: #5a5c69;
-  border-color: #5a5c69;
-}
-
-.btn-dark:hover {
-  color: #fff;
-  background-color: #484a54;
-  border-color: #42444e;
-}
-
-.btn-dark:focus, .btn-dark.focus {
-  color: #fff;
-  background-color: #484a54;
-  border-color: #42444e;
-  box-shadow: 0 0 0 0.2rem rgba(115, 116, 128, 0.5);
-}
-
-.btn-dark.disabled, .btn-dark:disabled {
-  color: #fff;
-  background-color: #5a5c69;
-  border-color: #5a5c69;
-}
-
-.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active,
-.show > .btn-dark.dropdown-toggle {
-  color: #fff;
-  background-color: #42444e;
-  border-color: #3d3e47;
-}
-
-.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus,
-.show > .btn-dark.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(115, 116, 128, 0.5);
-}
-
-.btn-outline-primary {
-  color: #4e73df;
-  border-color: #4e73df;
-}
-
-.btn-outline-primary:hover {
-  color: #fff;
-  background-color: #4e73df;
-  border-color: #4e73df;
-}
-
-.btn-outline-primary:focus, .btn-outline-primary.focus {
-  box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.5);
-}
-
-.btn-outline-primary.disabled, .btn-outline-primary:disabled {
-  color: #4e73df;
-  background-color: transparent;
-}
-
-.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active,
-.show > .btn-outline-primary.dropdown-toggle {
-  color: #fff;
-  background-color: #4e73df;
-  border-color: #4e73df;
-}
-
-.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus,
-.show > .btn-outline-primary.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.5);
-}
-
-.btn-outline-secondary {
-  color: #858796;
-  border-color: #858796;
-}
-
-.btn-outline-secondary:hover {
-  color: #fff;
-  background-color: #858796;
-  border-color: #858796;
-}
-
-.btn-outline-secondary:focus, .btn-outline-secondary.focus {
-  box-shadow: 0 0 0 0.2rem rgba(133, 135, 150, 0.5);
-}
-
-.btn-outline-secondary.disabled, .btn-outline-secondary:disabled {
-  color: #858796;
-  background-color: transparent;
-}
-
-.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active,
-.show > .btn-outline-secondary.dropdown-toggle {
-  color: #fff;
-  background-color: #858796;
-  border-color: #858796;
-}
-
-.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus,
-.show > .btn-outline-secondary.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(133, 135, 150, 0.5);
-}
-
-.btn-outline-success {
-  color: #1cc88a;
-  border-color: #1cc88a;
-}
-
-.btn-outline-success:hover {
-  color: #fff;
-  background-color: #1cc88a;
-  border-color: #1cc88a;
-}
-
-.btn-outline-success:focus, .btn-outline-success.focus {
-  box-shadow: 0 0 0 0.2rem rgba(28, 200, 138, 0.5);
-}
-
-.btn-outline-success.disabled, .btn-outline-success:disabled {
-  color: #1cc88a;
-  background-color: transparent;
-}
-
-.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active,
-.show > .btn-outline-success.dropdown-toggle {
-  color: #fff;
-  background-color: #1cc88a;
-  border-color: #1cc88a;
-}
-
-.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus,
-.show > .btn-outline-success.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(28, 200, 138, 0.5);
-}
-
-.btn-outline-info {
-  color: #36b9cc;
-  border-color: #36b9cc;
-}
-
-.btn-outline-info:hover {
-  color: #fff;
-  background-color: #36b9cc;
-  border-color: #36b9cc;
-}
-
-.btn-outline-info:focus, .btn-outline-info.focus {
-  box-shadow: 0 0 0 0.2rem rgba(54, 185, 204, 0.5);
-}
-
-.btn-outline-info.disabled, .btn-outline-info:disabled {
-  color: #36b9cc;
-  background-color: transparent;
-}
-
-.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active,
-.show > .btn-outline-info.dropdown-toggle {
-  color: #fff;
-  background-color: #36b9cc;
-  border-color: #36b9cc;
-}
-
-.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus,
-.show > .btn-outline-info.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(54, 185, 204, 0.5);
-}
-
-.btn-outline-warning {
-  color: #f6c23e;
-  border-color: #f6c23e;
-}
-
-.btn-outline-warning:hover {
-  color: #fff;
-  background-color: #f6c23e;
-  border-color: #f6c23e;
-}
-
-.btn-outline-warning:focus, .btn-outline-warning.focus {
-  box-shadow: 0 0 0 0.2rem rgba(246, 194, 62, 0.5);
-}
-
-.btn-outline-warning.disabled, .btn-outline-warning:disabled {
-  color: #f6c23e;
-  background-color: transparent;
-}
-
-.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active,
-.show > .btn-outline-warning.dropdown-toggle {
-  color: #fff;
-  background-color: #f6c23e;
-  border-color: #f6c23e;
-}
-
-.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus,
-.show > .btn-outline-warning.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(246, 194, 62, 0.5);
-}
-
-.btn-outline-danger {
-  color: #e74a3b;
-  border-color: #e74a3b;
-}
-
-.btn-outline-danger:hover {
-  color: #fff;
-  background-color: #e74a3b;
-  border-color: #e74a3b;
-}
-
-.btn-outline-danger:focus, .btn-outline-danger.focus {
-  box-shadow: 0 0 0 0.2rem rgba(231, 74, 59, 0.5);
-}
-
-.btn-outline-danger.disabled, .btn-outline-danger:disabled {
-  color: #e74a3b;
-  background-color: transparent;
-}
-
-.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active,
-.show > .btn-outline-danger.dropdown-toggle {
-  color: #fff;
-  background-color: #e74a3b;
-  border-color: #e74a3b;
-}
-
-.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus,
-.show > .btn-outline-danger.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(231, 74, 59, 0.5);
-}
-
-.btn-outline-light {
-  color: #f8f9fc;
-  border-color: #f8f9fc;
-}
-
-.btn-outline-light:hover {
-  color: #3a3b45;
-  background-color: #f8f9fc;
-  border-color: #f8f9fc;
-}
-
-.btn-outline-light:focus, .btn-outline-light.focus {
-  box-shadow: 0 0 0 0.2rem rgba(248, 249, 252, 0.5);
-}
-
-.btn-outline-light.disabled, .btn-outline-light:disabled {
-  color: #f8f9fc;
-  background-color: transparent;
-}
-
-.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active,
-.show > .btn-outline-light.dropdown-toggle {
-  color: #3a3b45;
-  background-color: #f8f9fc;
-  border-color: #f8f9fc;
-}
-
-.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus,
-.show > .btn-outline-light.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(248, 249, 252, 0.5);
-}
-
-.btn-outline-dark {
-  color: #5a5c69;
-  border-color: #5a5c69;
-}
-
-.btn-outline-dark:hover {
-  color: #fff;
-  background-color: #5a5c69;
-  border-color: #5a5c69;
-}
-
-.btn-outline-dark:focus, .btn-outline-dark.focus {
-  box-shadow: 0 0 0 0.2rem rgba(90, 92, 105, 0.5);
-}
-
-.btn-outline-dark.disabled, .btn-outline-dark:disabled {
-  color: #5a5c69;
-  background-color: transparent;
-}
-
-.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active,
-.show > .btn-outline-dark.dropdown-toggle {
-  color: #fff;
-  background-color: #5a5c69;
-  border-color: #5a5c69;
-}
-
-.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus,
-.show > .btn-outline-dark.dropdown-toggle:focus {
-  box-shadow: 0 0 0 0.2rem rgba(90, 92, 105, 0.5);
-}
-
-.btn-link {
-  font-weight: 400;
-  color: #4e73df;
-  text-decoration: none;
-}
-
-.btn-link:hover {
-  color: #224abe;
-  text-decoration: underline;
-}
-
-.btn-link:focus, .btn-link.focus {
-  text-decoration: underline;
-}
-
-.btn-link:disabled, .btn-link.disabled {
-  color: #858796;
-  pointer-events: none;
-}
-
-.btn-lg, .btn-group-lg > .btn {
-  padding: 0.5rem 1rem;
-  font-size: 1.25rem;
-  line-height: 1.5;
-  border-radius: 0.3rem;
-}
-
-.btn-sm, .btn-group-sm > .btn {
-  padding: 0.25rem 0.5rem;
-  font-size: 0.875rem;
-  line-height: 1.5;
-  border-radius: 0.2rem;
-}
-
-.btn-block {
-  display: block;
-  width: 100%;
-}
-
-.btn-block + .btn-block {
-  margin-top: 0.5rem;
-}
-
-input[type="submit"].btn-block,
-input[type="reset"].btn-block,
-input[type="button"].btn-block {
-  width: 100%;
-}
-
-.fade {
-  transition: opacity 0.15s linear;
-}
-
-@media (prefers-reduced-motion: reduce) {
-  .fade {
-    transition: none;
-  }
-}
-
-.fade:not(.show) {
-  opacity: 0;
-}
-
-.collapse:not(.show) {
-  display: none;
-}
-
-.collapsing {
-  position: relative;
-  height: 0;
-  overflow: hidden;
-  transition: height 0.15s ease;
-}
-
-@media (prefers-reduced-motion: reduce) {
-  .collapsing {
-    transition: none;
-  }
-}
-
-.dropup,
-.dropright,
-.dropdown,
-.dropleft {
-  position: relative;
-}
-
-.dropdown-toggle {
-  white-space: nowrap;
-}
-
-.dropdown-toggle::after {
-  display: inline-block;
-  margin-left: 0.255em;
-  vertical-align: 0.255em;
-  content: "";
-  border-top: 0.3em solid;
-  border-right: 0.3em solid transparent;
-  border-bottom: 0;
-  border-left: 0.3em solid transparent;
-}
-
-.dropdown-toggle:empty::after {
-  margin-left: 0;
-}
-
-.dropdown-menu {
-  position: absolute;
-  top: 100%;
-  left: 0;
-  z-index: 1000;
-  display: none;
-  float: left;
-  min-width: 10rem;
-  padding: 0.5rem 0;
-  margin: 0.125rem 0 0;
-  font-size: 0.85rem;
-  color: #858796;
-  text-align: left;
-  list-style: none;
-  background-color: #fff;
-  background-clip: padding-box;
-  border: 1px solid #e3e6f0;
-  border-radius: 0.35rem;
-}
-
-.dropdown-menu-left {
-  right: auto;
-  left: 0;
-}
-
-.dropdown-menu-right {
-  right: 0;
-  left: auto;
-}
-
-@media (min-width: 576px) {
-  .dropdown-menu-sm-left {
-    right: auto;
-    left: 0;
-  }
-  .dropdown-menu-sm-right {
-    right: 0;
-    left: auto;
-  }
-}
-
-@media (min-width: 768px) {
-  .dropdown-menu-md-left {
-    right: auto;
-    left: 0;
-  }
-  .dropdown-menu-md-right {
-    right: 0;
-    left: auto;
-  }
-}
-
-@media (min-width: 992px) {
-  .dropdown-menu-lg-left {
-    right: auto;
-    left: 0;
-  }
-  .dropdown-menu-lg-right {
-    right: 0;
-    left: auto;
-  }
-}
-
-@media (min-width: 1200px) {
-  .dropdown-menu-xl-left {
-    right: auto;
-    left: 0;
-  }
-  .dropdown-menu-xl-right {
-    right: 0;
-    left: auto;
-  }
-}
-
-.dropup .dropdown-menu {
-  top: auto;
-  bottom: 100%;
-  margin-top: 0;
-  margin-bottom: 0.125rem;
-}
-
-.dropup .dropdown-toggle::after {
-  display: inline-block;
-  margin-left: 0.255em;
-  vertical-align: 0.255em;
-  content: "";
-  border-top: 0;
-  border-right: 0.3em solid transparent;
-  border-bottom: 0.3em solid;
-  border-left: 0.3em solid transparent;
-}
-
-.dropup .dropdown-toggle:empty::after {
-  margin-left: 0;
-}
-
-.dropright .dropdown-menu {
-  top: 0;
-  right: auto;
-  left: 100%;
-  margin-top: 0;
-  margin-left: 0.125rem;
-}
-
-.dropright .dropdown-toggle::after {
-  display: inline-block;
-  margin-left: 0.255em;
-  vertical-align: 0.255em;
-  content: "";
-  border-top: 0.3em solid transparent;
-  border-right: 0;
-  border-bottom: 0.3em solid transparent;
-  border-left: 0.3em solid;
-}
-
-.dropright .dropdown-toggle:empty::after {
-  margin-left: 0;
-}
-
-.dropright .dropdown-toggle::after {
-  vertical-align: 0;
-}
-
-.dropleft .dropdown-menu {
-  top: 0;
-  right: 100%;
-  left: auto;
-  margin-top: 0;
-  margin-right: 0.125rem;
-}
-
-.dropleft .dropdown-toggle::after {
-  display: inline-block;
-  margin-left: 0.255em;
-  vertical-align: 0.255em;
-  content: "";
-}
-
-.dropleft .dropdown-toggle::after {
-  display: none;
-}
-
-.dropleft .dropdown-toggle::before {
-  display: inline-block;
-  margin-right: 0.255em;
-  vertical-align: 0.255em;
-  content: "";
-  border-top: 0.3em solid transparent;
-  border-right: 0.3em solid;
-  border-bottom: 0.3em solid transparent;
-}
-
-.dropleft .dropdown-toggle:empty::after {
-  margin-left: 0;
-}
-
-.dropleft .dropdown-toggle::before {
-  vertical-align: 0;
-}
-
-.dropdown-menu[x-placement^="top"], .dropdown-menu[x-placement^="right"], .dropdown-menu[x-placement^="bottom"], .dropdown-menu[x-placement^="left"] {
-  right: auto;
-  bottom: auto;
-}
-
-.dropdown-divider {
-  height: 0;
-  margin: 0.5rem 0;
-  overflow: hidden;
-  border-top: 1px solid #eaecf4;
-}
-
-.dropdown-item {
-  display: block;
-  width: 100%;
-  padding: 0.25rem 1.5rem;
-  clear: both;
-  font-weight: 400;
-  color: #3a3b45;
-  text-align: inherit;
-  white-space: nowrap;
-  background-color: transparent;
-  border: 0;
-}
-
-.dropdown-item:hover, .dropdown-item:focus {
-  color: #2e2f37;
-  text-decoration: none;
-  background-color: #eaecf4;
-}
-
-.dropdown-item.active, .dropdown-item:active {
-  color: #fff;
-  text-decoration: none;
-  background-color: #4e73df;
-}
-
-.dropdown-item.disabled, .dropdown-item:disabled {
-  color: #b7b9cc;
-  pointer-events: none;
-  background-color: transparent;
-}
-
-.dropdown-menu.show {
-  display: block;
-}
-
-.dropdown-header {
-  display: block;
-  padding: 0.5rem 1.5rem;
-  margin-bottom: 0;
-  font-size: 0.875rem;
-  color: #858796;
-  white-space: nowrap;
-}
-
-.dropdown-item-text {
-  display: block;
-  padding: 0.25rem 1.5rem;
-  color: #3a3b45;
-}
-
-.btn-group,
-.btn-group-vertical {
-  position: relative;
-  display: inline-flex;
-  vertical-align: middle;
-}
-
-.btn-group > .btn,
-.btn-group-vertical > .btn {
-  position: relative;
-  flex: 1 1 auto;
-}
-
-.btn-group > .btn:hover,
-.btn-group-vertical > .btn:hover {
-  z-index: 1;
-}
-
-.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,
-.btn-group-vertical > .btn:focus,
-.btn-group-vertical > .btn:active,
-.btn-group-vertical > .btn.active {
-  z-index: 1;
-}
-
-.btn-toolbar {
-  display: flex;
-  flex-wrap: wrap;
-  justify-content: flex-start;
-}
-
-.btn-toolbar .input-group {
-  width: auto;
-}
-
-.btn-group > .btn:not(:first-child),
-.btn-group > .btn-group:not(:first-child) {
-  margin-left: -1px;
-}
-
-.btn-group > .btn:not(:last-child):not(.dropdown-toggle),
-.btn-group > .btn-group:not(:last-child) > .btn {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-
-.btn-group > .btn:not(:first-child),
-.btn-group > .btn-group:not(:first-child) > .btn {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-
-.dropdown-toggle-split {
-  padding-right: 0.5625rem;
-  padding-left: 0.5625rem;
-}
-
-.dropdown-toggle-split::after,
-.dropup .dropdown-toggle-split::after,
-.dropright .dropdown-toggle-split::after {
-  margin-left: 0;
-}
-
-.dropleft .dropdown-toggle-split::before {
-  margin-right: 0;
-}
-
-.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {
-  padding-right: 0.375rem;
-  padding-left: 0.375rem;
-}
-
-.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {
-  padding-right: 0.75rem;
-  padding-left: 0.75rem;
-}
-
-.btn-group-vertical {
-  flex-direction: column;
-  align-items: flex-start;
-  justify-content: center;
-}
-
-.btn-group-vertical > .btn,
-.btn-group-vertical > .btn-group {
-  width: 100%;
-}
-
-.btn-group-vertical > .btn:not(:first-child),
-.btn-group-vertical > .btn-group:not(:first-child) {
-  margin-top: -1px;
-}
-
-.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),
-.btn-group-vertical > .btn-group:not(:last-child) > .btn {
-  border-bottom-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-
-.btn-group-vertical > .btn:not(:first-child),
-.btn-group-vertical > .btn-group:not(:first-child) > .btn {
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-
-.btn-group-toggle > .btn,
-.btn-group-toggle > .btn-group > .btn {
-  margin-bottom: 0;
-}
-
-.btn-group-toggle > .btn input[type="radio"],
-.btn-group-toggle > .btn input[type="checkbox"],
-.btn-group-toggle > .btn-group > .btn input[type="radio"],
-.btn-group-toggle > .btn-group > .btn input[type="checkbox"] {
-  position: absolute;
-  clip: rect(0, 0, 0, 0);
-  pointer-events: none;
-}
-
-.input-group {
-  position: relative;
-  display: flex;
-  flex-wrap: wrap;
-  align-items: stretch;
-  width: 100%;
-}
-
-
-
-
-
-.input-group-text {
-  display: flex;
-  align-items: center;
-  padding: 0.375rem 0.75rem;
-  margin-bottom: 0;
-  font-size: 1rem;
-  font-weight: 400;
-  line-height: 1.5;
-  color: #6e707e;
-  text-align: center;
-  white-space: nowrap;
-  background-color: #eaecf4;
-  border: 1px solid #d1d3e2;
-  border-radius: 0.35rem;
-}
-
-
-
-
-
-
-.nav {
-  display: flex;
-  flex-wrap: wrap;
-  padding-left: 0;
-  margin-bottom: 0;
-  list-style: none;
-}
-
-.nav-link {
-  display: block;
-  padding: 0.5rem 1rem;
-}
-
-.nav-link:hover, .nav-link:focus {
-  text-decoration: none;
-}
-
-.nav-link.disabled {
-  color: #858796;
-  pointer-events: none;
-  cursor: default;
-}
-
-.nav-tabs {
-  border-bottom: 1px solid #dddfeb;
-}
-
-.nav-tabs .nav-link {
-  margin-bottom: -1px;
-  border: 1px solid transparent;
-  border-top-left-radius: 0.35rem;
-  border-top-right-radius: 0.35rem;
-}
-
-.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {
-  border-color: #eaecf4 #eaecf4 #dddfeb;
-}
-
-.nav-tabs .nav-link.disabled {
-  color: #858796;
-  background-color: transparent;
-  border-color: transparent;
-}
-
-.nav-tabs .nav-link.active,
-.nav-tabs .nav-item.show .nav-link {
-  color: #6e707e;
-  background-color: #fff;
-  border-color: #dddfeb #dddfeb #fff;
-}
-
-.nav-tabs .dropdown-menu {
-  margin-top: -1px;
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-
-.nav-pills .nav-link {
-  border-radius: 0.35rem;
-}
-
-.nav-pills .nav-link.active,
-.nav-pills .show > .nav-link {
-  color: #fff;
-  background-color: #4e73df;
-}
-
-.nav-fill > .nav-link,
-.nav-fill .nav-item {
-  flex: 1 1 auto;
-  text-align: center;
-}
-
-.nav-justified > .nav-link,
-.nav-justified .nav-item {
-  flex-basis: 0;
-  flex-grow: 1;
-  text-align: center;
-}
-
-.tab-content > .tab-pane {
-  display: none;
-}
-
-.tab-content > .active {
-  display: block;
-}
-
-.navbar {
-  position: relative;
-  display: flex;
-  flex-wrap: wrap;
-  align-items: center;
-  justify-content: space-between;
-  padding: 0.5rem 1rem;
-}
-
-.navbar .container,
-.navbar .container-fluid, .navbar .container-sm, .navbar .container-md, .navbar .container-lg, .navbar .container-xl {
-  display: flex;
-  flex-wrap: wrap;
-  align-items: center;
-  justify-content: space-between;
-}
-
-.navbar-brand {
-  display: inline-block;
-  padding-top: 0.3125rem;
-  padding-bottom: 0.3125rem;
-  margin-right: 1rem;
-  font-size: 1.25rem;
-  line-height: inherit;
-  white-space: nowrap;
-}
-
-.navbar-brand:hover, .navbar-brand:focus {
-  text-decoration: none;
-}
-
-.navbar-nav {
-  display: flex;
-  flex-direction: column;
-  padding-left: 0;
-  margin-bottom: 0;
-  list-style: none;
-}
-
-.navbar-nav .nav-link {
-  padding-right: 0;
-  padding-left: 0;
-}
-
-.navbar-nav .dropdown-menu {
-  position: static;
-  float: none;
-}
-
-.navbar-text {
-  display: inline-block;
-  padding-top: 0.5rem;
-  padding-bottom: 0.5rem;
-}
-
-.navbar-collapse {
-  flex-basis: 100%;
-  flex-grow: 1;
-  align-items: center;
-}
-
-.navbar-toggler {
-  padding: 0.25rem 0.75rem;
-  font-size: 1.25rem;
-  line-height: 1;
-  background-color: transparent;
-  border: 1px solid transparent;
-  border-radius: 0.35rem;
-}
-
-.navbar-toggler:hover, .navbar-toggler:focus {
-  text-decoration: none;
-}
-
-.navbar-toggler-icon {
-  display: inline-block;
-  width: 1.5em;
-  height: 1.5em;
-  vertical-align: middle;
-  content: "";
-  background: 50% / 100% 100% no-repeat;
-}
-
-.navbar-nav-scroll {
-  max-height: 75vh;
-  overflow-y: auto;
-}
-
-@media (max-width: 575.98px) {
-  .navbar-expand-sm > .container,
-  .navbar-expand-sm > .container-fluid, .navbar-expand-sm > .container-sm, .navbar-expand-sm > .container-md, .navbar-expand-sm > .container-lg, .navbar-expand-sm > .container-xl {
-    padding-right: 0;
-    padding-left: 0;
-  }
-}
-
-@media (min-width: 576px) {
-  .navbar-expand-sm {
-    flex-flow: row nowrap;
-    justify-content: flex-start;
-  }
-  .navbar-expand-sm .navbar-nav {
-    flex-direction: row;
-  }
-  .navbar-expand-sm .navbar-nav .dropdown-menu {
-    position: absolute;
-  }
-  .navbar-expand-sm .navbar-nav .nav-link {
-    padding-right: 0.5rem;
-    padding-left: 0.5rem;
-  }
-  .navbar-expand-sm > .container,
-  .navbar-expand-sm > .container-fluid, .navbar-expand-sm > .container-sm, .navbar-expand-sm > .container-md, .navbar-expand-sm > .container-lg, .navbar-expand-sm > .container-xl {
-    flex-wrap: nowrap;
-  }
-  .navbar-expand-sm .navbar-nav-scroll {
-    overflow: visible;
-  }
-  .navbar-expand-sm .navbar-collapse {
-    display: flex !important;
-    flex-basis: auto;
-  }
-  .navbar-expand-sm .navbar-toggler {
-    display: none;
-  }
-}
-
-@media (max-width: 767.98px) {
-  .navbar-expand-md > .container,
-  .navbar-expand-md > .container-fluid, .navbar-expand-md > .container-sm, .navbar-expand-md > .container-md, .navbar-expand-md > .container-lg, .navbar-expand-md > .container-xl {
-    padding-right: 0;
-    padding-left: 0;
-  }
-}
-
-@media (min-width: 768px) {
-  .navbar-expand-md {
-    flex-flow: row nowrap;
-    justify-content: flex-start;
-  }
-  .navbar-expand-md .navbar-nav {
-    flex-direction: row;
-  }
-  .navbar-expand-md .navbar-nav .dropdown-menu {
-    position: absolute;
-  }
-  .navbar-expand-md .navbar-nav .nav-link {
-    padding-right: 0.5rem;
-    padding-left: 0.5rem;
-  }
-  .navbar-expand-md > .container,
-  .navbar-expand-md > .container-fluid, .navbar-expand-md > .container-sm, .navbar-expand-md > .container-md, .navbar-expand-md > .container-lg, .navbar-expand-md > .container-xl {
-    flex-wrap: nowrap;
-  }
-  .navbar-expand-md .navbar-nav-scroll {
-    overflow: visible;
-  }
-  .navbar-expand-md .navbar-collapse {
-    display: flex !important;
-    flex-basis: auto;
-  }
-  .navbar-expand-md .navbar-toggler {
-    display: none;
-  }
-}
-
-@media (max-width: 991.98px) {
-  .navbar-expand-lg > .container,
-  .navbar-expand-lg > .container-fluid, .navbar-expand-lg > .container-sm, .navbar-expand-lg > .container-md, .navbar-expand-lg > .container-lg, .navbar-expand-lg > .container-xl {
-    padding-right: 0;
-    padding-left: 0;
-  }
-}
-
-@media (min-width: 992px) {
-  .navbar-expand-lg {
-    flex-flow: row nowrap;
-    justify-content: flex-start;
-  }
-  .navbar-expand-lg .navbar-nav {
-    flex-direction: row;
-  }
-  .navbar-expand-lg .navbar-nav .dropdown-menu {
-    position: absolute;
-  }
-  .navbar-expand-lg .navbar-nav .nav-link {
-    padding-right: 0.5rem;
-    padding-left: 0.5rem;
-  }
-  .navbar-expand-lg > .container,
-  .navbar-expand-lg > .container-fluid, .navbar-expand-lg > .container-sm, .navbar-expand-lg > .container-md, .navbar-expand-lg > .container-lg, .navbar-expand-lg > .container-xl {
-    flex-wrap: nowrap;
-  }
-  .navbar-expand-lg .navbar-nav-scroll {
-    overflow: visible;
-  }
-  .navbar-expand-lg .navbar-collapse {
-    display: flex !important;
-    flex-basis: auto;
-  }
-  .navbar-expand-lg .navbar-toggler {
-    display: none;
-  }
-}
-
-@media (max-width: 1199.98px) {
-  .navbar-expand-xl > .container,
-  .navbar-expand-xl > .container-fluid, .navbar-expand-xl > .container-sm, .navbar-expand-xl > .container-md, .navbar-expand-xl > .container-lg, .navbar-expand-xl > .container-xl {
-    padding-right: 0;
-    padding-left: 0;
-  }
-}
-
-@media (min-width: 1200px) {
-  .navbar-expand-xl {
-    flex-flow: row nowrap;
-    justify-content: flex-start;
-  }
-  .navbar-expand-xl .navbar-nav {
-    flex-direction: row;
-  }
-  .navbar-expand-xl .navbar-nav .dropdown-menu {
-    position: absolute;
-  }
-  .navbar-expand-xl .navbar-nav .nav-link {
-    padding-right: 0.5rem;
-    padding-left: 0.5rem;
-  }
-  .navbar-expand-xl > .container,
-  .navbar-expand-xl > .container-fluid, .navbar-expand-xl > .container-sm, .navbar-expand-xl > .container-md, .navbar-expand-xl > .container-lg, .navbar-expand-xl > .container-xl {
-    flex-wrap: nowrap;
-  }
-  .navbar-expand-xl .navbar-nav-scroll {
-    overflow: visible;
-  }
-  .navbar-expand-xl .navbar-collapse {
-    display: flex !important;
-    flex-basis: auto;
-  }
-  .navbar-expand-xl .navbar-toggler {
-    display: none;
-  }
-}
-
-.navbar-expand {
-  flex-flow: row nowrap;
-  justify-content: flex-start;
-}
-
-.navbar-expand > .container,
-.navbar-expand > .container-fluid, .navbar-expand > .container-sm, .navbar-expand > .container-md, .navbar-expand > .container-lg, .navbar-expand > .container-xl {
-  padding-right: 0;
-  padding-left: 0;
-}
-
-.navbar-expand .navbar-nav {
-  flex-direction: row;
-}
-
-.navbar-expand .navbar-nav .dropdown-menu {
-  position: absolute;
-}
-
-.navbar-expand .navbar-nav .nav-link {
-  padding-right: 0.5rem;
-  padding-left: 0.5rem;
-}
-
-.navbar-expand > .container,
-.navbar-expand > .container-fluid, .navbar-expand > .container-sm, .navbar-expand > .container-md, .navbar-expand > .container-lg, .navbar-expand > .container-xl {
-  flex-wrap: nowrap;
-}
-
-.navbar-expand .navbar-nav-scroll {
-  overflow: visible;
-}
-
-.navbar-expand .navbar-collapse {
-  display: flex !important;
-  flex-basis: auto;
-}
-
-.navbar-expand .navbar-toggler {
-  display: none;
-}
-
-.navbar-light .navbar-brand {
-  color: rgba(0, 0, 0, 0.9);
-}
-
-.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus {
-  color: rgba(0, 0, 0, 0.9);
-}
-
-.navbar-light .navbar-nav .nav-link {
-  color: rgba(0, 0, 0, 0.5);
-}
-
-.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {
-  color: rgba(0, 0, 0, 0.7);
-}
-
-.navbar-light .navbar-nav .nav-link.disabled {
-  color: rgba(0, 0, 0, 0.3);
-}
-
-.navbar-light .navbar-nav .show > .nav-link,
-.navbar-light .navbar-nav .active > .nav-link,
-.navbar-light .navbar-nav .nav-link.show,
-.navbar-light .navbar-nav .nav-link.active {
-  color: rgba(0, 0, 0, 0.9);
-}
-
-.navbar-light .navbar-toggler {
-  color: rgba(0, 0, 0, 0.5);
-  border-color: rgba(0, 0, 0, 0.1);
-}
-
-.navbar-light .navbar-toggler-icon {
-  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
-}
-
-.navbar-light .navbar-text {
-  color: rgba(0, 0, 0, 0.5);
-}
-
-.navbar-light .navbar-text a {
-  color: rgba(0, 0, 0, 0.9);
-}
-
-.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus {
-  color: rgba(0, 0, 0, 0.9);
-}
-
-.navbar-dark .navbar-brand {
-  color: #fff;
-}
-
-.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus {
-  color: #fff;
-}
-
-.navbar-dark .navbar-nav .nav-link {
-  color: rgba(255, 255, 255, 0.5);
-}
-
-.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus {
-  color: rgba(255, 255, 255, 0.75);
-}
-
-.navbar-dark .navbar-nav .nav-link.disabled {
-  color: rgba(255, 255, 255, 0.25);
-}
-
-.navbar-dark .navbar-nav .show > .nav-link,
-.navbar-dark .navbar-nav .active > .nav-link,
-.navbar-dark .navbar-nav .nav-link.show,
-.navbar-dark .navbar-nav .nav-link.active {
-  color: #fff;
-}
-
-.navbar-dark .navbar-toggler {
-  color: rgba(255, 255, 255, 0.5);
-  border-color: rgba(255, 255, 255, 0.1);
-}
-
-.navbar-dark .navbar-toggler-icon {
-  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
-}
-
-.navbar-dark .navbar-text {
-  color: rgba(255, 255, 255, 0.5);
-}
-
-.navbar-dark .navbar-text a {
-  color: #fff;
-}
-
-.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus {
-  color: #fff;
-}
-
-.card {
-  position: relative;
-  display: flex;
-  flex-direction: column;
-  min-width: 0;
-  word-wrap: break-word;
-  background-color: #fff;
-  background-clip: border-box;
-  border: 1px solid #e3e6f0;
-  border-radius: 0.35rem;
-}
-
-.card > hr {
-  margin-right: 0;
-  margin-left: 0;
-}
-
-.card > .list-group {
-  border-top: inherit;
-  border-bottom: inherit;
-}
-
-.card > .list-group:first-child {
-  border-top-width: 0;
-  border-top-left-radius: calc(0.35rem - 1px);
-  border-top-right-radius: calc(0.35rem - 1px);
-}
-
-.card > .list-group:last-child {
-  border-bottom-width: 0;
-  border-bottom-right-radius: calc(0.35rem - 1px);
-  border-bottom-left-radius: calc(0.35rem - 1px);
-}
-
-.card > .card-header + .list-group,
-.card > .list-group + .card-footer {
-  border-top: 0;
-}
-
-.card-body {
-  flex: 1 1 auto;
-  min-height: 1px;
-  padding: 1.25rem;
-}
-
-.card-title {
-  margin-bottom: 0.75rem;
-}
-
-.card-subtitle {
-  margin-top: -0.375rem;
-  margin-bottom: 0;
-}
-
-.card-text:last-child {
-  margin-bottom: 0;
-}
-
-.card-link:hover {
-  text-decoration: none;
-}
-
-.card-link + .card-link {
-  margin-left: 1.25rem;
-}
-
-.card-header {
-  padding: 0.75rem 1.25rem;
-  margin-bottom: 0;
-  background-color: #f8f9fc;
-  border-bottom: 1px solid #e3e6f0;
-}
-
-.card-header:first-child {
-  border-radius: calc(0.35rem - 1px) calc(0.35rem - 1px) 0 0;
-}
-
-.card-footer {
-  padding: 0.75rem 1.25rem;
-  background-color: #f8f9fc;
-  border-top: 1px solid #e3e6f0;
-}
-
-.card-footer:last-child {
-  border-radius: 0 0 calc(0.35rem - 1px) calc(0.35rem - 1px);
-}
-
-.card-header-tabs {
-  margin-right: -0.625rem;
-  margin-bottom: -0.75rem;
-  margin-left: -0.625rem;
-  border-bottom: 0;
-}
-
-.card-header-pills {
-  margin-right: -0.625rem;
-  margin-left: -0.625rem;
-}
-
-.card-img-overlay {
-  position: absolute;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  padding: 1.25rem;
-  border-radius: calc(0.35rem - 1px);
-}
-
-.card-img,
-.card-img-top,
-.card-img-bottom {
-  flex-shrink: 0;
-  width: 100%;
-}
-
-.card-img,
-.card-img-top {
-  border-top-left-radius: calc(0.35rem - 1px);
-  border-top-right-radius: calc(0.35rem - 1px);
-}
-
-.card-img,
-.card-img-bottom {
-  border-bottom-right-radius: calc(0.35rem - 1px);
-  border-bottom-left-radius: calc(0.35rem - 1px);
-}
-
-.card-deck .card {
-  margin-bottom: 0.75rem;
-}
-
-@media (min-width: 576px) {
-  .card-deck {
-    display: flex;
-    flex-flow: row wrap;
-    margin-right: -0.75rem;
-    margin-left: -0.75rem;
-  }
-  .card-deck .card {
-    flex: 1 0 0%;
-    margin-right: 0.75rem;
-    margin-bottom: 0;
-    margin-left: 0.75rem;
-  }
-}
-
-.card-group > .card {
-  margin-bottom: 0.75rem;
-}
-
-@media (min-width: 576px) {
-  .card-group {
-    display: flex;
-    flex-flow: row wrap;
-  }
-  .card-group > .card {
-    flex: 1 0 0%;
-    margin-bottom: 0;
-  }
-  .card-group > .card + .card {
-    margin-left: 0;
-    border-left: 0;
-  }
-  .card-group > .card:not(:last-child) {
-    border-top-right-radius: 0;
-    border-bottom-right-radius: 0;
-  }
-  .card-group > .card:not(:last-child) .card-img-top,
-  .card-group > .card:not(:last-child) .card-header {
-    border-top-right-radius: 0;
-  }
-  .card-group > .card:not(:last-child) .card-img-bottom,
-  .card-group > .card:not(:last-child) .card-footer {
-    border-bottom-right-radius: 0;
-  }
-  .card-group > .card:not(:first-child) {
-    border-top-left-radius: 0;
-    border-bottom-left-radius: 0;
-  }
-  .card-group > .card:not(:first-child) .card-img-top,
-  .card-group > .card:not(:first-child) .card-header {
-    border-top-left-radius: 0;
-  }
-  .card-group > .card:not(:first-child) .card-img-bottom,
-  .card-group > .card:not(:first-child) .card-footer {
-    border-bottom-left-radius: 0;
-  }
-}
-
-.card-columns .card {
-  margin-bottom: 0.75rem;
-}
-
-@media (min-width: 576px) {
-  .card-columns {
-    -moz-column-count: 3;
-    column-count: 3;
-    -moz-column-gap: 1.25rem;
-    column-gap: 1.25rem;
-    orphans: 1;
-    widows: 1;
-  }
-  .card-columns .card {
-    display: inline-block;
-    width: 100%;
-  }
-}
-
-.accordion {
-  overflow-anchor: none;
-}
-
-.accordion > .card {
-  overflow: hidden;
-}
-
-.accordion > .card:not(:last-of-type) {
-  border-bottom: 0;
-  border-bottom-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-
-.accordion > .card:not(:first-of-type) {
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-
-.accordion > .card > .card-header {
-  border-radius: 0;
-  margin-bottom: -1px;
-}
-
-
-
-
-
-.pagination {
-  display: flex;
-  padding-left: 0;
-  list-style: none;
-  border-radius: 0.35rem;
-}
-
-.page-link {
-  position: relative;
-  display: block;
-  padding: 0.5rem 0.75rem;
-  margin-left: -1px;
-  line-height: 1.25;
-  color: #4e73df;
-  background-color: #fff;
-  border: 1px solid #dddfeb;
-}
-
-.page-link:hover {
-  z-index: 2;
-  color: #224abe;
-  text-decoration: none;
-  background-color: #eaecf4;
-  border-color: #dddfeb;
-}
-
-.page-link:focus {
-  z-index: 3;
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.25);
-}
-
-.page-item:first-child .page-link {
-  margin-left: 0;
-  border-top-left-radius: 0.35rem;
-  border-bottom-left-radius: 0.35rem;
-}
-
-.page-item:last-child .page-link {
-  border-top-right-radius: 0.35rem;
-  border-bottom-right-radius: 0.35rem;
-}
-
-.page-item.active .page-link {
-  z-index: 3;
-  color: #fff;
-  background-color: #4e73df;
-  border-color: #4e73df;
-}
-
-.page-item.disabled .page-link {
-  color: #858796;
-  pointer-events: none;
-  cursor: auto;
-  background-color: #fff;
-  border-color: #dddfeb;
-}
-
-.pagination-lg .page-link {
-  padding: 0.75rem 1.5rem;
-  font-size: 1.25rem;
-  line-height: 1.5;
-}
-
-.pagination-lg .page-item:first-child .page-link {
-  border-top-left-radius: 0.3rem;
-  border-bottom-left-radius: 0.3rem;
-}
-
-.pagination-lg .page-item:last-child .page-link {
-  border-top-right-radius: 0.3rem;
-  border-bottom-right-radius: 0.3rem;
-}
-
-.pagination-sm .page-link {
-  padding: 0.25rem 0.5rem;
-  font-size: 0.875rem;
-  line-height: 1.5;
-}
-
-.pagination-sm .page-item:first-child .page-link {
-  border-top-left-radius: 0.2rem;
-  border-bottom-left-radius: 0.2rem;
-}
-
-.pagination-sm .page-item:last-child .page-link {
-  border-top-right-radius: 0.2rem;
-  border-bottom-right-radius: 0.2rem;
-}
-
-.badge {
-  display: inline-block;
-  padding: 0.25em 0.4em;
-  font-size: 75%;
-  font-weight: 700;
-  line-height: 1;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: baseline;
-  border-radius: 0.35rem;
-  transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
-}
-
-@media (prefers-reduced-motion: reduce) {
-  .badge {
-    transition: none;
-  }
-}
-
-a.badge:hover, a.badge:focus {
-  text-decoration: none;
-}
-
-.badge:empty {
-  display: none;
-}
-
-.btn .badge {
-  position: relative;
-  top: -1px;
-}
-
-.badge-pill {
-  padding-right: 0.6em;
-  padding-left: 0.6em;
-  border-radius: 10rem;
-}
-
-.badge-primary {
-  color: #fff;
-  background-color: #4e73df;
-}
-
-a.badge-primary:hover, a.badge-primary:focus {
-  color: #fff;
-  background-color: #2653d4;
-}
-
-a.badge-primary:focus, a.badge-primary.focus {
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.5);
-}
-
-.badge-secondary {
-  color: #fff;
-  background-color: #858796;
-}
-
-a.badge-secondary:hover, a.badge-secondary:focus {
-  color: #fff;
-  background-color: #6b6d7d;
-}
-
-a.badge-secondary:focus, a.badge-secondary.focus {
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(133, 135, 150, 0.5);
-}
-
-.badge-success {
-  color: #fff;
-  background-color: #1cc88a;
-}
-
-a.badge-success:hover, a.badge-success:focus {
-  color: #fff;
-  background-color: #169b6b;
-}
-
-a.badge-success:focus, a.badge-success.focus {
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(28, 200, 138, 0.5);
-}
-
-.badge-info {
-  color: #fff;
-  background-color: #36b9cc;
-}
-
-a.badge-info:hover, a.badge-info:focus {
-  color: #fff;
-  background-color: #2a96a5;
-}
-
-a.badge-info:focus, a.badge-info.focus {
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(54, 185, 204, 0.5);
-}
-
-.badge-warning {
-  color: #fff;
-  background-color: #f6c23e;
-}
-
-a.badge-warning:hover, a.badge-warning:focus {
-  color: #fff;
-  background-color: #f4b30d;
-}
-
-a.badge-warning:focus, a.badge-warning.focus {
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(246, 194, 62, 0.5);
-}
-
-.badge-danger {
-  color: #fff;
-  background-color: #e74a3b;
-}
-
-a.badge-danger:hover, a.badge-danger:focus {
-  color: #fff;
-  background-color: #d52a1a;
-}
-
-a.badge-danger:focus, a.badge-danger.focus {
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(231, 74, 59, 0.5);
-}
-
-.badge-light {
-  color: #3a3b45;
-  background-color: #f8f9fc;
-}
-
-a.badge-light:hover, a.badge-light:focus {
-  color: #3a3b45;
-  background-color: #d4daed;
-}
-
-a.badge-light:focus, a.badge-light.focus {
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(248, 249, 252, 0.5);
-}
-
-.badge-dark {
-  color: #fff;
-  background-color: #5a5c69;
-}
-
-a.badge-dark:hover, a.badge-dark:focus {
-  color: #fff;
-  background-color: #42444e;
-}
-
-a.badge-dark:focus, a.badge-dark.focus {
-  outline: 0;
-  box-shadow: 0 0 0 0.2rem rgba(90, 92, 105, 0.5);
-}
-
-.jumbotron {
-  padding: 2rem 1rem;
-  margin-bottom: 2rem;
-  background-color: #eaecf4;
-  border-radius: 0.3rem;
-}
-
-@media (min-width: 576px) {
-  .jumbotron {
-    padding: 4rem 2rem;
-  }
-}
-
-.jumbotron-fluid {
-  padding-right: 0;
-  padding-left: 0;
-  border-radius: 0;
-}
-
-.alert {
-  position: relative;
-  padding: 0.75rem 1.25rem;
-  margin-bottom: 1rem;
-  border: 1px solid transparent;
-  border-radius: 0.35rem;
-}
-
-.alert-heading {
-  color: inherit;
-}
-
-.alert-link {
-  font-weight: 700;
-}
-
-.alert-dismissible {
-  padding-right: 4rem;
-}
-
-.alert-dismissible .close {
-  position: absolute;
-  top: 0;
-  right: 0;
-  z-index: 2;
-  padding: 0.75rem 1.25rem;
-  color: inherit;
-}
-
-.alert-primary {
-  color: #293c74;
-  background-color: #dce3f9;
-  border-color: #cdd8f6;
-}
-
-.alert-primary hr {
-  border-top-color: #b7c7f2;
-}
-
-.alert-primary .alert-link {
-  color: #1c294e;
-}
-
-.alert-secondary {
-  color: #45464e;
-  background-color: #e7e7ea;
-  border-color: #dddde2;
-}
-
-.alert-secondary hr {
-  border-top-color: #cfcfd6;
-}
-
-.alert-secondary .alert-link {
-  color: #2d2e33;
-}
-
-.alert-success {
-  color: #0f6848;
-  background-color: #d2f4e8;
-  border-color: #bff0de;
-}
-
-.alert-success hr {
-  border-top-color: #aaebd3;
-}
-
-.alert-success .alert-link {
-  color: #093b29;
-}
-
-.alert-info {
-  color: #1c606a;
-  background-color: #d7f1f5;
-  border-color: #c7ebf1;
-}
-
-.alert-info hr {
-  border-top-color: #b3e4ec;
-}
-
-.alert-info .alert-link {
-  color: #113b42;
-}
-
-.alert-warning {
-  color: #806520;
-  background-color: #fdf3d8;
-  border-color: #fceec9;
-}
-
-.alert-warning hr {
-  border-top-color: #fbe6b1;
-}
-
-.alert-warning .alert-link {
-  color: #574516;
-}
-
-.alert-danger {
-  color: #78261f;
-  background-color: #fadbd8;
-  border-color: #f8ccc8;
-}
-
-.alert-danger hr {
-  border-top-color: #f5b7b1;
-}
-
-.alert-danger .alert-link {
-  color: #4f1915;
-}
-
-.alert-light {
-  color: #818183;
-  background-color: #fefefe;
-  border-color: #fdfdfe;
-}
-
-.alert-light hr {
-  border-top-color: #ececf6;
-}
-
-.alert-light .alert-link {
-  color: #686869;
-}
-
-.alert-dark {
-  color: #2f3037;
-  background-color: #dedee1;
-  border-color: #d1d1d5;
-}
-
-.alert-dark hr {
-  border-top-color: #c4c4c9;
-}
-
-.alert-dark .alert-link {
-  color: #18181c;
-}
-
-@-webkit-keyframes progress-bar-stripes {
-  from {
-    background-position: 1rem 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-
-@keyframes progress-bar-stripes {
-  from {
-    background-position: 1rem 0;
-  }
-  to {
-    background-position: 0 0;
-  }
-}
-
-.progress {
-  display: flex;
-  height: 1rem;
-  overflow: hidden;
-  line-height: 0;
-  font-size: 0.75rem;
-  background-color: #eaecf4;
-  border-radius: 0.35rem;
-}
-
-
-
-.media {
-  display: flex;
-  align-items: flex-start;
-}
-
-.media-body {
-  flex: 1;
-}
-
-.list-group {
-  display: flex;
-  flex-direction: column;
-  padding-left: 0;
-  margin-bottom: 0;
-  border-radius: 0.35rem;
-}
-
-.list-group-item-action {
-  width: 100%;
-  color: #6e707e;
-  text-align: inherit;
-}
-
-.list-group-item-action:hover, .list-group-item-action:focus {
-  z-index: 1;
-  color: #6e707e;
-  text-decoration: none;
-  background-color: #f8f9fc;
-}
-
-.list-group-item-action:active {
-  color: #858796;
-  background-color: #eaecf4;
-}
-
-.list-group-item {
-  position: relative;
-  display: block;
-  padding: 0.75rem 1.25rem;
-  background-color: #fff;
-  border: 1px solid rgba(0, 0, 0, 0.125);
-}
-
-.list-group-item:first-child {
-  border-top-left-radius: inherit;
-  border-top-right-radius: inherit;
-}
-
-.list-group-item:last-child {
-  border-bottom-right-radius: inherit;
-  border-bottom-left-radius: inherit;
-}
-
-.list-group-item.disabled, .list-group-item:disabled {
-  color: #858796;
-  pointer-events: none;
-  background-color: #fff;
-}
-
-.list-group-item.active {
-  z-index: 2;
-  color: #fff;
-  background-color: #4e73df;
-  border-color: #4e73df;
-}
-
-.list-group-item + .list-group-item {
-  border-top-width: 0;
-}
-
-.list-group-item + .list-group-item.active {
-  margin-top: -1px;
-  border-top-width: 1px;
-}
-
-.list-group-horizontal {
-  flex-direction: row;
-}
-
-.list-group-horizontal > .list-group-item:first-child {
-  border-bottom-left-radius: 0.35rem;
-  border-top-right-radius: 0;
-}
-
-.list-group-horizontal > .list-group-item:last-child {
-  border-top-right-radius: 0.35rem;
-  border-bottom-left-radius: 0;
-}
-
-.list-group-horizontal > .list-group-item.active {
-  margin-top: 0;
-}
-
-.list-group-horizontal > .list-group-item + .list-group-item {
-  border-top-width: 1px;
-  border-left-width: 0;
-}
-
-.list-group-horizontal > .list-group-item + .list-group-item.active {
-  margin-left: -1px;
-  border-left-width: 1px;
-}
-
-@media (min-width: 576px) {
-  .list-group-horizontal-sm {
-    flex-direction: row;
-  }
-  .list-group-horizontal-sm > .list-group-item:first-child {
-    border-bottom-left-radius: 0.35rem;
-    border-top-right-radius: 0;
-  }
-  .list-group-horizontal-sm > .list-group-item:last-child {
-    border-top-right-radius: 0.35rem;
-    border-bottom-left-radius: 0;
-  }
-  .list-group-horizontal-sm > .list-group-item.active {
-    margin-top: 0;
-  }
-  .list-group-horizontal-sm > .list-group-item + .list-group-item {
-    border-top-width: 1px;
-    border-left-width: 0;
-  }
-  .list-group-horizontal-sm > .list-group-item + .list-group-item.active {
-    margin-left: -1px;
-    border-left-width: 1px;
-  }
-}
-
-@media (min-width: 768px) {
-  .list-group-horizontal-md {
-    flex-direction: row;
-  }
-  .list-group-horizontal-md > .list-group-item:first-child {
-    border-bottom-left-radius: 0.35rem;
-    border-top-right-radius: 0;
-  }
-  .list-group-horizontal-md > .list-group-item:last-child {
-    border-top-right-radius: 0.35rem;
-    border-bottom-left-radius: 0;
-  }
-  .list-group-horizontal-md > .list-group-item.active {
-    margin-top: 0;
-  }
-  .list-group-horizontal-md > .list-group-item + .list-group-item {
-    border-top-width: 1px;
-    border-left-width: 0;
-  }
-  .list-group-horizontal-md > .list-group-item + .list-group-item.active {
-    margin-left: -1px;
-    border-left-width: 1px;
-  }
-}
-
-@media (min-width: 992px) {
-  .list-group-horizontal-lg {
-    flex-direction: row;
-  }
-  .list-group-horizontal-lg > .list-group-item:first-child {
-    border-bottom-left-radius: 0.35rem;
-    border-top-right-radius: 0;
-  }
-  .list-group-horizontal-lg > .list-group-item:last-child {
-    border-top-right-radius: 0.35rem;
-    border-bottom-left-radius: 0;
-  }
-  .list-group-horizontal-lg > .list-group-item.active {
-    margin-top: 0;
-  }
-  .list-group-horizontal-lg > .list-group-item + .list-group-item {
-    border-top-width: 1px;
-    border-left-width: 0;
-  }
-  .list-group-horizontal-lg > .list-group-item + .list-group-item.active {
-    margin-left: -1px;
-    border-left-width: 1px;
-  }
-}
-
-@media (min-width: 1200px) {
-  .list-group-horizontal-xl {
-    flex-direction: row;
-  }
-  .list-group-horizontal-xl > .list-group-item:first-child {
-    border-bottom-left-radius: 0.35rem;
-    border-top-right-radius: 0;
-  }
-  .list-group-horizontal-xl > .list-group-item:last-child {
-    border-top-right-radius: 0.35rem;
-    border-bottom-left-radius: 0;
-  }
-  .list-group-horizontal-xl > .list-group-item.active {
-    margin-top: 0;
-  }
-  .list-group-horizontal-xl > .list-group-item + .list-group-item {
-    border-top-width: 1px;
-    border-left-width: 0;
-  }
-  .list-group-horizontal-xl > .list-group-item + .list-group-item.active {
-    margin-left: -1px;
-    border-left-width: 1px;
-  }
-}
-
-.list-group-flush {
-  border-radius: 0;
-}
-
-.list-group-flush > .list-group-item {
-  border-width: 0 0 1px;
-}
-
-.list-group-flush > .list-group-item:last-child {
-  border-bottom-width: 0;
-}
-
-.list-group-item-primary {
-  color: #293c74;
-  background-color: #cdd8f6;
-}
-
-.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {
-  color: #293c74;
-  background-color: #b7c7f2;
-}
-
-.list-group-item-primary.list-group-item-action.active {
-  color: #fff;
-  background-color: #293c74;
-  border-color: #293c74;
-}
-
-.list-group-item-secondary {
-  color: #45464e;
-  background-color: #dddde2;
-}
-
-.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {
-  color: #45464e;
-  background-color: #cfcfd6;
-}
-
-.list-group-item-secondary.list-group-item-action.active {
-  color: #fff;
-  background-color: #45464e;
-  border-color: #45464e;
-}
-
-.list-group-item-success {
-  color: #0f6848;
-  background-color: #bff0de;
-}
-
-.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {
-  color: #0f6848;
-  background-color: #aaebd3;
-}
-
-.list-group-item-success.list-group-item-action.active {
-  color: #fff;
-  background-color: #0f6848;
-  border-color: #0f6848;
-}
-
-.list-group-item-info {
-  color: #1c606a;
-  background-color: #c7ebf1;
-}
-
-.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {
-  color: #1c606a;
-  background-color: #b3e4ec;
-}
-
-.list-group-item-info.list-group-item-action.active {
-  color: #fff;
-  background-color: #1c606a;
-  border-color: #1c606a;
-}
-
-.list-group-item-warning {
-  color: #806520;
-  background-color: #fceec9;
-}
-
-.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {
-  color: #806520;
-  background-color: #fbe6b1;
-}
-
-.list-group-item-warning.list-group-item-action.active {
-  color: #fff;
-  background-color: #806520;
-  border-color: #806520;
-}
-
-.list-group-item-danger {
-  color: #78261f;
-  background-color: #f8ccc8;
-}
-
-.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {
-  color: #78261f;
-  background-color: #f5b7b1;
-}
-
-.list-group-item-danger.list-group-item-action.active {
-  color: #fff;
-  background-color: #78261f;
-  border-color: #78261f;
-}
-
-.list-group-item-light {
-  color: #818183;
-  background-color: #fdfdfe;
-}
-
-.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {
-  color: #818183;
-  background-color: #ececf6;
-}
-
-.list-group-item-light.list-group-item-action.active {
-  color: #fff;
-  background-color: #818183;
-  border-color: #818183;
-}
-
-.list-group-item-dark {
-  color: #2f3037;
-  background-color: #d1d1d5;
-}
-
-.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {
-  color: #2f3037;
-  background-color: #c4c4c9;
-}
-
-.list-group-item-dark.list-group-item-action.active {
-  color: #fff;
-  background-color: #2f3037;
-  border-color: #2f3037;
-}
-
-.close {
-  float: right;
-  font-size: 1.5rem;
-  font-weight: 700;
-  line-height: 1;
-  color: #000;
-  text-shadow: 0 1px 0 #fff;
-  opacity: .5;
-}
-
-.close:hover {
-  color: #000;
-  text-decoration: none;
-}
-
-.close:not(:disabled):not(.disabled):hover, .close:not(:disabled):not(.disabled):focus {
-  opacity: .75;
-}
-
-button.close {
-  padding: 0;
-  background-color: transparent;
-  border: 0;
-}
-
-a.close.disabled {
-  pointer-events: none;
-}
-
-.toast {
-  flex-basis: 350px;
-  max-width: 350px;
-  font-size: 0.875rem;
-  background-color: rgba(255, 255, 255, 0.85);
-  background-clip: padding-box;
-  border: 1px solid rgba(0, 0, 0, 0.1);
-  box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
-  opacity: 0;
-  border-radius: 0.25rem;
-}
-
-.toast:not(:last-child) {
-  margin-bottom: 0.75rem;
-}
-
-.toast.showing {
-  opacity: 1;
-}
-
-.toast.show {
-  display: block;
-  opacity: 1;
-}
-
-.toast.hide {
-  display: none;
-}
-
-.toast-header {
-  display: flex;
-  align-items: center;
-  padding: 0.25rem 0.75rem;
-  color: #858796;
-  background-color: rgba(255, 255, 255, 0.85);
-  background-clip: padding-box;
-  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
-  border-top-left-radius: calc(0.25rem - 1px);
-  border-top-right-radius: calc(0.25rem - 1px);
-}
-
-.toast-body {
-  padding: 0.75rem;
-}
-
-.modal-open {
-  overflow: hidden;
-}
-
-.modal-open .modal {
-  overflow-x: hidden;
-  overflow-y: auto;
-}
-
-.modal {
-  position: fixed;
-  top: 0;
-  left: 0;
-  z-index: 1050;
-  display: none;
-  width: 100%;
-  height: 100%;
-  overflow: hidden;
-  outline: 0;
-}
-
-.modal-dialog {
-  position: relative;
-  width: auto;
-  margin: 0.5rem;
-  pointer-events: none;
-}
-
-.modal.fade .modal-dialog {
-  transition: transform 0.3s ease-out;
-  transform: translate(0, -50px);
-}
-
-@media (prefers-reduced-motion: reduce) {
-  .modal.fade .modal-dialog {
-    transition: none;
-  }
-}
-
-.modal.show .modal-dialog {
-  transform: none;
-}
-
-.modal.modal-static .modal-dialog {
-  transform: scale(1.02);
-}
-
-.modal-dialog-scrollable {
-  display: flex;
-  max-height: calc(100% - 1rem);
-}
-
-.modal-dialog-scrollable .modal-content {
-  max-height: calc(100vh - 1rem);
-  overflow: hidden;
-}
-
-.modal-dialog-scrollable .modal-header,
-.modal-dialog-scrollable .modal-footer {
-  flex-shrink: 0;
-}
-
-.modal-dialog-scrollable .modal-body {
-  overflow-y: auto;
-}
-
-.modal-dialog-centered {
-  display: flex;
-  align-items: center;
-  min-height: calc(100% - 1rem);
-}
-
-.modal-dialog-centered::before {
-  display: block;
-  height: calc(100vh - 1rem);
-  height: -webkit-min-content;
-  height: -moz-min-content;
-  height: min-content;
-  content: "";
-}
-
-.modal-dialog-centered.modal-dialog-scrollable {
-  flex-direction: column;
-  justify-content: center;
-  height: 100%;
-}
-
-.modal-dialog-centered.modal-dialog-scrollable .modal-content {
-  max-height: none;
-}
-
-.modal-dialog-centered.modal-dialog-scrollable::before {
-  content: none;
-}
-
-.modal-content {
-  position: relative;
-  display: flex;
-  flex-direction: column;
-  width: 100%;
-  pointer-events: auto;
-  background-color: #fff;
-  background-clip: padding-box;
-  border: 1px solid rgba(0, 0, 0, 0.2);
-  border-radius: 0.3rem;
-  outline: 0;
-}
-
-.modal-backdrop {
-  position: fixed;
-  top: 0;
-  left: 0;
-  z-index: 1040;
-  width: 100vw;
-  height: 100vh;
-  background-color: #000;
-}
-
-.modal-backdrop.fade {
-  opacity: 0;
-}
-
-.modal-backdrop.show {
-  opacity: 0.5;
-}
-
-.modal-header {
-  display: flex;
-  align-items: flex-start;
-  justify-content: space-between;
-  padding: 1rem 1rem;
-  border-bottom: 1px solid #e3e6f0;
-  border-top-left-radius: calc(0.3rem - 1px);
-  border-top-right-radius: calc(0.3rem - 1px);
-}
-
-.modal-header .close {
-  padding: 1rem 1rem;
-  margin: -1rem -1rem -1rem auto;
-}
-
-.modal-title {
-  margin-bottom: 0;
-  line-height: 1.5;
-}
-
-.modal-body {
-  position: relative;
-  flex: 1 1 auto;
-  padding: 1rem;
-}
-
-.modal-footer {
-  display: flex;
-  flex-wrap: wrap;
-  align-items: center;
-  justify-content: flex-end;
-  padding: 0.75rem;
-  border-top: 1px solid #e3e6f0;
-  border-bottom-right-radius: calc(0.3rem - 1px);
-  border-bottom-left-radius: calc(0.3rem - 1px);
-}
-
-.modal-footer > * {
-  margin: 0.25rem;
-}
-
-.modal-scrollbar-measure {
-  position: absolute;
-  top: -9999px;
-  width: 50px;
-  height: 50px;
-  overflow: scroll;
-}
-
-@media (min-width: 576px) {
-  .modal-dialog {
-    max-width: 500px;
-    margin: 1.75rem auto;
-  }
-  .modal-dialog-scrollable {
-    max-height: calc(100% - 3.5rem);
-  }
-  .modal-dialog-scrollable .modal-content {
-    max-height: calc(100vh - 3.5rem);
-  }
-  .modal-dialog-centered {
-    min-height: calc(100% - 3.5rem);
-  }
-  .modal-dialog-centered::before {
-    height: calc(100vh - 3.5rem);
-    height: -webkit-min-content;
-    height: -moz-min-content;
-    height: min-content;
-  }
-  .modal-sm {
-    max-width: 300px;
-  }
-}
-
-@media (min-width: 992px) {
-  .modal-lg,
-  .modal-xl {
-    max-width: 800px;
-  }
-}
-
-@media (min-width: 1200px) {
-  .modal-xl {
-    max-width: 1140px;
-  }
-}
-
-
-.align-baseline {
-  vertical-align: baseline !important;
-}
-
-.align-top {
-  vertical-align: top !important;
-}
-
-.align-middle {
-  vertical-align: middle !important;
-}
-
-.align-bottom {
-  vertical-align: bottom !important;
-}
-
-.align-text-bottom {
-  vertical-align: text-bottom !important;
-}
-
-.align-text-top {
-  vertical-align: text-top !important;
-}
-
-.bg-primary {
-  background-color: #4e73df !important;
-}
-
-a.bg-primary:hover, a.bg-primary:focus,
-button.bg-primary:hover,
-button.bg-primary:focus {
-  background-color: #2653d4 !important;
-}
-
-.bg-secondary {
-  background-color: #858796 !important;
-}
-
-a.bg-secondary:hover, a.bg-secondary:focus,
-button.bg-secondary:hover,
-button.bg-secondary:focus {
-  background-color: #6b6d7d !important;
-}
-
-.bg-success {
-  background-color: #1cc88a !important;
-}
-
-a.bg-success:hover, a.bg-success:focus,
-button.bg-success:hover,
-button.bg-success:focus {
-  background-color: #169b6b !important;
-}
-
-.bg-info {
-  background-color: #36b9cc !important;
-}
-
-a.bg-info:hover, a.bg-info:focus,
-button.bg-info:hover,
-button.bg-info:focus {
-  background-color: #2a96a5 !important;
-}
-
-.bg-warning {
-  background-color: #f6c23e !important;
-}
-
-a.bg-warning:hover, a.bg-warning:focus,
-button.bg-warning:hover,
-button.bg-warning:focus {
-  background-color: #f4b30d !important;
-}
-
-.bg-danger {
-  background-color: #e74a3b !important;
-}
-
-a.bg-danger:hover, a.bg-danger:focus,
-button.bg-danger:hover,
-button.bg-danger:focus {
-  background-color: #d52a1a !important;
-}
-
-.bg-light {
-  background-color: #f8f9fc !important;
-}
-
-a.bg-light:hover, a.bg-light:focus,
-button.bg-light:hover,
-button.bg-light:focus {
-  background-color: #d4daed !important;
-}
-
-.bg-dark {
-  background-color: #5a5c69 !important;
-}
-
-a.bg-dark:hover, a.bg-dark:focus,
-button.bg-dark:hover,
-button.bg-dark:focus {
-  background-color: #42444e !important;
-}
-
-.bg-white {
-  background-color: #fff !important;
-}
-
-.bg-transparent {
-  background-color: transparent !important;
-}
-
-.border {
-  border: 1px solid #e3e6f0 !important;
-}
-
-.border-top {
-  border-top: 1px solid #e3e6f0 !important;
-}
-
-.border-right {
-  border-right: 1px solid #e3e6f0 !important;
-}
-
-.border-bottom {
-  border-bottom: 1px solid #e3e6f0 !important;
-}
-
-.border-left {
-  border-left: 1px solid #e3e6f0 !important;
-}
-
-.border-0 {
-  border: 0 !important;
-}
-
-.border-top-0 {
-  border-top: 0 !important;
-}
-
-.border-right-0 {
-  border-right: 0 !important;
-}
-
-.border-bottom-0 {
-  border-bottom: 0 !important;
-}
-
-.border-left-0 {
-  border-left: 0 !important;
-}
-
-.border-primary {
-  border-color: #4e73df !important;
-}
-
-.border-secondary {
-  border-color: #858796 !important;
-}
-
-.border-success {
-  border-color: #1cc88a !important;
-}
-
-.border-info {
-  border-color: #36b9cc !important;
-}
-
-.border-warning {
-  border-color: #f6c23e !important;
-}
-
-.border-danger {
-  border-color: #e74a3b !important;
-}
-
-.border-light {
-  border-color: #f8f9fc !important;
-}
-
-.border-dark {
-  border-color: #5a5c69 !important;
-}
-
-.border-white {
-  border-color: #fff !important;
-}
-
-.rounded-sm {
-  border-radius: 0.2rem !important;
-}
-
-.rounded {
-  border-radius: 0.35rem !important;
-}
-
-.rounded-top {
-  border-top-left-radius: 0.35rem !important;
-  border-top-right-radius: 0.35rem !important;
-}
-
-.rounded-right {
-  border-top-right-radius: 0.35rem !important;
-  border-bottom-right-radius: 0.35rem !important;
-}
-
-.rounded-bottom {
-  border-bottom-right-radius: 0.35rem !important;
-  border-bottom-left-radius: 0.35rem !important;
-}
-
-.rounded-left {
-  border-top-left-radius: 0.35rem !important;
-  border-bottom-left-radius: 0.35rem !important;
-}
-
-.rounded-lg {
-  border-radius: 0.3rem !important;
-}
-
-.rounded-circle {
-  border-radius: 50% !important;
-}
-
-.rounded-pill {
-  border-radius: 50rem !important;
-}
-
-.rounded-0 {
-  border-radius: 0 !important;
-}
-
-
-
-.d-none {
-  display: none !important;
-}
-
-.d-inline {
-  display: inline !important;
-}
-
-.d-inline-block {
-  display: inline-block !important;
-}
-
-.d-block {
-  display: block !important;
-}
-
-.d-table {
-  display: table !important;
-}
-
-.d-table-row {
-  display: table-row !important;
-}
-
-.d-table-cell {
-  display: table-cell !important;
-}
-
-.d-flex {
-  display: flex !important;
-}
-
-.d-inline-flex {
-  display: inline-flex !important;
-}
-
-@media (min-width: 576px) {
-  .d-sm-none {
-    display: none !important;
-  }
-  .d-sm-inline {
-    display: inline !important;
-  }
-  .d-sm-inline-block {
-    display: inline-block !important;
-  }
-  .d-sm-block {
-    display: block !important;
-  }
-  .d-sm-table {
-    display: table !important;
-  }
-  .d-sm-table-row {
-    display: table-row !important;
-  }
-  .d-sm-table-cell {
-    display: table-cell !important;
-  }
-  .d-sm-flex {
-    display: flex !important;
-  }
-  .d-sm-inline-flex {
-    display: inline-flex !important;
-  }
-}
-
-@media (min-width: 768px) {
-  .d-md-none {
-    display: none !important;
-  }
-  .d-md-inline {
-    display: inline !important;
-  }
-  .d-md-inline-block {
-    display: inline-block !important;
-  }
-  .d-md-block {
-    display: block !important;
-  }
-  .d-md-table {
-    display: table !important;
-  }
-  .d-md-table-row {
-    display: table-row !important;
-  }
-  .d-md-table-cell {
-    display: table-cell !important;
-  }
-  .d-md-flex {
-    display: flex !important;
-  }
-  .d-md-inline-flex {
-    display: inline-flex !important;
-  }
-}
-
-@media (min-width: 992px) {
-  .d-lg-none {
-    display: none !important;
-  }
-  .d-lg-inline {
-    display: inline !important;
-  }
-  .d-lg-inline-block {
-    display: inline-block !important;
-  }
-  .d-lg-block {
-    display: block !important;
-  }
-  .d-lg-table {
-    display: table !important;
-  }
-  .d-lg-table-row {
-    display: table-row !important;
-  }
-  .d-lg-table-cell {
-    display: table-cell !important;
-  }
-  .d-lg-flex {
-    display: flex !important;
-  }
-  .d-lg-inline-flex {
-    display: inline-flex !important;
-  }
-}
-
-@media (min-width: 1200px) {
-  .d-xl-none {
-    display: none !important;
-  }
-  .d-xl-inline {
-    display: inline !important;
-  }
-  .d-xl-inline-block {
-    display: inline-block !important;
-  }
-  .d-xl-block {
-    display: block !important;
-  }
-  .d-xl-table {
-    display: table !important;
-  }
-  .d-xl-table-row {
-    display: table-row !important;
-  }
-  .d-xl-table-cell {
-    display: table-cell !important;
-  }
-  .d-xl-flex {
-    display: flex !important;
-  }
-  .d-xl-inline-flex {
-    display: inline-flex !important;
-  }
-}
-
-@media print {
-  .d-print-none {
-    display: none !important;
-  }
-  .d-print-inline {
-    display: inline !important;
-  }
-  .d-print-inline-block {
-    display: inline-block !important;
-  }
-  .d-print-block {
-    display: block !important;
-  }
-  .d-print-table {
-    display: table !important;
-  }
-  .d-print-table-row {
-    display: table-row !important;
-  }
-  .d-print-table-cell {
-    display: table-cell !important;
-  }
-  .d-print-flex {
-    display: flex !important;
-  }
-  .d-print-inline-flex {
-    display: inline-flex !important;
-  }
-}
-
-
-
-
-
-.flex-row {
-  flex-direction: row !important;
-}
-
-.flex-column {
-  flex-direction: column !important;
-}
-
-.flex-row-reverse {
-  flex-direction: row-reverse !important;
-}
-
-.flex-column-reverse {
-  flex-direction: column-reverse !important;
-}
-
-.flex-wrap {
-  flex-wrap: wrap !important;
-}
-
-.flex-nowrap {
-  flex-wrap: nowrap !important;
-}
-
-.flex-wrap-reverse {
-  flex-wrap: wrap-reverse !important;
-}
-
-.flex-fill {
-  flex: 1 1 auto !important;
-}
-
-.flex-grow-0 {
-  flex-grow: 0 !important;
-}
-
-.flex-grow-1 {
-  flex-grow: 1 !important;
-}
-
-.flex-shrink-0 {
-  flex-shrink: 0 !important;
-}
-
-.flex-shrink-1 {
-  flex-shrink: 1 !important;
-}
-
-.justify-content-start {
-  justify-content: flex-start !important;
-}
-
-.justify-content-end {
-  justify-content: flex-end !important;
-}
-
-.justify-content-center {
-  justify-content: center !important;
-}
-
-.justify-content-between {
-  justify-content: space-between !important;
-}
-
-.justify-content-around {
-  justify-content: space-around !important;
-}
-
-.align-items-start {
-  align-items: flex-start !important;
-}
-
-.align-items-end {
-  align-items: flex-end !important;
-}
-
-.align-items-center {
-  align-items: center !important;
-}
-
-.align-items-baseline {
-  align-items: baseline !important;
-}
-
-.align-items-stretch {
-  align-items: stretch !important;
-}
-
-.align-content-start {
-  align-content: flex-start !important;
-}
-
-.align-content-end {
-  align-content: flex-end !important;
-}
-
-.align-content-center {
-  align-content: center !important;
-}
-
-.align-content-between {
-  align-content: space-between !important;
-}
-
-.align-content-around {
-  align-content: space-around !important;
-}
-
-.align-content-stretch {
-  align-content: stretch !important;
-}
-
-.align-self-auto {
-  align-self: auto !important;
-}
-
-.align-self-start {
-  align-self: flex-start !important;
-}
-
-.align-self-end {
-  align-self: flex-end !important;
-}
-
-.align-self-center {
-  align-self: center !important;
-}
-
-.align-self-baseline {
-  align-self: baseline !important;
-}
-
-.align-self-stretch {
-  align-self: stretch !important;
-}
-
-@media (min-width: 576px) {
-  .flex-sm-row {
-    flex-direction: row !important;
-  }
-  .flex-sm-column {
-    flex-direction: column !important;
-  }
-  .flex-sm-row-reverse {
-    flex-direction: row-reverse !important;
-  }
-  .flex-sm-column-reverse {
-    flex-direction: column-reverse !important;
-  }
-  .flex-sm-wrap {
-    flex-wrap: wrap !important;
-  }
-  .flex-sm-nowrap {
-    flex-wrap: nowrap !important;
-  }
-  .flex-sm-wrap-reverse {
-    flex-wrap: wrap-reverse !important;
-  }
-  .flex-sm-fill {
-    flex: 1 1 auto !important;
-  }
-  .flex-sm-grow-0 {
-    flex-grow: 0 !important;
-  }
-  .flex-sm-grow-1 {
-    flex-grow: 1 !important;
-  }
-  .flex-sm-shrink-0 {
-    flex-shrink: 0 !important;
-  }
-  .flex-sm-shrink-1 {
-    flex-shrink: 1 !important;
-  }
-  .justify-content-sm-start {
-    justify-content: flex-start !important;
-  }
-  .justify-content-sm-end {
-    justify-content: flex-end !important;
-  }
-  .justify-content-sm-center {
-    justify-content: center !important;
-  }
-  .justify-content-sm-between {
-    justify-content: space-between !important;
-  }
-  .justify-content-sm-around {
-    justify-content: space-around !important;
-  }
-  .align-items-sm-start {
-    align-items: flex-start !important;
-  }
-  .align-items-sm-end {
-    align-items: flex-end !important;
-  }
-  .align-items-sm-center {
-    align-items: center !important;
-  }
-  .align-items-sm-baseline {
-    align-items: baseline !important;
-  }
-  .align-items-sm-stretch {
-    align-items: stretch !important;
-  }
-  .align-content-sm-start {
-    align-content: flex-start !important;
-  }
-  .align-content-sm-end {
-    align-content: flex-end !important;
-  }
-  .align-content-sm-center {
-    align-content: center !important;
-  }
-  .align-content-sm-between {
-    align-content: space-between !important;
-  }
-  .align-content-sm-around {
-    align-content: space-around !important;
-  }
-  .align-content-sm-stretch {
-    align-content: stretch !important;
-  }
-  .align-self-sm-auto {
-    align-self: auto !important;
-  }
-  .align-self-sm-start {
-    align-self: flex-start !important;
-  }
-  .align-self-sm-end {
-    align-self: flex-end !important;
-  }
-  .align-self-sm-center {
-    align-self: center !important;
-  }
-  .align-self-sm-baseline {
-    align-self: baseline !important;
-  }
-  .align-self-sm-stretch {
-    align-self: stretch !important;
-  }
-}
-
-@media (min-width: 768px) {
-  .flex-md-row {
-    flex-direction: row !important;
-  }
-  .flex-md-column {
-    flex-direction: column !important;
-  }
-  .flex-md-row-reverse {
-    flex-direction: row-reverse !important;
-  }
-  .flex-md-column-reverse {
-    flex-direction: column-reverse !important;
-  }
-  .flex-md-wrap {
-    flex-wrap: wrap !important;
-  }
-  .flex-md-nowrap {
-    flex-wrap: nowrap !important;
-  }
-  .flex-md-wrap-reverse {
-    flex-wrap: wrap-reverse !important;
-  }
-  .flex-md-fill {
-    flex: 1 1 auto !important;
-  }
-  .flex-md-grow-0 {
-    flex-grow: 0 !important;
-  }
-  .flex-md-grow-1 {
-    flex-grow: 1 !important;
-  }
-  .flex-md-shrink-0 {
-    flex-shrink: 0 !important;
-  }
-  .flex-md-shrink-1 {
-    flex-shrink: 1 !important;
-  }
-  .justify-content-md-start {
-    justify-content: flex-start !important;
-  }
-  .justify-content-md-end {
-    justify-content: flex-end !important;
-  }
-  .justify-content-md-center {
-    justify-content: center !important;
-  }
-  .justify-content-md-between {
-    justify-content: space-between !important;
-  }
-  .justify-content-md-around {
-    justify-content: space-around !important;
-  }
-  .align-items-md-start {
-    align-items: flex-start !important;
-  }
-  .align-items-md-end {
-    align-items: flex-end !important;
-  }
-  .align-items-md-center {
-    align-items: center !important;
-  }
-  .align-items-md-baseline {
-    align-items: baseline !important;
-  }
-  .align-items-md-stretch {
-    align-items: stretch !important;
-  }
-  .align-content-md-start {
-    align-content: flex-start !important;
-  }
-  .align-content-md-end {
-    align-content: flex-end !important;
-  }
-  .align-content-md-center {
-    align-content: center !important;
-  }
-  .align-content-md-between {
-    align-content: space-between !important;
-  }
-  .align-content-md-around {
-    align-content: space-around !important;
-  }
-  .align-content-md-stretch {
-    align-content: stretch !important;
-  }
-  .align-self-md-auto {
-    align-self: auto !important;
-  }
-  .align-self-md-start {
-    align-self: flex-start !important;
-  }
-  .align-self-md-end {
-    align-self: flex-end !important;
-  }
-  .align-self-md-center {
-    align-self: center !important;
-  }
-  .align-self-md-baseline {
-    align-self: baseline !important;
-  }
-  .align-self-md-stretch {
-    align-self: stretch !important;
-  }
-}
-
-@media (min-width: 992px) {
-  .flex-lg-row {
-    flex-direction: row !important;
-  }
-  .flex-lg-column {
-    flex-direction: column !important;
-  }
-  .flex-lg-row-reverse {
-    flex-direction: row-reverse !important;
-  }
-  .flex-lg-column-reverse {
-    flex-direction: column-reverse !important;
-  }
-  .flex-lg-wrap {
-    flex-wrap: wrap !important;
-  }
-  .flex-lg-nowrap {
-    flex-wrap: nowrap !important;
-  }
-  .flex-lg-wrap-reverse {
-    flex-wrap: wrap-reverse !important;
-  }
-  .flex-lg-fill {
-    flex: 1 1 auto !important;
-  }
-  .flex-lg-grow-0 {
-    flex-grow: 0 !important;
-  }
-  .flex-lg-grow-1 {
-    flex-grow: 1 !important;
-  }
-  .flex-lg-shrink-0 {
-    flex-shrink: 0 !important;
-  }
-  .flex-lg-shrink-1 {
-    flex-shrink: 1 !important;
-  }
-  .justify-content-lg-start {
-    justify-content: flex-start !important;
-  }
-  .justify-content-lg-end {
-    justify-content: flex-end !important;
-  }
-  .justify-content-lg-center {
-    justify-content: center !important;
-  }
-  .justify-content-lg-between {
-    justify-content: space-between !important;
-  }
-  .justify-content-lg-around {
-    justify-content: space-around !important;
-  }
-  .align-items-lg-start {
-    align-items: flex-start !important;
-  }
-  .align-items-lg-end {
-    align-items: flex-end !important;
-  }
-  .align-items-lg-center {
-    align-items: center !important;
-  }
-  .align-items-lg-baseline {
-    align-items: baseline !important;
-  }
-  .align-items-lg-stretch {
-    align-items: stretch !important;
-  }
-  .align-content-lg-start {
-    align-content: flex-start !important;
-  }
-  .align-content-lg-end {
-    align-content: flex-end !important;
-  }
-  .align-content-lg-center {
-    align-content: center !important;
-  }
-  .align-content-lg-between {
-    align-content: space-between !important;
-  }
-  .align-content-lg-around {
-    align-content: space-around !important;
-  }
-  .align-content-lg-stretch {
-    align-content: stretch !important;
-  }
-  .align-self-lg-auto {
-    align-self: auto !important;
-  }
-  .align-self-lg-start {
-    align-self: flex-start !important;
-  }
-  .align-self-lg-end {
-    align-self: flex-end !important;
-  }
-  .align-self-lg-center {
-    align-self: center !important;
-  }
-  .align-self-lg-baseline {
-    align-self: baseline !important;
-  }
-  .align-self-lg-stretch {
-    align-self: stretch !important;
-  }
-}
-
-@media (min-width: 1200px) {
-  .flex-xl-row {
-    flex-direction: row !important;
-  }
-  .flex-xl-column {
-    flex-direction: column !important;
-  }
-  .flex-xl-row-reverse {
-    flex-direction: row-reverse !important;
-  }
-  .flex-xl-column-reverse {
-    flex-direction: column-reverse !important;
-  }
-  .flex-xl-wrap {
-    flex-wrap: wrap !important;
-  }
-  .flex-xl-nowrap {
-    flex-wrap: nowrap !important;
-  }
-  .flex-xl-wrap-reverse {
-    flex-wrap: wrap-reverse !important;
-  }
-  .flex-xl-fill {
-    flex: 1 1 auto !important;
-  }
-  .flex-xl-grow-0 {
-    flex-grow: 0 !important;
-  }
-  .flex-xl-grow-1 {
-    flex-grow: 1 !important;
-  }
-  .flex-xl-shrink-0 {
-    flex-shrink: 0 !important;
-  }
-  .flex-xl-shrink-1 {
-    flex-shrink: 1 !important;
-  }
-  .justify-content-xl-start {
-    justify-content: flex-start !important;
-  }
-  .justify-content-xl-end {
-    justify-content: flex-end !important;
-  }
-  .justify-content-xl-center {
-    justify-content: center !important;
-  }
-  .justify-content-xl-between {
-    justify-content: space-between !important;
-  }
-  .justify-content-xl-around {
-    justify-content: space-around !important;
-  }
-  .align-items-xl-start {
-    align-items: flex-start !important;
-  }
-  .align-items-xl-end {
-    align-items: flex-end !important;
-  }
-  .align-items-xl-center {
-    align-items: center !important;
-  }
-  .align-items-xl-baseline {
-    align-items: baseline !important;
-  }
-  .align-items-xl-stretch {
-    align-items: stretch !important;
-  }
-  .align-content-xl-start {
-    align-content: flex-start !important;
-  }
-  .align-content-xl-end {
-    align-content: flex-end !important;
-  }
-  .align-content-xl-center {
-    align-content: center !important;
-  }
-  .align-content-xl-between {
-    align-content: space-between !important;
-  }
-  .align-content-xl-around {
-    align-content: space-around !important;
-  }
-  .align-content-xl-stretch {
-    align-content: stretch !important;
-  }
-  .align-self-xl-auto {
-    align-self: auto !important;
-  }
-  .align-self-xl-start {
-    align-self: flex-start !important;
-  }
-  .align-self-xl-end {
-    align-self: flex-end !important;
-  }
-  .align-self-xl-center {
-    align-self: center !important;
-  }
-  .align-self-xl-baseline {
-    align-self: baseline !important;
-  }
-  .align-self-xl-stretch {
-    align-self: stretch !important;
-  }
-}
-
-.float-left {
-  float: left !important;
-}
-
-.float-right {
-  float: right !important;
-}
-
-.float-none {
-  float: none !important;
-}
-
-@media (min-width: 576px) {
-  .float-sm-left {
-    float: left !important;
-  }
-  .float-sm-right {
-    float: right !important;
-  }
-  .float-sm-none {
-    float: none !important;
-  }
-}
-
-@media (min-width: 768px) {
-  .float-md-left {
-    float: left !important;
-  }
-  .float-md-right {
-    float: right !important;
-  }
-  .float-md-none {
-    float: none !important;
-  }
-}
-
-@media (min-width: 992px) {
-  .float-lg-left {
-    float: left !important;
-  }
-  .float-lg-right {
-    float: right !important;
-  }
-  .float-lg-none {
-    float: none !important;
-  }
-}
-
-@media (min-width: 1200px) {
-  .float-xl-left {
-    float: left !important;
-  }
-  .float-xl-right {
-    float: right !important;
-  }
-  .float-xl-none {
-    float: none !important;
-  }
-}
-
-
-
-
-.position-static {
-  position: static !important;
-}
-
-.position-relative {
-  position: relative !important;
-}
-
-.position-absolute {
-  position: absolute !important;
-}
-
-.position-fixed {
-  position: fixed !important;
-}
-
-.position-sticky {
-  position: -webkit-sticky !important;
-  position: sticky !important;
-}
-
-.fixed-top {
-  position: fixed;
-  top: 0;
-  right: 0;
-  left: 0;
-  z-index: 1030;
-}
-
-.fixed-bottom {
-  position: fixed;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 1030;
-}
-
-@supports ((position: -webkit-sticky) or (position: sticky)) {
-  .sticky-top {
-    position: -webkit-sticky;
-    position: sticky;
-    top: 0;
-    z-index: 1020;
-  }
-}
-
-
-
-.shadow-sm {
-  box-shadow: 0 0.125rem 0.25rem 0 rgba(58, 59, 69, 0.2) !important;
-}
-
-.shadow {
-  box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15) !important;
-}
-
-.shadow-lg {
-  box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important;
-}
-
-.shadow-none {
-  box-shadow: none !important;
-}
-
-.w-25 {
-  width: 25% !important;
-}
-
-.w-50 {
-  width: 50% !important;
-}
-
-.w-75 {
-  width: 75% !important;
-}
-
-.w-100 {
-  width: 100% !important;
-}
-
-.w-auto {
-  width: auto !important;
-}
-
-.h-25 {
-  height: 25% !important;
-}
-
-.h-50 {
-  height: 50% !important;
-}
-
-.h-75 {
-  height: 75% !important;
-}
-
-.h-100 {
-  height: 100% !important;
-}
-
-.h-auto {
-  height: auto !important;
-}
-
-.mw-100 {
-  max-width: 100% !important;
-}
-
-.mh-100 {
-  max-height: 100% !important;
-}
-
-.min-vw-100 {
-  min-width: 100vw !important;
-}
-
-.min-vh-100 {
-  min-height: 100vh !important;
-}
-
-.vw-100 {
-  width: 100vw !important;
-}
-
-.vh-100 {
-  height: 100vh !important;
-}
-
-.m-0 {
-  margin: 0 !important;
-}
-
-.mt-0,
-.my-0 {
-  margin-top: 0 !important;
-}
-
-.mr-0,
-.mx-0 {
-  margin-right: 0 !important;
-}
-
-.mb-0,
-.my-0 {
-  margin-bottom: 0 !important;
-}
-
-.ml-0,
-.mx-0 {
-  margin-left: 0 !important;
-}
-
-.m-1 {
-  margin: 0.25rem !important;
-}
-
-.mt-1,
-.my-1 {
-  margin-top: 0.25rem !important;
-}
-
-.mr-1,
-.mx-1 {
-  margin-right: 0.25rem !important;
-}
-
-.mb-1,
-.my-1 {
-  margin-bottom: 0.25rem !important;
-}
-
-.ml-1,
-.mx-1 {
-  margin-left: 0.25rem !important;
-}
-
-.m-2 {
-  margin: 0.5rem !important;
-}
-
-.mt-2,
-.my-2 {
-  margin-top: 0.5rem !important;
-}
-
-.mr-2,
-.mx-2 {
-  margin-right: 0.5rem !important;
-}
-
-.mb-2,
-.my-2 {
-  margin-bottom: 0.5rem !important;
-}
-
-.ml-2,
-.mx-2 {
-  margin-left: 0.5rem !important;
-}
-
-.m-3 {
-  margin: 1rem !important;
-}
-
-.mt-3,
-.my-3 {
-  margin-top: 1rem !important;
-}
-
-.mr-3,
-.mx-3 {
-  margin-right: 1rem !important;
-}
-
-.mb-3,
-.my-3 {
-  margin-bottom: 1rem !important;
-}
-
-.ml-3,
-.mx-3 {
-  margin-left: 1rem !important;
-}
-
-.m-4 {
-  margin: 1.5rem !important;
-}
-
-.mt-4,
-.my-4 {
-  margin-top: 1.5rem !important;
-}
-
-.mr-4,
-.mx-4 {
-  margin-right: 1.5rem !important;
-}
-
-.mb-4,
-.my-4 {
-  margin-bottom: 1.5rem !important;
-}
-
-.ml-4,
-.mx-4 {
-  margin-left: 1.5rem !important;
-}
-
-.m-5 {
-  margin: 3rem !important;
-}
-
-.mt-5,
-.my-5 {
-  margin-top: 3rem !important;
-}
-
-.mr-5,
-.mx-5 {
-  margin-right: 3rem !important;
-}
-
-.mb-5,
-.my-5 {
-  margin-bottom: 3rem !important;
-}
-
-.ml-5,
-.mx-5 {
-  margin-left: 3rem !important;
-}
-
-.p-0 {
-  padding: 0 !important;
-}
-
-.pt-0,
-.py-0 {
-  padding-top: 0 !important;
-}
-
-.pr-0,
-.px-0 {
-  padding-right: 0 !important;
-}
-
-.pb-0,
-.py-0 {
-  padding-bottom: 0 !important;
-}
-
-.pl-0,
-.px-0 {
-  padding-left: 0 !important;
-}
-
-.p-1 {
-  padding: 0.25rem !important;
-}
-
-.pt-1,
-.py-1 {
-  padding-top: 0.25rem !important;
-}
-
-.pr-1,
-.px-1 {
-  padding-right: 0.25rem !important;
-}
-
-.pb-1,
-.py-1 {
-  padding-bottom: 0.25rem !important;
-}
-
-.pl-1,
-.px-1 {
-  padding-left: 0.25rem !important;
-}
-
-.p-2 {
-  padding: 0.5rem !important;
-}
-
-.pt-2,
-.py-2 {
-  padding-top: 0.5rem !important;
-}
-
-.pr-2,
-.px-2 {
-  padding-right: 0.5rem !important;
-}
-
-.pb-2,
-.py-2 {
-  padding-bottom: 0.5rem !important;
-}
-
-.pl-2,
-.px-2 {
-  padding-left: 0.5rem !important;
-}
-
-.p-3 {
-  padding: 1rem !important;
-}
-
-.pt-3,
-.py-3 {
-  padding-top: 1rem !important;
-}
-
-.pr-3,
-.px-3 {
-  padding-right: 1rem !important;
-}
-
-.pb-3,
-.py-3 {
-  padding-bottom: 1rem !important;
-}
-
-.pl-3,
-.px-3 {
-  padding-left: 1rem !important;
-}
-
-.p-4 {
-  padding: 1.5rem !important;
-}
-
-.pt-4,
-.py-4 {
-  padding-top: 1.5rem !important;
-}
-
-.pr-4,
-.px-4 {
-  padding-right: 1.5rem !important;
-}
-
-.pb-4,
-.py-4 {
-  padding-bottom: 1.5rem !important;
-}
-
-.pl-4,
-.px-4 {
-  padding-left: 1.5rem !important;
-}
-
-.p-5 {
-  padding: 3rem !important;
-}
-
-.pt-5,
-.py-5 {
-  padding-top: 3rem !important;
-}
-
-.pr-5,
-.px-5 {
-  padding-right: 3rem !important;
-}
-
-.pb-5,
-.py-5 {
-  padding-bottom: 3rem !important;
-}
-
-.pl-5,
-.px-5 {
-  padding-left: 3rem !important;
-}
-
-.m-n1 {
-  margin: -0.25rem !important;
-}
-
-.mt-n1,
-.my-n1 {
-  margin-top: -0.25rem !important;
-}
-
-.mr-n1,
-.mx-n1 {
-  margin-right: -0.25rem !important;
-}
-
-.mb-n1,
-.my-n1 {
-  margin-bottom: -0.25rem !important;
-}
-
-.ml-n1,
-.mx-n1 {
-  margin-left: -0.25rem !important;
-}
-
-.m-n2 {
-  margin: -0.5rem !important;
-}
-
-.mt-n2,
-.my-n2 {
-  margin-top: -0.5rem !important;
-}
-
-.mr-n2,
-.mx-n2 {
-  margin-right: -0.5rem !important;
-}
-
-.mb-n2,
-.my-n2 {
-  margin-bottom: -0.5rem !important;
-}
-
-.ml-n2,
-.mx-n2 {
-  margin-left: -0.5rem !important;
-}
-
-.m-n3 {
-  margin: -1rem !important;
-}
-
-.mt-n3,
-.my-n3 {
-  margin-top: -1rem !important;
-}
-
-.mr-n3,
-.mx-n3 {
-  margin-right: -1rem !important;
-}
-
-.mb-n3,
-.my-n3 {
-  margin-bottom: -1rem !important;
-}
-
-.ml-n3,
-.mx-n3 {
-  margin-left: -1rem !important;
-}
-
-.m-n4 {
-  margin: -1.5rem !important;
-}
-
-.mt-n4,
-.my-n4 {
-  margin-top: -1.5rem !important;
-}
-
-.mr-n4,
-.mx-n4 {
-  margin-right: -1.5rem !important;
-}
-
-.mb-n4,
-.my-n4 {
-  margin-bottom: -1.5rem !important;
-}
-
-.ml-n4,
-.mx-n4 {
-  margin-left: -1.5rem !important;
-}
-
-.m-n5 {
-  margin: -3rem !important;
-}
-
-.mt-n5,
-.my-n5 {
-  margin-top: -3rem !important;
-}
-
-.mr-n5,
-.mx-n5 {
-  margin-right: -3rem !important;
-}
-
-.mb-n5,
-.my-n5 {
-  margin-bottom: -3rem !important;
-}
-
-.ml-n5,
-.mx-n5 {
-  margin-left: -3rem !important;
-}
-
-.m-auto {
-  margin: auto !important;
-}
-
-.mt-auto,
-.my-auto {
-  margin-top: auto !important;
-}
-
-.mr-auto,
-.mx-auto {
-  margin-right: auto !important;
-}
-
-.mb-auto,
-.my-auto {
-  margin-bottom: auto !important;
-}
-
-.ml-auto,
-.mx-auto {
-  margin-left: auto !important;
-}
-
-@media (min-width: 576px) {
-  .m-sm-0 {
-    margin: 0 !important;
-  }
-  .mt-sm-0,
-  .my-sm-0 {
-    margin-top: 0 !important;
-  }
-  .mr-sm-0,
-  .mx-sm-0 {
-    margin-right: 0 !important;
-  }
-  .mb-sm-0,
-  .my-sm-0 {
-    margin-bottom: 0 !important;
-  }
-  .ml-sm-0,
-  .mx-sm-0 {
-    margin-left: 0 !important;
-  }
-  .m-sm-1 {
-    margin: 0.25rem !important;
-  }
-  .mt-sm-1,
-  .my-sm-1 {
-    margin-top: 0.25rem !important;
-  }
-  .mr-sm-1,
-  .mx-sm-1 {
-    margin-right: 0.25rem !important;
-  }
-  .mb-sm-1,
-  .my-sm-1 {
-    margin-bottom: 0.25rem !important;
-  }
-  .ml-sm-1,
-  .mx-sm-1 {
-    margin-left: 0.25rem !important;
-  }
-  .m-sm-2 {
-    margin: 0.5rem !important;
-  }
-  .mt-sm-2,
-  .my-sm-2 {
-    margin-top: 0.5rem !important;
-  }
-  .mr-sm-2,
-  .mx-sm-2 {
-    margin-right: 0.5rem !important;
-  }
-  .mb-sm-2,
-  .my-sm-2 {
-    margin-bottom: 0.5rem !important;
-  }
-  .ml-sm-2,
-  .mx-sm-2 {
-    margin-left: 0.5rem !important;
-  }
-  .m-sm-3 {
-    margin: 1rem !important;
-  }
-  .mt-sm-3,
-  .my-sm-3 {
-    margin-top: 1rem !important;
-  }
-  .mr-sm-3,
-  .mx-sm-3 {
-    margin-right: 1rem !important;
-  }
-  .mb-sm-3,
-  .my-sm-3 {
-    margin-bottom: 1rem !important;
-  }
-  .ml-sm-3,
-  .mx-sm-3 {
-    margin-left: 1rem !important;
-  }
-  .m-sm-4 {
-    margin: 1.5rem !important;
-  }
-  .mt-sm-4,
-  .my-sm-4 {
-    margin-top: 1.5rem !important;
-  }
-  .mr-sm-4,
-  .mx-sm-4 {
-    margin-right: 1.5rem !important;
-  }
-  .mb-sm-4,
-  .my-sm-4 {
-    margin-bottom: 1.5rem !important;
-  }
-  .ml-sm-4,
-  .mx-sm-4 {
-    margin-left: 1.5rem !important;
-  }
-  .m-sm-5 {
-    margin: 3rem !important;
-  }
-  .mt-sm-5,
-  .my-sm-5 {
-    margin-top: 3rem !important;
-  }
-  .mr-sm-5,
-  .mx-sm-5 {
-    margin-right: 3rem !important;
-  }
-  .mb-sm-5,
-  .my-sm-5 {
-    margin-bottom: 3rem !important;
-  }
-  .ml-sm-5,
-  .mx-sm-5 {
-    margin-left: 3rem !important;
-  }
-  .p-sm-0 {
-    padding: 0 !important;
-  }
-  .pt-sm-0,
-  .py-sm-0 {
-    padding-top: 0 !important;
-  }
-  .pr-sm-0,
-  .px-sm-0 {
-    padding-right: 0 !important;
-  }
-  .pb-sm-0,
-  .py-sm-0 {
-    padding-bottom: 0 !important;
-  }
-  .pl-sm-0,
-  .px-sm-0 {
-    padding-left: 0 !important;
-  }
-  .p-sm-1 {
-    padding: 0.25rem !important;
-  }
-  .pt-sm-1,
-  .py-sm-1 {
-    padding-top: 0.25rem !important;
-  }
-  .pr-sm-1,
-  .px-sm-1 {
-    padding-right: 0.25rem !important;
-  }
-  .pb-sm-1,
-  .py-sm-1 {
-    padding-bottom: 0.25rem !important;
-  }
-  .pl-sm-1,
-  .px-sm-1 {
-    padding-left: 0.25rem !important;
-  }
-  .p-sm-2 {
-    padding: 0.5rem !important;
-  }
-  .pt-sm-2,
-  .py-sm-2 {
-    padding-top: 0.5rem !important;
-  }
-  .pr-sm-2,
-  .px-sm-2 {
-    padding-right: 0.5rem !important;
-  }
-  .pb-sm-2,
-  .py-sm-2 {
-    padding-bottom: 0.5rem !important;
-  }
-  .pl-sm-2,
-  .px-sm-2 {
-    padding-left: 0.5rem !important;
-  }
-  .p-sm-3 {
-    padding: 1rem !important;
-  }
-  .pt-sm-3,
-  .py-sm-3 {
-    padding-top: 1rem !important;
-  }
-  .pr-sm-3,
-  .px-sm-3 {
-    padding-right: 1rem !important;
-  }
-  .pb-sm-3,
-  .py-sm-3 {
-    padding-bottom: 1rem !important;
-  }
-  .pl-sm-3,
-  .px-sm-3 {
-    padding-left: 1rem !important;
-  }
-  .p-sm-4 {
-    padding: 1.5rem !important;
-  }
-  .pt-sm-4,
-  .py-sm-4 {
-    padding-top: 1.5rem !important;
-  }
-  .pr-sm-4,
-  .px-sm-4 {
-    padding-right: 1.5rem !important;
-  }
-  .pb-sm-4,
-  .py-sm-4 {
-    padding-bottom: 1.5rem !important;
-  }
-  .pl-sm-4,
-  .px-sm-4 {
-    padding-left: 1.5rem !important;
-  }
-  .p-sm-5 {
-    padding: 3rem !important;
-  }
-  .pt-sm-5,
-  .py-sm-5 {
-    padding-top: 3rem !important;
-  }
-  .pr-sm-5,
-  .px-sm-5 {
-    padding-right: 3rem !important;
-  }
-  .pb-sm-5,
-  .py-sm-5 {
-    padding-bottom: 3rem !important;
-  }
-  .pl-sm-5,
-  .px-sm-5 {
-    padding-left: 3rem !important;
-  }
-  .m-sm-n1 {
-    margin: -0.25rem !important;
-  }
-  .mt-sm-n1,
-  .my-sm-n1 {
-    margin-top: -0.25rem !important;
-  }
-  .mr-sm-n1,
-  .mx-sm-n1 {
-    margin-right: -0.25rem !important;
-  }
-  .mb-sm-n1,
-  .my-sm-n1 {
-    margin-bottom: -0.25rem !important;
-  }
-  .ml-sm-n1,
-  .mx-sm-n1 {
-    margin-left: -0.25rem !important;
-  }
-  .m-sm-n2 {
-    margin: -0.5rem !important;
-  }
-  .mt-sm-n2,
-  .my-sm-n2 {
-    margin-top: -0.5rem !important;
-  }
-  .mr-sm-n2,
-  .mx-sm-n2 {
-    margin-right: -0.5rem !important;
-  }
-  .mb-sm-n2,
-  .my-sm-n2 {
-    margin-bottom: -0.5rem !important;
-  }
-  .ml-sm-n2,
-  .mx-sm-n2 {
-    margin-left: -0.5rem !important;
-  }
-  .m-sm-n3 {
-    margin: -1rem !important;
-  }
-  .mt-sm-n3,
-  .my-sm-n3 {
-    margin-top: -1rem !important;
-  }
-  .mr-sm-n3,
-  .mx-sm-n3 {
-    margin-right: -1rem !important;
-  }
-  .mb-sm-n3,
-  .my-sm-n3 {
-    margin-bottom: -1rem !important;
-  }
-  .ml-sm-n3,
-  .mx-sm-n3 {
-    margin-left: -1rem !important;
-  }
-  .m-sm-n4 {
-    margin: -1.5rem !important;
-  }
-  .mt-sm-n4,
-  .my-sm-n4 {
-    margin-top: -1.5rem !important;
-  }
-  .mr-sm-n4,
-  .mx-sm-n4 {
-    margin-right: -1.5rem !important;
-  }
-  .mb-sm-n4,
-  .my-sm-n4 {
-    margin-bottom: -1.5rem !important;
-  }
-  .ml-sm-n4,
-  .mx-sm-n4 {
-    margin-left: -1.5rem !important;
-  }
-  .m-sm-n5 {
-    margin: -3rem !important;
-  }
-  .mt-sm-n5,
-  .my-sm-n5 {
-    margin-top: -3rem !important;
-  }
-  .mr-sm-n5,
-  .mx-sm-n5 {
-    margin-right: -3rem !important;
-  }
-  .mb-sm-n5,
-  .my-sm-n5 {
-    margin-bottom: -3rem !important;
-  }
-  .ml-sm-n5,
-  .mx-sm-n5 {
-    margin-left: -3rem !important;
-  }
-  .m-sm-auto {
-    margin: auto !important;
-  }
-  .mt-sm-auto,
-  .my-sm-auto {
-    margin-top: auto !important;
-  }
-  .mr-sm-auto,
-  .mx-sm-auto {
-    margin-right: auto !important;
-  }
-  .mb-sm-auto,
-  .my-sm-auto {
-    margin-bottom: auto !important;
-  }
-  .ml-sm-auto,
-  .mx-sm-auto {
-    margin-left: auto !important;
-  }
-}
-
-@media (min-width: 768px) {
-  .m-md-0 {
-    margin: 0 !important;
-  }
-  .mt-md-0,
-  .my-md-0 {
-    margin-top: 0 !important;
-  }
-  .mr-md-0,
-  .mx-md-0 {
-    margin-right: 0 !important;
-  }
-  .mb-md-0,
-  .my-md-0 {
-    margin-bottom: 0 !important;
-  }
-  .ml-md-0,
-  .mx-md-0 {
-    margin-left: 0 !important;
-  }
-  .m-md-1 {
-    margin: 0.25rem !important;
-  }
-  .mt-md-1,
-  .my-md-1 {
-    margin-top: 0.25rem !important;
-  }
-  .mr-md-1,
-  .mx-md-1 {
-    margin-right: 0.25rem !important;
-  }
-  .mb-md-1,
-  .my-md-1 {
-    margin-bottom: 0.25rem !important;
-  }
-  .ml-md-1,
-  .mx-md-1 {
-    margin-left: 0.25rem !important;
-  }
-  .m-md-2 {
-    margin: 0.5rem !important;
-  }
-  .mt-md-2,
-  .my-md-2 {
-    margin-top: 0.5rem !important;
-  }
-  .mr-md-2,
-  .mx-md-2 {
-    margin-right: 0.5rem !important;
-  }
-  .mb-md-2,
-  .my-md-2 {
-    margin-bottom: 0.5rem !important;
-  }
-  .ml-md-2,
-  .mx-md-2 {
-    margin-left: 0.5rem !important;
-  }
-  .m-md-3 {
-    margin: 1rem !important;
-  }
-  .mt-md-3,
-  .my-md-3 {
-    margin-top: 1rem !important;
-  }
-  .mr-md-3,
-  .mx-md-3 {
-    margin-right: 1rem !important;
-  }
-  .mb-md-3,
-  .my-md-3 {
-    margin-bottom: 1rem !important;
-  }
-  .ml-md-3,
-  .mx-md-3 {
-    margin-left: 1rem !important;
-  }
-  .m-md-4 {
-    margin: 1.5rem !important;
-  }
-  .mt-md-4,
-  .my-md-4 {
-    margin-top: 1.5rem !important;
-  }
-  .mr-md-4,
-  .mx-md-4 {
-    margin-right: 1.5rem !important;
-  }
-  .mb-md-4,
-  .my-md-4 {
-    margin-bottom: 1.5rem !important;
-  }
-  .ml-md-4,
-  .mx-md-4 {
-    margin-left: 1.5rem !important;
-  }
-  .m-md-5 {
-    margin: 3rem !important;
-  }
-  .mt-md-5,
-  .my-md-5 {
-    margin-top: 3rem !important;
-  }
-  .mr-md-5,
-  .mx-md-5 {
-    margin-right: 3rem !important;
-  }
-  .mb-md-5,
-  .my-md-5 {
-    margin-bottom: 3rem !important;
-  }
-  .ml-md-5,
-  .mx-md-5 {
-    margin-left: 3rem !important;
-  }
-  .p-md-0 {
-    padding: 0 !important;
-  }
-  .pt-md-0,
-  .py-md-0 {
-    padding-top: 0 !important;
-  }
-  .pr-md-0,
-  .px-md-0 {
-    padding-right: 0 !important;
-  }
-  .pb-md-0,
-  .py-md-0 {
-    padding-bottom: 0 !important;
-  }
-  .pl-md-0,
-  .px-md-0 {
-    padding-left: 0 !important;
-  }
-  .p-md-1 {
-    padding: 0.25rem !important;
-  }
-  .pt-md-1,
-  .py-md-1 {
-    padding-top: 0.25rem !important;
-  }
-  .pr-md-1,
-  .px-md-1 {
-    padding-right: 0.25rem !important;
-  }
-  .pb-md-1,
-  .py-md-1 {
-    padding-bottom: 0.25rem !important;
-  }
-  .pl-md-1,
-  .px-md-1 {
-    padding-left: 0.25rem !important;
-  }
-  .p-md-2 {
-    padding: 0.5rem !important;
-  }
-  .pt-md-2,
-  .py-md-2 {
-    padding-top: 0.5rem !important;
-  }
-  .pr-md-2,
-  .px-md-2 {
-    padding-right: 0.5rem !important;
-  }
-  .pb-md-2,
-  .py-md-2 {
-    padding-bottom: 0.5rem !important;
-  }
-  .pl-md-2,
-  .px-md-2 {
-    padding-left: 0.5rem !important;
-  }
-  .p-md-3 {
-    padding: 1rem !important;
-  }
-  .pt-md-3,
-  .py-md-3 {
-    padding-top: 1rem !important;
-  }
-  .pr-md-3,
-  .px-md-3 {
-    padding-right: 1rem !important;
-  }
-  .pb-md-3,
-  .py-md-3 {
-    padding-bottom: 1rem !important;
-  }
-  .pl-md-3,
-  .px-md-3 {
-    padding-left: 1rem !important;
-  }
-  .p-md-4 {
-    padding: 1.5rem !important;
-  }
-  .pt-md-4,
-  .py-md-4 {
-    padding-top: 1.5rem !important;
-  }
-  .pr-md-4,
-  .px-md-4 {
-    padding-right: 1.5rem !important;
-  }
-  .pb-md-4,
-  .py-md-4 {
-    padding-bottom: 1.5rem !important;
-  }
-  .pl-md-4,
-  .px-md-4 {
-    padding-left: 1.5rem !important;
-  }
-  .p-md-5 {
-    padding: 3rem !important;
-  }
-  .pt-md-5,
-  .py-md-5 {
-    padding-top: 3rem !important;
-  }
-  .pr-md-5,
-  .px-md-5 {
-    padding-right: 3rem !important;
-  }
-  .pb-md-5,
-  .py-md-5 {
-    padding-bottom: 3rem !important;
-  }
-  .pl-md-5,
-  .px-md-5 {
-    padding-left: 3rem !important;
-  }
-  .m-md-n1 {
-    margin: -0.25rem !important;
-  }
-  .mt-md-n1,
-  .my-md-n1 {
-    margin-top: -0.25rem !important;
-  }
-  .mr-md-n1,
-  .mx-md-n1 {
-    margin-right: -0.25rem !important;
-  }
-  .mb-md-n1,
-  .my-md-n1 {
-    margin-bottom: -0.25rem !important;
-  }
-  .ml-md-n1,
-  .mx-md-n1 {
-    margin-left: -0.25rem !important;
-  }
-  .m-md-n2 {
-    margin: -0.5rem !important;
-  }
-  .mt-md-n2,
-  .my-md-n2 {
-    margin-top: -0.5rem !important;
-  }
-  .mr-md-n2,
-  .mx-md-n2 {
-    margin-right: -0.5rem !important;
-  }
-  .mb-md-n2,
-  .my-md-n2 {
-    margin-bottom: -0.5rem !important;
-  }
-  .ml-md-n2,
-  .mx-md-n2 {
-    margin-left: -0.5rem !important;
-  }
-  .m-md-n3 {
-    margin: -1rem !important;
-  }
-  .mt-md-n3,
-  .my-md-n3 {
-    margin-top: -1rem !important;
-  }
-  .mr-md-n3,
-  .mx-md-n3 {
-    margin-right: -1rem !important;
-  }
-  .mb-md-n3,
-  .my-md-n3 {
-    margin-bottom: -1rem !important;
-  }
-  .ml-md-n3,
-  .mx-md-n3 {
-    margin-left: -1rem !important;
-  }
-  .m-md-n4 {
-    margin: -1.5rem !important;
-  }
-  .mt-md-n4,
-  .my-md-n4 {
-    margin-top: -1.5rem !important;
-  }
-  .mr-md-n4,
-  .mx-md-n4 {
-    margin-right: -1.5rem !important;
-  }
-  .mb-md-n4,
-  .my-md-n4 {
-    margin-bottom: -1.5rem !important;
-  }
-  .ml-md-n4,
-  .mx-md-n4 {
-    margin-left: -1.5rem !important;
-  }
-  .m-md-n5 {
-    margin: -3rem !important;
-  }
-  .mt-md-n5,
-  .my-md-n5 {
-    margin-top: -3rem !important;
-  }
-  .mr-md-n5,
-  .mx-md-n5 {
-    margin-right: -3rem !important;
-  }
-  .mb-md-n5,
-  .my-md-n5 {
-    margin-bottom: -3rem !important;
-  }
-  .ml-md-n5,
-  .mx-md-n5 {
-    margin-left: -3rem !important;
-  }
-  .m-md-auto {
-    margin: auto !important;
-  }
-  .mt-md-auto,
-  .my-md-auto {
-    margin-top: auto !important;
-  }
-  .mr-md-auto,
-  .mx-md-auto {
-    margin-right: auto !important;
-  }
-  .mb-md-auto,
-  .my-md-auto {
-    margin-bottom: auto !important;
-  }
-  .ml-md-auto,
-  .mx-md-auto {
-    margin-left: auto !important;
-  }
-}
-
-@media (min-width: 992px) {
-  .m-lg-0 {
-    margin: 0 !important;
-  }
-  .mt-lg-0,
-  .my-lg-0 {
-    margin-top: 0 !important;
-  }
-  .mr-lg-0,
-  .mx-lg-0 {
-    margin-right: 0 !important;
-  }
-  .mb-lg-0,
-  .my-lg-0 {
-    margin-bottom: 0 !important;
-  }
-  .ml-lg-0,
-  .mx-lg-0 {
-    margin-left: 0 !important;
-  }
-  .m-lg-1 {
-    margin: 0.25rem !important;
-  }
-  .mt-lg-1,
-  .my-lg-1 {
-    margin-top: 0.25rem !important;
-  }
-  .mr-lg-1,
-  .mx-lg-1 {
-    margin-right: 0.25rem !important;
-  }
-  .mb-lg-1,
-  .my-lg-1 {
-    margin-bottom: 0.25rem !important;
-  }
-  .ml-lg-1,
-  .mx-lg-1 {
-    margin-left: 0.25rem !important;
-  }
-  .m-lg-2 {
-    margin: 0.5rem !important;
-  }
-  .mt-lg-2,
-  .my-lg-2 {
-    margin-top: 0.5rem !important;
-  }
-  .mr-lg-2,
-  .mx-lg-2 {
-    margin-right: 0.5rem !important;
-  }
-  .mb-lg-2,
-  .my-lg-2 {
-    margin-bottom: 0.5rem !important;
-  }
-  .ml-lg-2,
-  .mx-lg-2 {
-    margin-left: 0.5rem !important;
-  }
-  .m-lg-3 {
-    margin: 1rem !important;
-  }
-  .mt-lg-3,
-  .my-lg-3 {
-    margin-top: 1rem !important;
-  }
-  .mr-lg-3,
-  .mx-lg-3 {
-    margin-right: 1rem !important;
-  }
-  .mb-lg-3,
-  .my-lg-3 {
-    margin-bottom: 1rem !important;
-  }
-  .ml-lg-3,
-  .mx-lg-3 {
-    margin-left: 1rem !important;
-  }
-  .m-lg-4 {
-    margin: 1.5rem !important;
-  }
-  .mt-lg-4,
-  .my-lg-4 {
-    margin-top: 1.5rem !important;
-  }
-  .mr-lg-4,
-  .mx-lg-4 {
-    margin-right: 1.5rem !important;
-  }
-  .mb-lg-4,
-  .my-lg-4 {
-    margin-bottom: 1.5rem !important;
-  }
-  .ml-lg-4,
-  .mx-lg-4 {
-    margin-left: 1.5rem !important;
-  }
-  .m-lg-5 {
-    margin: 3rem !important;
-  }
-  .mt-lg-5,
-  .my-lg-5 {
-    margin-top: 3rem !important;
-  }
-  .mr-lg-5,
-  .mx-lg-5 {
-    margin-right: 3rem !important;
-  }
-  .mb-lg-5,
-  .my-lg-5 {
-    margin-bottom: 3rem !important;
-  }
-  .ml-lg-5,
-  .mx-lg-5 {
-    margin-left: 3rem !important;
-  }
-  .p-lg-0 {
-    padding: 0 !important;
-  }
-  .pt-lg-0,
-  .py-lg-0 {
-    padding-top: 0 !important;
-  }
-  .pr-lg-0,
-  .px-lg-0 {
-    padding-right: 0 !important;
-  }
-  .pb-lg-0,
-  .py-lg-0 {
-    padding-bottom: 0 !important;
-  }
-  .pl-lg-0,
-  .px-lg-0 {
-    padding-left: 0 !important;
-  }
-  .p-lg-1 {
-    padding: 0.25rem !important;
-  }
-  .pt-lg-1,
-  .py-lg-1 {
-    padding-top: 0.25rem !important;
-  }
-  .pr-lg-1,
-  .px-lg-1 {
-    padding-right: 0.25rem !important;
-  }
-  .pb-lg-1,
-  .py-lg-1 {
-    padding-bottom: 0.25rem !important;
-  }
-  .pl-lg-1,
-  .px-lg-1 {
-    padding-left: 0.25rem !important;
-  }
-  .p-lg-2 {
-    padding: 0.5rem !important;
-  }
-  .pt-lg-2,
-  .py-lg-2 {
-    padding-top: 0.5rem !important;
-  }
-  .pr-lg-2,
-  .px-lg-2 {
-    padding-right: 0.5rem !important;
-  }
-  .pb-lg-2,
-  .py-lg-2 {
-    padding-bottom: 0.5rem !important;
-  }
-  .pl-lg-2,
-  .px-lg-2 {
-    padding-left: 0.5rem !important;
-  }
-  .p-lg-3 {
-    padding: 1rem !important;
-  }
-  .pt-lg-3,
-  .py-lg-3 {
-    padding-top: 1rem !important;
-  }
-  .pr-lg-3,
-  .px-lg-3 {
-    padding-right: 1rem !important;
-  }
-  .pb-lg-3,
-  .py-lg-3 {
-    padding-bottom: 1rem !important;
-  }
-  .pl-lg-3,
-  .px-lg-3 {
-    padding-left: 1rem !important;
-  }
-  .p-lg-4 {
-    padding: 1.5rem !important;
-  }
-  .pt-lg-4,
-  .py-lg-4 {
-    padding-top: 1.5rem !important;
-  }
-  .pr-lg-4,
-  .px-lg-4 {
-    padding-right: 1.5rem !important;
-  }
-  .pb-lg-4,
-  .py-lg-4 {
-    padding-bottom: 1.5rem !important;
-  }
-  .pl-lg-4,
-  .px-lg-4 {
-    padding-left: 1.5rem !important;
-  }
-  .p-lg-5 {
-    padding: 3rem !important;
-  }
-  .pt-lg-5,
-  .py-lg-5 {
-    padding-top: 3rem !important;
-  }
-  .pr-lg-5,
-  .px-lg-5 {
-    padding-right: 3rem !important;
-  }
-  .pb-lg-5,
-  .py-lg-5 {
-    padding-bottom: 3rem !important;
-  }
-  .pl-lg-5,
-  .px-lg-5 {
-    padding-left: 3rem !important;
-  }
-  .m-lg-n1 {
-    margin: -0.25rem !important;
-  }
-  .mt-lg-n1,
-  .my-lg-n1 {
-    margin-top: -0.25rem !important;
-  }
-  .mr-lg-n1,
-  .mx-lg-n1 {
-    margin-right: -0.25rem !important;
-  }
-  .mb-lg-n1,
-  .my-lg-n1 {
-    margin-bottom: -0.25rem !important;
-  }
-  .ml-lg-n1,
-  .mx-lg-n1 {
-    margin-left: -0.25rem !important;
-  }
-  .m-lg-n2 {
-    margin: -0.5rem !important;
-  }
-  .mt-lg-n2,
-  .my-lg-n2 {
-    margin-top: -0.5rem !important;
-  }
-  .mr-lg-n2,
-  .mx-lg-n2 {
-    margin-right: -0.5rem !important;
-  }
-  .mb-lg-n2,
-  .my-lg-n2 {
-    margin-bottom: -0.5rem !important;
-  }
-  .ml-lg-n2,
-  .mx-lg-n2 {
-    margin-left: -0.5rem !important;
-  }
-  .m-lg-n3 {
-    margin: -1rem !important;
-  }
-  .mt-lg-n3,
-  .my-lg-n3 {
-    margin-top: -1rem !important;
-  }
-  .mr-lg-n3,
-  .mx-lg-n3 {
-    margin-right: -1rem !important;
-  }
-  .mb-lg-n3,
-  .my-lg-n3 {
-    margin-bottom: -1rem !important;
-  }
-  .ml-lg-n3,
-  .mx-lg-n3 {
-    margin-left: -1rem !important;
-  }
-  .m-lg-n4 {
-    margin: -1.5rem !important;
-  }
-  .mt-lg-n4,
-  .my-lg-n4 {
-    margin-top: -1.5rem !important;
-  }
-  .mr-lg-n4,
-  .mx-lg-n4 {
-    margin-right: -1.5rem !important;
-  }
-  .mb-lg-n4,
-  .my-lg-n4 {
-    margin-bottom: -1.5rem !important;
-  }
-  .ml-lg-n4,
-  .mx-lg-n4 {
-    margin-left: -1.5rem !important;
-  }
-  .m-lg-n5 {
-    margin: -3rem !important;
-  }
-  .mt-lg-n5,
-  .my-lg-n5 {
-    margin-top: -3rem !important;
-  }
-  .mr-lg-n5,
-  .mx-lg-n5 {
-    margin-right: -3rem !important;
-  }
-  .mb-lg-n5,
-  .my-lg-n5 {
-    margin-bottom: -3rem !important;
-  }
-  .ml-lg-n5,
-  .mx-lg-n5 {
-    margin-left: -3rem !important;
-  }
-  .m-lg-auto {
-    margin: auto !important;
-  }
-  .mt-lg-auto,
-  .my-lg-auto {
-    margin-top: auto !important;
-  }
-  .mr-lg-auto,
-  .mx-lg-auto {
-    margin-right: auto !important;
-  }
-  .mb-lg-auto,
-  .my-lg-auto {
-    margin-bottom: auto !important;
-  }
-  .ml-lg-auto,
-  .mx-lg-auto {
-    margin-left: auto !important;
-  }
-}
-
-@media (min-width: 1200px) {
-  .m-xl-0 {
-    margin: 0 !important;
-  }
-  .mt-xl-0,
-  .my-xl-0 {
-    margin-top: 0 !important;
-  }
-  .mr-xl-0,
-  .mx-xl-0 {
-    margin-right: 0 !important;
-  }
-  .mb-xl-0,
-  .my-xl-0 {
-    margin-bottom: 0 !important;
-  }
-  .ml-xl-0,
-  .mx-xl-0 {
-    margin-left: 0 !important;
-  }
-  .m-xl-1 {
-    margin: 0.25rem !important;
-  }
-  .mt-xl-1,
-  .my-xl-1 {
-    margin-top: 0.25rem !important;
-  }
-  .mr-xl-1,
-  .mx-xl-1 {
-    margin-right: 0.25rem !important;
-  }
-  .mb-xl-1,
-  .my-xl-1 {
-    margin-bottom: 0.25rem !important;
-  }
-  .ml-xl-1,
-  .mx-xl-1 {
-    margin-left: 0.25rem !important;
-  }
-  .m-xl-2 {
-    margin: 0.5rem !important;
-  }
-  .mt-xl-2,
-  .my-xl-2 {
-    margin-top: 0.5rem !important;
-  }
-  .mr-xl-2,
-  .mx-xl-2 {
-    margin-right: 0.5rem !important;
-  }
-  .mb-xl-2,
-  .my-xl-2 {
-    margin-bottom: 0.5rem !important;
-  }
-  .ml-xl-2,
-  .mx-xl-2 {
-    margin-left: 0.5rem !important;
-  }
-  .m-xl-3 {
-    margin: 1rem !important;
-  }
-  .mt-xl-3,
-  .my-xl-3 {
-    margin-top: 1rem !important;
-  }
-  .mr-xl-3,
-  .mx-xl-3 {
-    margin-right: 1rem !important;
-  }
-  .mb-xl-3,
-  .my-xl-3 {
-    margin-bottom: 1rem !important;
-  }
-  .ml-xl-3,
-  .mx-xl-3 {
-    margin-left: 1rem !important;
-  }
-  .m-xl-4 {
-    margin: 1.5rem !important;
-  }
-  .mt-xl-4,
-  .my-xl-4 {
-    margin-top: 1.5rem !important;
-  }
-  .mr-xl-4,
-  .mx-xl-4 {
-    margin-right: 1.5rem !important;
-  }
-  .mb-xl-4,
-  .my-xl-4 {
-    margin-bottom: 1.5rem !important;
-  }
-  .ml-xl-4,
-  .mx-xl-4 {
-    margin-left: 1.5rem !important;
-  }
-  .m-xl-5 {
-    margin: 3rem !important;
-  }
-  .mt-xl-5,
-  .my-xl-5 {
-    margin-top: 3rem !important;
-  }
-  .mr-xl-5,
-  .mx-xl-5 {
-    margin-right: 3rem !important;
-  }
-  .mb-xl-5,
-  .my-xl-5 {
-    margin-bottom: 3rem !important;
-  }
-  .ml-xl-5,
-  .mx-xl-5 {
-    margin-left: 3rem !important;
-  }
-  .p-xl-0 {
-    padding: 0 !important;
-  }
-  .pt-xl-0,
-  .py-xl-0 {
-    padding-top: 0 !important;
-  }
-  .pr-xl-0,
-  .px-xl-0 {
-    padding-right: 0 !important;
-  }
-  .pb-xl-0,
-  .py-xl-0 {
-    padding-bottom: 0 !important;
-  }
-  .pl-xl-0,
-  .px-xl-0 {
-    padding-left: 0 !important;
-  }
-  .p-xl-1 {
-    padding: 0.25rem !important;
-  }
-  .pt-xl-1,
-  .py-xl-1 {
-    padding-top: 0.25rem !important;
-  }
-  .pr-xl-1,
-  .px-xl-1 {
-    padding-right: 0.25rem !important;
-  }
-  .pb-xl-1,
-  .py-xl-1 {
-    padding-bottom: 0.25rem !important;
-  }
-  .pl-xl-1,
-  .px-xl-1 {
-    padding-left: 0.25rem !important;
-  }
-  .p-xl-2 {
-    padding: 0.5rem !important;
-  }
-  .pt-xl-2,
-  .py-xl-2 {
-    padding-top: 0.5rem !important;
-  }
-  .pr-xl-2,
-  .px-xl-2 {
-    padding-right: 0.5rem !important;
-  }
-  .pb-xl-2,
-  .py-xl-2 {
-    padding-bottom: 0.5rem !important;
-  }
-  .pl-xl-2,
-  .px-xl-2 {
-    padding-left: 0.5rem !important;
-  }
-  .p-xl-3 {
-    padding: 1rem !important;
-  }
-  .pt-xl-3,
-  .py-xl-3 {
-    padding-top: 1rem !important;
-  }
-  .pr-xl-3,
-  .px-xl-3 {
-    padding-right: 1rem !important;
-  }
-  .pb-xl-3,
-  .py-xl-3 {
-    padding-bottom: 1rem !important;
-  }
-  .pl-xl-3,
-  .px-xl-3 {
-    padding-left: 1rem !important;
-  }
-  .p-xl-4 {
-    padding: 1.5rem !important;
-  }
-  .pt-xl-4,
-  .py-xl-4 {
-    padding-top: 1.5rem !important;
-  }
-  .pr-xl-4,
-  .px-xl-4 {
-    padding-right: 1.5rem !important;
-  }
-  .pb-xl-4,
-  .py-xl-4 {
-    padding-bottom: 1.5rem !important;
-  }
-  .pl-xl-4,
-  .px-xl-4 {
-    padding-left: 1.5rem !important;
-  }
-  .p-xl-5 {
-    padding: 3rem !important;
-  }
-  .pt-xl-5,
-  .py-xl-5 {
-    padding-top: 3rem !important;
-  }
-  .pr-xl-5,
-  .px-xl-5 {
-    padding-right: 3rem !important;
-  }
-  .pb-xl-5,
-  .py-xl-5 {
-    padding-bottom: 3rem !important;
-  }
-  .pl-xl-5,
-  .px-xl-5 {
-    padding-left: 3rem !important;
-  }
-  .m-xl-n1 {
-    margin: -0.25rem !important;
-  }
-  .mt-xl-n1,
-  .my-xl-n1 {
-    margin-top: -0.25rem !important;
-  }
-  .mr-xl-n1,
-  .mx-xl-n1 {
-    margin-right: -0.25rem !important;
-  }
-  .mb-xl-n1,
-  .my-xl-n1 {
-    margin-bottom: -0.25rem !important;
-  }
-  .ml-xl-n1,
-  .mx-xl-n1 {
-    margin-left: -0.25rem !important;
-  }
-  .m-xl-n2 {
-    margin: -0.5rem !important;
-  }
-  .mt-xl-n2,
-  .my-xl-n2 {
-    margin-top: -0.5rem !important;
-  }
-  .mr-xl-n2,
-  .mx-xl-n2 {
-    margin-right: -0.5rem !important;
-  }
-  .mb-xl-n2,
-  .my-xl-n2 {
-    margin-bottom: -0.5rem !important;
-  }
-  .ml-xl-n2,
-  .mx-xl-n2 {
-    margin-left: -0.5rem !important;
-  }
-  .m-xl-n3 {
-    margin: -1rem !important;
-  }
-  .mt-xl-n3,
-  .my-xl-n3 {
-    margin-top: -1rem !important;
-  }
-  .mr-xl-n3,
-  .mx-xl-n3 {
-    margin-right: -1rem !important;
-  }
-  .mb-xl-n3,
-  .my-xl-n3 {
-    margin-bottom: -1rem !important;
-  }
-  .ml-xl-n3,
-  .mx-xl-n3 {
-    margin-left: -1rem !important;
-  }
-  .m-xl-n4 {
-    margin: -1.5rem !important;
-  }
-  .mt-xl-n4,
-  .my-xl-n4 {
-    margin-top: -1.5rem !important;
-  }
-  .mr-xl-n4,
-  .mx-xl-n4 {
-    margin-right: -1.5rem !important;
-  }
-  .mb-xl-n4,
-  .my-xl-n4 {
-    margin-bottom: -1.5rem !important;
-  }
-  .ml-xl-n4,
-  .mx-xl-n4 {
-    margin-left: -1.5rem !important;
-  }
-  .m-xl-n5 {
-    margin: -3rem !important;
-  }
-  .mt-xl-n5,
-  .my-xl-n5 {
-    margin-top: -3rem !important;
-  }
-  .mr-xl-n5,
-  .mx-xl-n5 {
-    margin-right: -3rem !important;
-  }
-  .mb-xl-n5,
-  .my-xl-n5 {
-    margin-bottom: -3rem !important;
-  }
-  .ml-xl-n5,
-  .mx-xl-n5 {
-    margin-left: -3rem !important;
-  }
-  .m-xl-auto {
-    margin: auto !important;
-  }
-  .mt-xl-auto,
-  .my-xl-auto {
-    margin-top: auto !important;
-  }
-  .mr-xl-auto,
-  .mx-xl-auto {
-    margin-right: auto !important;
-  }
-  .mb-xl-auto,
-  .my-xl-auto {
-    margin-bottom: auto !important;
-  }
-  .ml-xl-auto,
-  .mx-xl-auto {
-    margin-left: auto !important;
-  }
-}
-
-.stretched-link::after {
-  position: absolute;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 1;
-  pointer-events: auto;
-  content: "";
-  background-color: rgba(0, 0, 0, 0);
-}
-
-.text-monospace {
-  font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !important;
-}
-
-.text-justify {
-  text-align: justify !important;
-}
-
-.text-wrap {
-  white-space: normal !important;
-}
-
-.text-nowrap {
-  white-space: nowrap !important;
-}
-
-.text-truncate {
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.text-left {
-  text-align: left !important;
-}
-
-.text-right {
-  text-align: right !important;
-}
-
-.text-center {
-  text-align: center !important;
-}
-
-@media (min-width: 576px) {
-  .text-sm-left {
-    text-align: left !important;
-  }
-  .text-sm-right {
-    text-align: right !important;
-  }
-  .text-sm-center {
-    text-align: center !important;
-  }
-}
-
-@media (min-width: 768px) {
-  .text-md-left {
-    text-align: left !important;
-  }
-  .text-md-right {
-    text-align: right !important;
-  }
-  .text-md-center {
-    text-align: center !important;
-  }
-}
-
-@media (min-width: 992px) {
-  .text-lg-left {
-    text-align: left !important;
-  }
-  .text-lg-right {
-    text-align: right !important;
-  }
-  .text-lg-center {
-    text-align: center !important;
-  }
-}
-
-@media (min-width: 1200px) {
-  .text-xl-left {
-    text-align: left !important;
-  }
-  .text-xl-right {
-    text-align: right !important;
-  }
-  .text-xl-center {
-    text-align: center !important;
-  }
-}
-
-.text-lowercase {
-  text-transform: lowercase !important;
-}
-
-.text-uppercase, .dropdown .dropdown-menu .dropdown-header, .sidebar .sidebar-heading {
-  text-transform: uppercase !important;
-}
-
-.text-capitalize {
-  text-transform: capitalize !important;
-}
-
-.font-weight-light {
-  font-weight: 300 !important;
-}
-
-.font-weight-lighter {
-  font-weight: lighter !important;
-}
-
-.font-weight-normal {
-  font-weight: 400 !important;
-}
-
-.font-weight-bold {
-  font-weight: 700 !important;
-}
-
-.font-weight-bolder {
-  font-weight: bolder !important;
-}
-
-.font-italic {
-  font-style: italic !important;
-}
-
-.text-white {
-  color: #fff !important;
-}
-
-.text-primary {
-  color: #4e73df !important;
-}
-
-a.text-primary:hover, a.text-primary:focus {
-  color: #224abe !important;
-}
-
-.text-secondary {
-  color: #858796 !important;
-}
-
-a.text-secondary:hover, a.text-secondary:focus {
-  color: #60616f !important;
-}
-
-.text-success {
-  color: #1cc88a !important;
-}
-
-a.text-success:hover, a.text-success:focus {
-  color: #13855c !important;
-}
-
-.text-info {
-  color: #36b9cc !important;
-}
-
-a.text-info:hover, a.text-info:focus {
-  color: #258391 !important;
-}
-
-.text-warning {
-  color: #f6c23e !important;
-}
-
-a.text-warning:hover, a.text-warning:focus {
-  color: #dda20a !important;
-}
-
-.text-danger {
-  color: #e74a3b !important;
-}
-
-a.text-danger:hover, a.text-danger:focus {
-  color: #be2617 !important;
-}
-
-.text-light {
-  color: #f8f9fc !important;
-}
-
-a.text-light:hover, a.text-light:focus {
-  color: #c2cbe5 !important;
-}
-
-.text-dark {
-  color: #5a5c69 !important;
-}
-
-a.text-dark:hover, a.text-dark:focus {
-  color: #373840 !important;
-}
-
-.text-body {
-  color: #858796 !important;
-}
-
-.text-muted {
-  color: #858796 !important;
-}
-
-.text-black-50 {
-  color: rgba(0, 0, 0, 0.5) !important;
-}
-
-.text-white-50 {
-  color: rgba(255, 255, 255, 0.5) !important;
-}
-
-.text-hide {
-  font: 0/0 a;
-  color: transparent;
-  text-shadow: none;
-  background-color: transparent;
-  border: 0;
-}
-
-.text-decoration-none {
-  text-decoration: none !important;
-}
-
-.text-break {
-  word-break: break-word !important;
-  word-wrap: break-word !important;
-}
-
-.text-reset {
-  color: inherit !important;
-}
-
-.visible {
-  visibility: visible !important;
-}
-
-.invisible {
-  visibility: hidden !important;
-}
-
-@media print {
-  *,
-  *::before,
-  *::after {
-    text-shadow: none !important;
-    box-shadow: none !important;
-  }
-  a:not(.btn) {
-    text-decoration: underline;
-  }
-  abbr[title]::after {
-    content: " (" attr(title) ")";
-  }
-  pre {
-    white-space: pre-wrap !important;
-  }
-  pre,
-  blockquote {
-    border: 1px solid #b7b9cc;
-    page-break-inside: avoid;
-  }
-  thead {
-    display: table-header-group;
-  }
-  tr,
-  img {
-    page-break-inside: avoid;
-  }
-  p,
-  h2,
-  h3 {
-    orphans: 3;
-    widows: 3;
-  }
-  h2,
-  h3 {
-    page-break-after: avoid;
-  }
-  @page {
-    size: a3;
-  }
-  body {
-    min-width: 992px !important;
-  }
-  .container {
-    min-width: 992px !important;
-  }
-  .navbar {
-    display: none;
-  }
-  .badge {
-    border: 1px solid #000;
-  }
-  .table {
-    border-collapse: collapse !important;
-  }
-  .table td,
-  .table th {
-    background-color: #fff !important;
-  }
-  .table-bordered th,
-  .table-bordered td {
-    border: 1px solid #dddfeb !important;
-  }
-  .table-dark {
-    color: inherit;
-  }
-  .table-dark th,
-  .table-dark td,
-  .table-dark thead th,
-  .table-dark tbody + tbody {
-    border-color: #e3e6f0;
-  }
-  .table .thead-dark th {
-    color: inherit;
-    border-color: #e3e6f0;
-  }
-}
-
-html {
-  position: relative;
-  min-height: 100%;
-}
-
-body {
-  height: 100%;
-}
-
-a:focus {
-  outline: none;
-}
-
-#wrapper {
-  display: flex;
-}
-
-#wrapper #content-wrapper {
-  background-color: #f8f9fc;
-  width: 100%;
-  overflow-x: hidden;
-}
-
-#wrapper #content-wrapper #content {
-  flex: 1 0 auto;
-}
-
-.container,
-.container-fluid,
-.container-sm,
-.container-md,
-.container-lg,
-.container-xl {
-  padding-left: 1.5rem;
-  padding-right: 1.5rem;
-}
-
-.scroll-to-top {
-  position: fixed;
-  right: 1rem;
-  bottom: 1rem;
-  display: none;
-  width: 2.75rem;
-  height: 2.75rem;
-  text-align: center;
-  color: #fff;
-  background: rgba(90, 92, 105, 0.5);
-  line-height: 46px;
-}
-
-.scroll-to-top:focus, .scroll-to-top:hover {
-  color: white;
-}
-
-.scroll-to-top:hover {
-  background: #5a5c69;
-}
-
-.scroll-to-top i {
-  font-weight: 800;
-}
-
-@-webkit-keyframes growIn {
-  0% {
-    transform: scale(0.9);
-    opacity: 0;
-  }
-  100% {
-    transform: scale(1);
-    opacity: 1;
-  }
-}
-
-@keyframes growIn {
-  0% {
-    transform: scale(0.9);
-    opacity: 0;
-  }
-  100% {
-    transform: scale(1);
-    opacity: 1;
-  }
-}
-
-.animated--grow-in, .sidebar .nav-item .collapse {
-  -webkit-animation-name: growIn;
-  animation-name: growIn;
-  -webkit-animation-duration: 200ms;
-  animation-duration: 200ms;
-  -webkit-animation-timing-function: transform cubic-bezier(0.18, 1.25, 0.4, 1), opacity cubic-bezier(0, 1, 0.4, 1);
-  animation-timing-function: transform cubic-bezier(0.18, 1.25, 0.4, 1), opacity cubic-bezier(0, 1, 0.4, 1);
-}
-
-@-webkit-keyframes fadeIn {
-  0% {
-    opacity: 0;
-  }
-  100% {
-    opacity: 1;
-  }
-}
-
-@keyframes fadeIn {
-  0% {
-    opacity: 0;
-  }
-  100% {
-    opacity: 1;
-  }
-}
-
-.animated--fade-in {
-  -webkit-animation-name: fadeIn;
-  animation-name: fadeIn;
-  -webkit-animation-duration: 200ms;
-  animation-duration: 200ms;
-  -webkit-animation-timing-function: opacity cubic-bezier(0, 1, 0.4, 1);
-  animation-timing-function: opacity cubic-bezier(0, 1, 0.4, 1);
-}
-
-.bg-gradient-primary {
-  background-color: #4e73df;
-  background-image: linear-gradient(180deg, #4e73df 10%, #224abe 100%);
-  background-size: cover;
-}
-
-.bg-gradient-secondary {
-  background-color: #858796;
-  background-image: linear-gradient(180deg, #858796 10%, #60616f 100%);
-  background-size: cover;
-}
-
-.bg-gradient-success {
-  background-color: #1cc88a;
-  background-image: linear-gradient(180deg, #1cc88a 10%, #13855c 100%);
-  background-size: cover;
-}
-
-.bg-gradient-info {
-  background-color: #36b9cc;
-  background-image: linear-gradient(180deg, #36b9cc 10%, #258391 100%);
-  background-size: cover;
-}
-
-.bg-gradient-warning {
-  background-color: #f6c23e;
-  background-image: linear-gradient(180deg, #f6c23e 10%, #dda20a 100%);
-  background-size: cover;
-}
-
-.bg-gradient-danger {
-  background-color: #e74a3b;
-  background-image: linear-gradient(180deg, #e74a3b 10%, #be2617 100%);
-  background-size: cover;
-}
-
-.bg-gradient-light {
-  background-color: #f8f9fc;
-  background-image: linear-gradient(180deg, #f8f9fc 10%, #c2cbe5 100%);
-  background-size: cover;
-}
-
-.bg-gradient-dark {
-  background-color: #5a5c69;
-  background-image: linear-gradient(180deg, #5a5c69 10%, #373840 100%);
-  background-size: cover;
-}
-
-.bg-gray-100 {
-  background-color: #f8f9fc !important;
-}
-
-.bg-gray-200 {
-  background-color: #eaecf4 !important;
-}
-
-.bg-gray-300 {
-  background-color: #dddfeb !important;
-}
-
-.bg-gray-400 {
-  background-color: #d1d3e2 !important;
-}
-
-.bg-gray-500 {
-  background-color: #b7b9cc !important;
-}
-
-.bg-gray-600 {
-  background-color: #858796 !important;
-}
-
-.bg-gray-700 {
-  background-color: #6e707e !important;
-}
-
-.bg-gray-800 {
-  background-color: #5a5c69 !important;
-}
-
-.bg-gray-900 {
-  background-color: #3a3b45 !important;
-}
-
-.o-hidden {
-  overflow: hidden !important;
-}
-
-.text-xs {
-  font-size: 1rem;
-}
-
-.text-lg {
-  font-size: 1.2rem;
-}
-
-.text-gray-100 {
-  color: #f8f9fc !important;
-}
-
-.text-gray-200 {
-  color: #eaecf4 !important;
-}
-
-.text-gray-300 {
-  color: #dddfeb !important;
-}
-
-.text-gray-400 {
-  color: #d1d3e2 !important;
-}
-
-.text-gray-500 {
-  color: #b7b9cc !important;
-}
-
-.text-gray-600 {
-  color: #858796 !important;
-}
-
-.text-gray-700 {
-  color: #6e707e !important;
-}
-
-.text-gray-800 {
-  color: #5a5c69 !important;
-}
-
-.text-gray-900 {
-  color: #3a3b45 !important;
-}
-
-.icon-circle {
-  height: 2.5rem;
-  width: 2.5rem;
-  border-radius: 100%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.border-left-primary {
-  border-left: 0.25rem solid #4e73df !important;
-}
-
-.border-bottom-primary {
-  border-bottom: 0.25rem solid #4e73df !important;
-}
-
-.border-left-secondary {
-  border-left: 0.25rem solid #858796 !important;
-}
-
-.border-bottom-secondary {
-  border-bottom: 0.25rem solid #858796 !important;
-}
-
-.border-left-success {
-  border-left: 0.25rem solid #1cc88a !important;
-}
-
-.border-bottom-success {
-  border-bottom: 0.25rem solid #1cc88a !important;
-}
-
-.border-left-info {
-  border-left: 0.25rem solid #36b9cc !important;
-}
-
-.border-bottom-info {
-  border-bottom: 0.25rem solid #36b9cc !important;
-}
-
-.border-left-warning {
-  border-left: 0.25rem solid #f6c23e !important;
-}
-
-.border-bottom-warning {
-  border-bottom: 0.25rem solid #f6c23e !important;
-}
-
-.border-left-danger {
-  border-left: 0.25rem solid #e74a3b !important;
-}
-
-.border-bottom-danger {
-  border-bottom: 0.25rem solid #e74a3b !important;
-}
-
-.border-left-light {
-  border-left: 0.25rem solid #f8f9fc !important;
-}
-
-.border-bottom-light {
-  border-bottom: 0.25rem solid #f8f9fc !important;
-}
-
-.border-left-dark {
-  border-left: 0.25rem solid #5a5c69 !important;
-}
-
-.border-bottom-dark {
-  border-bottom: 0.25rem solid #5a5c69 !important;
-}
-
-.progress-sm {
-  height: .5rem;
-}
-
-.rotate-15 {
-  transform: rotate(15deg);
-}
-
-.rotate-n-15 {
-  transform: rotate(-15deg);
-}
-
-.dropdown .dropdown-menu {
-  font-size: 0.85rem;
-}
-
-.dropdown .dropdown-menu .dropdown-header {
-  font-weight: 800;
-  font-size: 0.65rem;
-  color: #b7b9cc;
-}
-
-.dropdown.no-arrow .dropdown-toggle::after {
-  display: none;
-}
-
-.sidebar .nav-item.dropdown .dropdown-toggle::after,
-.topbar .nav-item.dropdown .dropdown-toggle::after {
-  width: 1rem;
-  text-align: center;
-  float: right;
-  vertical-align: 0;
-  border: 0;
-  font-weight: 900;
-  content: '\f105';
-  font-family: 'Font Awesome 5 Free';
-}
-
-.sidebar .nav-item.dropdown.show .dropdown-toggle::after,
-.topbar .nav-item.dropdown.show .dropdown-toggle::after {
-  content: '\f107';
-}
-
-.sidebar .nav-item .nav-link,
-.topbar .nav-item .nav-link {
-  position: relative;
-}
-
-.sidebar .nav-item .nav-link .badge-counter,
-.topbar .nav-item .nav-link .badge-counter {
-  position: absolute;
-  transform: scale(0.7);
-  transform-origin: top right;
-  right: .25rem;
-  margin-top: -.25rem;
-}
-
-.sidebar .nav-item .nav-link .img-profile,
-.topbar .nav-item .nav-link .img-profile {
-  height: 3rem;
-  width: 2rem;
-}
-
-.img-logo{
-  height: 3rem;
-  width: 2rem;
-
-}
-
-.topbar {
-  height: 4.375rem;
-}
-
-.topbar #sidebarToggleTop {
-  height: 2.5rem;
-  width: 2.5rem;
-}
-
-.topbar #sidebarToggleTop:hover {
-  background-color: #eaecf4;
-}
-
-.topbar #sidebarToggleTop:active {
-  background-color: #dddfeb;
-}
-
-.topbar .navbar-search {
-  width: 25rem;
-}
-
-.topbar .navbar-search input {
-  font-size: 0.85rem;
-  height: auto;
-}
-
-.topbar .topbar-divider {
-  width: 0;
-  border-right: 1px solid #e3e6f0;
-  height: calc(4.375rem - 2rem);
-  margin: auto 1rem;
-}
-
-.topbar .nav-item .nav-link {
-  height: 4.375rem;
-  display: flex;
-  align-items: center;
-  padding: 0 0.75rem;
-}
-
-.topbar .nav-item .nav-link:focus {
-  outline: none;
-}
-
-.topbar .nav-item:focus {
-  outline: none;
-}
-
-.topbar .dropdown {
-  position: static;
-}
-
-.topbar .dropdown .dropdown-menu {
-  width: calc(100% - 1.5rem);
-  right: 0.75rem;
-}
-
-.topbar .dropdown-list {
-  padding: 0;
-  border: none;
-  overflow: hidden;
-}
-
-.topbar .dropdown-list .dropdown-header {
-  background-color: #4e73df;
-  border: 1px solid #4e73df;
-  padding-top: 0.75rem;
-  padding-bottom: 0.75rem;
-  color: #fff;
-}
-
-.topbar .dropdown-list .dropdown-item {
-  white-space: normal;
-  padding-top: 0.5rem;
-  padding-bottom: 0.5rem;
-  border-left: 1px solid #e3e6f0;
-  border-right: 1px solid #e3e6f0;
-  border-bottom: 1px solid #e3e6f0;
-  line-height: 1.3rem;
-}
-
-.topbar .dropdown-list .dropdown-item .dropdown-list-image {
-  position: relative;
-  height: 2.5rem;
-  width: 2.5rem;
-}
-
-.topbar .dropdown-list .dropdown-item .dropdown-list-image img {
-  height: 2.5rem;
-  width: 2.5rem;
-}
-
-.topbar .dropdown-list .dropdown-item .dropdown-list-image .status-indicator {
-  background-color: #eaecf4;
-  height: 0.75rem;
-  width: 0.75rem;
-  border-radius: 100%;
-  position: absolute;
-  bottom: 0;
-  right: 0;
-  border: 0.125rem solid #fff;
-}
-
-.topbar .dropdown-list .dropdown-item .text-truncate {
-  max-width: 10rem;
-}
-
-.topbar .dropdown-list .dropdown-item:active {
-  background-color: #eaecf4;
-  color: #3a3b45;
-}
-
-@media (min-width: 576px) {
-  .topbar .dropdown {
-    position: relative;
-  }
-  .topbar .dropdown .dropdown-menu {
-    width: auto;
-    right: 0;
-  }
-  .topbar .dropdown-list {
-    width: 20rem !important;
-  }
-  .topbar .dropdown-list .dropdown-item .text-truncate {
-    max-width: 13.375rem;
-  }
-}
-
-.topbar.navbar-dark .navbar-nav .nav-item .nav-link {
-  color: rgba(255, 255, 255, 0.8);
-}
-
-.topbar.navbar-dark .navbar-nav .nav-item .nav-link:hover {
-  color: #fff;
-}
-
-.topbar.navbar-dark .navbar-nav .nav-item .nav-link:active {
-  color: #fff;
-}
-
-.topbar.navbar-light .navbar-nav .nav-item .nav-link {
-  color: #d1d3e2;
-}
-
-.topbar.navbar-light .navbar-nav .nav-item .nav-link:hover {
-  color: #b7b9cc;
-}
-
-.topbar.navbar-light .navbar-nav .nav-item .nav-link:active {
-  color: #858796;
-}
-
-.sidebar {
-  width: 6.5rem;
-  min-height: 100vh;
-}
-
-.sidebar .nav-item {
-  position: relative;
-}
-
-.sidebar .nav-item:last-child {
-  margin-bottom: 1rem;
-}
-
-.sidebar .nav-item .nav-link {
-  text-align: center;
-  padding: 0.75rem 0.5rem;
-  width: 6.5rem;
-}
-
-.sidebar .nav-item .nav-link span {
-  font-size: 0.65rem;
-  display: block;
-}
-
-.sidebar .nav-item.active .nav-link {
-  font-weight: 700;
-}
-
-.sidebar .nav-item .collapse {
-  position: absolute;
-  left: calc(6.5rem + 1.5rem / 2);
-  z-index: 1;
-  top: 2px;
-}
-
-.sidebar .nav-item .collapse .collapse-inner {
-  border-radius: 0.35rem;
-  box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
-}
-
-.sidebar .nav-item .collapsing {
-  display: none;
-  transition: none;
-}
-
-.sidebar .nav-item .collapse .collapse-inner,
-.sidebar .nav-item .collapsing .collapse-inner {
-  padding: .5rem 0;
-  min-width: 10rem;
-  font-size: 0.85rem;
-  margin: 0 0 1rem 0;
-}
-
-.sidebar .nav-item .collapse .collapse-inner .collapse-header,
-.sidebar .nav-item .collapsing .collapse-inner .collapse-header {
-  margin: 0;
-  white-space: nowrap;
-  padding: .5rem 1.5rem;
-  text-transform: uppercase;
-  font-weight: 800;
-  font-size: 0.65rem;
-  color: #b7b9cc;
-}
-
-.sidebar .nav-item .collapse .collapse-inner .collapse-item,
-.sidebar .nav-item .collapsing .collapse-inner .collapse-item {
-  padding: 0.5rem 1rem;
-  margin: 0 0.5rem;
-  display: block;
-  color: #3a3b45;
-  text-decoration: none;
-  border-radius: 0.35rem;
-  white-space: nowrap;
-}
-
-.sidebar .nav-item .collapse .collapse-inner .collapse-item:hover,
-.sidebar .nav-item .collapsing .collapse-inner .collapse-item:hover {
-  background-color: #eaecf4;
-}
-
-.sidebar .nav-item .collapse .collapse-inner .collapse-item:active,
-.sidebar .nav-item .collapsing .collapse-inner .collapse-item:active {
-  background-color: #dddfeb;
-}
-
-.sidebar .nav-item .collapse .collapse-inner .collapse-item.active,
-.sidebar .nav-item .collapsing .collapse-inner .collapse-item.active {
-  color: #4e73df;
-  font-weight: 700;
-}
-
-.sidebar #sidebarToggle {
-  width: 2.5rem;
-  height: 2.5rem;
-  text-align: center;
-  margin-bottom: 1rem;
-  cursor: pointer;
-}
-
-.sidebar #sidebarToggle::after {
-  font-weight: 900;
-  content: '\f104';
-  font-family: 'Font Awesome 5 Free';
-  margin-right: 0.1rem;
-}
-
-.sidebar #sidebarToggle:hover {
-  text-decoration: none;
-}
-
-.sidebar #sidebarToggle:focus {
-  outline: none;
-}
-
-.sidebar.toggled {
-  width: 0 !important;
-  overflow: hidden;
-}
-
-.sidebar.toggled #sidebarToggle::after {
-  content: '\f105';
-  font-family: 'Font Awesome 5 Free';
-  margin-left: 0.25rem;
-}
-
-.sidebar.toggled .sidebar-card {
-  display: none;
-}
-
-.sidebar .sidebar-brand {
-  height: 4.375rem;
-  text-decoration: none;
-  font-size: 1rem;
-  font-weight: 800;
-  padding: 1.5rem 1rem;
-  text-align: center;
-  text-transform: uppercase;
-  letter-spacing: 0.05rem;
-  z-index: 1;
-}
-
-.sidebar .sidebar-brand .sidebar-brand-icon i {
-  font-size: 2rem;
-}
-
-.sidebar .sidebar-brand .sidebar-brand-text {
-  display: none;
-}
-
-.sidebar hr.sidebar-divider {
-  margin: 0 1rem 1rem;
-}
-
-.sidebar .sidebar-heading {
-  text-align: center;
-  padding: 0 1rem;
-  font-weight: 800;
-  font-size: 0.65rem;
-}
-
-.sidebar .sidebar-card {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  font-size: 0.875rem;
-  border-radius: 0.35rem;
-  color: rgba(255, 255, 255, 0.8);
-  margin-left: 1rem;
-  margin-right: 1rem;
-  margin-bottom: 1rem;
-  padding: 1rem;
-  background-color: rgba(0, 0, 0, 0.1);
-}
-
-.sidebar .sidebar-card .sidebar-card-illustration {
-  height: 3rem;
-  display: block;
-}
-
-.sidebar .sidebar-card .sidebar-card-title {
-  font-weight: bold;
-}
-
-.sidebar .sidebar-card p {
-  font-size: 0.75rem;
-  color: rgba(255, 255, 255, 0.5);
-}
-
-@media (min-width: 768px) {
-  .sidebar {
-    width: 14rem !important;
-  }
-  .sidebar .nav-item .collapse {
-    position: relative;
-    left: 0;
-    z-index: 1;
-    top: 0;
-    -webkit-animation: none;
-    animation: none;
-  }
-  .sidebar .nav-item .collapse .collapse-inner {
-    border-radius: 0;
-    box-shadow: none;
-  }
-  .sidebar .nav-item .collapsing {
-    display: block;
-    transition: height 0.15s ease;
-  }
-  .sidebar .nav-item .collapse,
-  .sidebar .nav-item .collapsing {
-    margin: 0 1rem;
-  }
-  .sidebar .nav-item .nav-link {
-    display: block;
-    width: 100%;
-    text-align: left;
-    padding: 1rem;
-    width: 14rem;
-  }
-  .sidebar .nav-item .nav-link i {
-    font-size: 0.85rem;
-    margin-right: 0.25rem;
-  }
-  .sidebar .nav-item .nav-link span {
-    font-size: 0.85rem;
-    display: inline;
-  }
-  .sidebar .nav-item .nav-link[data-toggle="collapse"]::after {
-    width: 1rem;
-    text-align: center;
-    float: right;
-    vertical-align: 0;
-    border: 0;
-    font-weight: 900;
-    content: '\f107';
-    font-family: 'Font Awesome 5 Free';
-  }
-  .sidebar .nav-item .nav-link[data-toggle="collapse"].collapsed::after {
-    content: '\f105';
-  }
-  .sidebar .sidebar-brand .sidebar-brand-icon i {
-    font-size: 2rem;
-  }
-  .sidebar .sidebar-brand .sidebar-brand-text {
-    display: inline;
-  }
-  .sidebar .sidebar-heading {
-    text-align: left;
-  }
-  .sidebar.toggled {
-    overflow: visible;
-    width: 6.5rem !important;
-  }
-  .sidebar.toggled .nav-item .collapse {
-    position: absolute;
-    left: calc(6.5rem + 1.5rem / 2);
-    z-index: 1;
-    top: 2px;
-    -webkit-animation-name: growIn;
-    animation-name: growIn;
-    -webkit-animation-duration: 200ms;
-    animation-duration: 200ms;
-    -webkit-animation-timing-function: transform cubic-bezier(0.18, 1.25, 0.4, 1), opacity cubic-bezier(0, 1, 0.4, 1);
-    animation-timing-function: transform cubic-bezier(0.18, 1.25, 0.4, 1), opacity cubic-bezier(0, 1, 0.4, 1);
-  }
-  .sidebar.toggled .nav-item .collapse .collapse-inner {
-    box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
-    border-radius: 0.35rem;
-  }
-  .sidebar.toggled .nav-item .collapsing {
-    display: none;
-    transition: none;
-  }
-  .sidebar.toggled .nav-item .collapse,
-  .sidebar.toggled .nav-item .collapsing {
-    margin: 0;
-  }
-  .sidebar.toggled .nav-item:last-child {
-    margin-bottom: 1rem;
-  }
-  .sidebar.toggled .nav-item .nav-link {
-    text-align: center;
-    padding: 0.75rem 1rem;
-    width: 6.5rem;
-  }
-  .sidebar.toggled .nav-item .nav-link span {
-    font-size: 0.65rem;
-    display: block;
-  }
-  .sidebar.toggled .nav-item .nav-link i {
-    margin-right: 0;
-  }
-  .sidebar.toggled .nav-item .nav-link[data-toggle="collapse"]::after {
-    display: none;
-  }
-  .sidebar.toggled .sidebar-brand .sidebar-brand-icon i {
-    font-size: 2rem;
-  }
-  .sidebar.toggled .sidebar-brand .sidebar-brand-text {
-    display: none;
-  }
-  .sidebar.toggled .sidebar-heading {
-    text-align: center;
-  }
-}
-
-.sidebar-light .sidebar-brand {
-  color: #6e707e;
-}
-
-.sidebar-light hr.sidebar-divider {
-  border-top: 1px solid #eaecf4;
-}
-
-.sidebar-light .sidebar-heading {
-  color: #b7b9cc;
-}
-
-.sidebar-light .nav-item .nav-link {
-  color: #858796;
-}
-
-.sidebar-light .nav-item .nav-link i {
-  color: #d1d3e2;
-}
-
-.sidebar-light .nav-item .nav-link:active, .sidebar-light .nav-item .nav-link:focus, .sidebar-light .nav-item .nav-link:hover {
-  color: #6e707e;
-}
-
-.sidebar-light .nav-item .nav-link:active i, .sidebar-light .nav-item .nav-link:focus i, .sidebar-light .nav-item .nav-link:hover i {
-  color: #6e707e;
-}
-
-.sidebar-light .nav-item .nav-link[data-toggle="collapse"]::after {
-  color: #b7b9cc;
-}
-
-.sidebar-light .nav-item.active .nav-link {
-  color: #6e707e;
-}
-
-.sidebar-light .nav-item.active .nav-link i {
-  color: #6e707e;
-}
-
-.sidebar-light #sidebarToggle {
-  background-color: #eaecf4;
-}
-
-.sidebar-light #sidebarToggle::after {
-  color: #b7b9cc;
-}
-
-.sidebar-light #sidebarToggle:hover {
-  background-color: #dddfeb;
-}
-
-.sidebar-dark .sidebar-brand {
-  color: #fff;
-}
-
-.sidebar-dark hr.sidebar-divider {
-  border-top: 1px solid rgba(255, 255, 255, 0.15);
-}
-
-.sidebar-dark .sidebar-heading {
-  color: rgba(255, 255, 255, 0.4);
-}
-
-.sidebar-dark .nav-item .nav-link {
-  color: rgba(255, 255, 255, 0.8);
-}
-
-.sidebar-dark .nav-item .nav-link i {
-  color: rgba(255, 255, 255, 0.3);
-}
-
-.sidebar-dark .nav-item .nav-link:active, .sidebar-dark .nav-item .nav-link:focus, .sidebar-dark .nav-item .nav-link:hover {
-  color: #fff;
-}
-
-.sidebar-dark .nav-item .nav-link:active i, .sidebar-dark .nav-item .nav-link:focus i, .sidebar-dark .nav-item .nav-link:hover i {
-  color: #fff;
-}
-
-.sidebar-dark .nav-item .nav-link[data-toggle="collapse"]::after {
-  color: rgba(255, 255, 255, 0.5);
-}
-
-.sidebar-dark .nav-item.active .nav-link {
-  color: #fff;
-}
-
-.sidebar-dark .nav-item.active .nav-link i {
-  color: #fff;
-}
-
-.sidebar-dark #sidebarToggle {
-  background-color: rgba(255, 255, 255, 0.2);
-}
-
-.sidebar-dark #sidebarToggle::after {
-  color: rgba(255, 255, 255, 0.5);
-}
-
-.sidebar-dark #sidebarToggle:hover {
-  background-color: rgba(255, 255, 255, 0.25);
-}
-
-.sidebar-dark.toggled #sidebarToggle::after {
-  color: rgba(255, 255, 255, 0.5);
-}
-
-.btn-circle {
-  border-radius: 100%;
-  height: 2.5rem;
-  width: 2.5rem;
-  font-size: 1rem;
-  display: inline-flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.btn-circle.btn-sm, .btn-group-sm > .btn-circle.btn {
-  height: 1.8rem;
-  width: 1.8rem;
-  font-size: 0.75rem;
-}
-
-.btn-circle.btn-lg, .btn-group-lg > .btn-circle.btn {
-  height: 3.5rem;
-  width: 3.5rem;
-  font-size: 1.35rem;
-}
-
-.btn-icon-split {
-  padding: 0;
-  overflow: hidden;
-  display: inline-flex;
-  align-items: stretch;
-  justify-content: center;
-}
-
-.btn-icon-split .icon {
-  background: rgba(0, 0, 0, 0.15);
-  display: inline-block;
-  padding: 0.375rem 0.75rem;
-}
-
-.btn-icon-split .text {
-  display: inline-block;
-  padding: 0.375rem 0.75rem;
-}
-
-.btn-icon-split.btn-sm .icon, .btn-group-sm > .btn-icon-split.btn .icon {
-  padding: 0.25rem 0.5rem;
-}
-
-.btn-icon-split.btn-sm .text, .btn-group-sm > .btn-icon-split.btn .text {
-  padding: 0.25rem 0.5rem;
-}
-
-.btn-icon-split.btn-lg .icon, .btn-group-lg > .btn-icon-split.btn .icon {
-  padding: 0.5rem 1rem;
-}
-
-.btn-icon-split.btn-lg .text, .btn-group-lg > .btn-icon-split.btn .text {
-  padding: 0.5rem 1rem;
-}
-
-.card .card-header .dropdown {
-  line-height: 1;
-}
-
-.card .card-header .dropdown .dropdown-menu {
-  line-height: 1.5;
-}
-
-.card .card-header[data-toggle="collapse"] {
-  text-decoration: none;
-  position: relative;
-  padding: 0.75rem 3.25rem 0.75rem 1.25rem;
-}
-
-.card .card-header[data-toggle="collapse"]::after {
-  position: absolute;
-  right: 0;
-  top: 0;
-  padding-right: 1.725rem;
-  line-height: 51px;
-  font-weight: 900;
-  content: '\f107';
-  font-family: 'Font Awesome 5 Free';
-  color: #d1d3e2;
-}
-
-.card .card-header[data-toggle="collapse"].collapsed {
-  border-radius: 0.35rem;
-}
-
-.card .card-header[data-toggle="collapse"].collapsed::after {
-  content: '\f105';
-}
-
-
-
-
-
-
-form.user .custom-checkbox.small label {
-  line-height: 1.5rem;
-}
-
-form.user .form-control-user {
-  font-size: 0.8rem;
-  border-radius: 10rem;
-  padding: 1.5rem 1rem;
-}
-
-form.user .btn-user {
-  font-size: 0.8rem;
-  border-radius: 10rem;
-  padding: 0.75rem 1rem;
-}
-
-
-
-
-.error {
-  color: #5a5c69;
-  font-size: 7rem;
-  position: relative;
-  line-height: 1;
-  width: 12.5rem;
-}
-
-@-webkit-keyframes noise-anim {
-  0% {
-    clip: rect(49px, 9999px, 40px, 0);
-  }
-  5% {
-    clip: rect(75px, 9999px, 72px, 0);
-  }
-  10% {
-    clip: rect(97px, 9999px, 93px, 0);
-  }
-  15% {
-    clip: rect(15px, 9999px, 9px, 0);
-  }
-  20% {
-    clip: rect(14px, 9999px, 92px, 0);
-  }
-  25% {
-    clip: rect(18px, 9999px, 94px, 0);
-  }
-  30% {
-    clip: rect(17px, 9999px, 20px, 0);
-  }
-  35% {
-    clip: rect(71px, 9999px, 59px, 0);
-  }
-  40% {
-    clip: rect(42px, 9999px, 84px, 0);
-  }
-  45% {
-    clip: rect(56px, 9999px, 25px, 0);
-  }
-  50% {
-    clip: rect(46px, 9999px, 14px, 0);
-  }
-  55% {
-    clip: rect(47px, 9999px, 1px, 0);
-  }
-  60% {
-    clip: rect(64px, 9999px, 58px, 0);
-  }
-  65% {
-    clip: rect(89px, 9999px, 92px, 0);
-  }
-  70% {
-    clip: rect(56px, 9999px, 39px, 0);
-  }
-  75% {
-    clip: rect(80px, 9999px, 71px, 0);
-  }
-  80% {
-    clip: rect(8px, 9999px, 13px, 0);
-  }
-  85% {
-    clip: rect(66px, 9999px, 68px, 0);
-  }
-  90% {
-    clip: rect(68px, 9999px, 4px, 0);
-  }
-  95% {
-    clip: rect(56px, 9999px, 14px, 0);
-  }
-  100% {
-    clip: rect(28px, 9999px, 53px, 0);
-  }
-}
-
-@keyframes noise-anim {
-  0% {
-    clip: rect(49px, 9999px, 40px, 0);
-  }
-  5% {
-    clip: rect(75px, 9999px, 72px, 0);
-  }
-  10% {
-    clip: rect(97px, 9999px, 93px, 0);
-  }
-  15% {
-    clip: rect(15px, 9999px, 9px, 0);
-  }
-  20% {
-    clip: rect(14px, 9999px, 92px, 0);
-  }
-  25% {
-    clip: rect(18px, 9999px, 94px, 0);
-  }
-  30% {
-    clip: rect(17px, 9999px, 20px, 0);
-  }
-  35% {
-    clip: rect(71px, 9999px, 59px, 0);
-  }
-  40% {
-    clip: rect(42px, 9999px, 84px, 0);
-  }
-  45% {
-    clip: rect(56px, 9999px, 25px, 0);
-  }
-  50% {
-    clip: rect(46px, 9999px, 14px, 0);
-  }
-  55% {
-    clip: rect(47px, 9999px, 1px, 0);
-  }
-  60% {
-    clip: rect(64px, 9999px, 58px, 0);
-  }
-  65% {
-    clip: rect(89px, 9999px, 92px, 0);
-  }
-  70% {
-    clip: rect(56px, 9999px, 39px, 0);
-  }
-  75% {
-    clip: rect(80px, 9999px, 71px, 0);
-  }
-  80% {
-    clip: rect(8px, 9999px, 13px, 0);
-  }
-  85% {
-    clip: rect(66px, 9999px, 68px, 0);
-  }
-  90% {
-    clip: rect(68px, 9999px, 4px, 0);
-  }
-  95% {
-    clip: rect(56px, 9999px, 14px, 0);
-  }
-  100% {
-    clip: rect(28px, 9999px, 53px, 0);
-  }
-}
-
-.error:after {
-  content: attr(data-text);
-  position: absolute;
-  left: 2px;
-  text-shadow: -1px 0 #e74a3b;
-  top: 0;
-  color: #5a5c69;
-  background: #f8f9fc;
-  overflow: hidden;
-  clip: rect(0, 900px, 0, 0);
-  animation: noise-anim 2s infinite linear alternate-reverse;
-}
-
-@-webkit-keyframes noise-anim-2 {
-  0% {
-    clip: rect(16px, 9999px, 10px, 0);
-  }
-  5% {
-    clip: rect(22px, 9999px, 29px, 0);
-  }
-  10% {
-    clip: rect(6px, 9999px, 68px, 0);
-  }
-  15% {
-    clip: rect(85px, 9999px, 95px, 0);
-  }
-  20% {
-    clip: rect(65px, 9999px, 91px, 0);
-  }
-  25% {
-    clip: rect(93px, 9999px, 68px, 0);
-  }
-  30% {
-    clip: rect(10px, 9999px, 27px, 0);
-  }
-  35% {
-    clip: rect(37px, 9999px, 25px, 0);
-  }
-  40% {
-    clip: rect(12px, 9999px, 23px, 0);
-  }
-  45% {
-    clip: rect(40px, 9999px, 18px, 0);
-  }
-  50% {
-    clip: rect(19px, 9999px, 71px, 0);
-  }
-  55% {
-    clip: rect(2px, 9999px, 35px, 0);
-  }
-  60% {
-    clip: rect(16px, 9999px, 69px, 0);
-  }
-  65% {
-    clip: rect(8px, 9999px, 65px, 0);
-  }
-  70% {
-    clip: rect(30px, 9999px, 57px, 0);
-  }
-  75% {
-    clip: rect(14px, 9999px, 4px, 0);
-  }
-  80% {
-    clip: rect(39px, 9999px, 30px, 0);
-  }
-  85% {
-    clip: rect(22px, 9999px, 35px, 0);
-  }
-  90% {
-    clip: rect(58px, 9999px, 71px, 0);
-  }
-  95% {
-    clip: rect(34px, 9999px, 90px, 0);
-  }
-  100% {
-    clip: rect(67px, 9999px, 68px, 0);
-  }
-}
-
-@keyframes noise-anim-2 {
-  0% {
-    clip: rect(16px, 9999px, 10px, 0);
-  }
-  5% {
-    clip: rect(22px, 9999px, 29px, 0);
-  }
-  10% {
-    clip: rect(6px, 9999px, 68px, 0);
-  }
-  15% {
-    clip: rect(85px, 9999px, 95px, 0);
-  }
-  20% {
-    clip: rect(65px, 9999px, 91px, 0);
-  }
-  25% {
-    clip: rect(93px, 9999px, 68px, 0);
-  }
-  30% {
-    clip: rect(10px, 9999px, 27px, 0);
-  }
-  35% {
-    clip: rect(37px, 9999px, 25px, 0);
-  }
-  40% {
-    clip: rect(12px, 9999px, 23px, 0);
-  }
-  45% {
-    clip: rect(40px, 9999px, 18px, 0);
-  }
-  50% {
-    clip: rect(19px, 9999px, 71px, 0);
-  }
-  55% {
-    clip: rect(2px, 9999px, 35px, 0);
-  }
-  60% {
-    clip: rect(16px, 9999px, 69px, 0);
-  }
-  65% {
-    clip: rect(8px, 9999px, 65px, 0);
-  }
-  70% {
-    clip: rect(30px, 9999px, 57px, 0);
-  }
-  75% {
-    clip: rect(14px, 9999px, 4px, 0);
-  }
-  80% {
-    clip: rect(39px, 9999px, 30px, 0);
-  }
-  85% {
-    clip: rect(22px, 9999px, 35px, 0);
-  }
-  90% {
-    clip: rect(58px, 9999px, 71px, 0);
-  }
-  95% {
-    clip: rect(34px, 9999px, 90px, 0);
-  }
-  100% {
-    clip: rect(67px, 9999px, 68px, 0);
-  }
-}
-
-.error:before {
-  content: attr(data-text);
-  position: absolute;
-  left: -2px;
-  text-shadow: 1px 0 #4e73df;
-  top: 0;
-  color: #5a5c69;
-  background: #f8f9fc;
-  overflow: hidden;
-  clip: rect(0, 900px, 0, 0);
-  animation: noise-anim-2 3s infinite linear alternate-reverse;
-}
-
-
-
-body.sidebar-toggled footer.sticky-footer {
-  width: 100%;
-}
diff --git a/ganga/GangaGUI/gui/static/img/logo.svg b/ganga/GangaGUI/gui/static/img/logo.svg
deleted file mode 100644
index 12ad2a85cd..0000000000
--- a/ganga/GangaGUI/gui/static/img/logo.svg
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="120.70686mm" height="27.75136mm" viewBox="0 0 427.70143 98.33159" id="svg2" version="1.1" inkscape:version="0.91 r13725" sodipodi:docname="logo.svg">
-  <defs id="defs4"/>
-  <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="2.8" inkscape:cx="227.89043" inkscape:cy="23.488232" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" fit-margin-top="0.5" fit-margin-left="0.5" fit-margin-right="0.5" fit-margin-bottom="0.5" inkscape:window-width="1920" inkscape:window-height="1125" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1"/>
-  <metadata id="metadata7">
-    <rdf:RDF>
-      <cc:Work rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
-        <dc:title/>
-        <dc:creator>
-          <cc:Agent>
-            <dc:title>Matt Williams</dc:title>
-          </cc:Agent>
-        </dc:creator>
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-188.32753,-646.76197)">
-    <g id="g4471">
-      <path style="fill:#fece40;fill-opacity:1" d="m 197.00001,741.90717 c -3.34914,-1.57938 -5.30518,-3.44249 -6.26003,-5.96261 -0.42921,-1.13281 -0.63997,-14.4308 -0.63997,-40.3798 0,-42.0524 -0.14566,-40.18477 3.39643,-43.54931 3.66816,-3.48428 3.64413,-3.48183 34.10357,-3.48183 30.45943,0 30.43541,-0.002 34.10357,3.48183 3.54209,3.36454 3.39643,1.49691 3.39643,43.54931 0,25.949 -0.21076,39.24699 -0.63997,40.3798 -0.95485,2.52012 -2.91088,4.38323 -6.26003,5.96261 l -3,1.41473 -27.6,0 -27.6,0 -3,-1.41473 z m 36.00106,-64.21907 c 3.36148,-2.20253 4.52778,-8.04415 2.34894,-11.76511 -1.88188,-3.21382 -4.03038,-4.44651 -7.75,-4.44651 -3.71962,0 -5.86812,1.23269 -7.75,4.44651 -2.18743,3.73563 -1.01166,9.56316 2.37752,11.78383 3.15163,2.06504 7.60513,2.0573 10.77354,-0.0187 z m 67.54405,56.62862 c -9.64246,-2.02059 -16.58327,-5.97497 -19.63876,-11.18878 -3.00228,-5.123 -1.72177,-11.48584 3.17714,-15.78714 3.09595,-2.71828 9.83852,-5.7948 15.10574,-6.89247 6.34895,-1.32311 17.21808,-1.19224 23.36461,0.28134 8.68327,2.08173 15.16884,6.19306 17.55937,11.13124 1.04325,2.15505 1.27189,3.49011 1.07171,6.2576 -0.19114,2.6425 -0.6938,4.15395 -2.0197,6.07306 -2.31282,3.34757 -7.69356,6.77205 -13.71817,8.73069 -4.14381,1.34718 -6.1093,1.60302 -13.54705,1.7633 -4.785,0.10312 -9.8947,-0.0629 -11.35489,-0.36884 z m 18.22051,-6.85771 c 2.51414,-0.48104 6.18608,-1.59934 8.15986,-2.48511 3.98128,-1.7867 7.77452,-5.49893 7.77452,-7.6085 0,-1.49162 -1.37353,-3.74139 -3.28154,-5.375 -2.20593,-1.88867 -7.14339,-3.9325 -11.84316,-4.90238 -8.98035,-1.85327 -19.30209,-0.80249 -26.71404,2.71956 -3.94922,1.87661 -6.76126,4.81392 -6.76126,7.06247 0,2.14885 1.56239,4.54686 4.02362,6.17563 2.82839,1.87174 8.49203,3.97942 12.48803,4.64731 4.79314,0.80114 11.23126,0.70789 16.15397,-0.23398 z m 184.83438,6.5462 c -2.31,-0.49664 -6.40722,-1.97895 -9.10493,-3.29402 -9.28462,-4.52602 -13.00643,-11.41646 -9.87246,-18.27757 1.26384,-2.76691 5.51026,-6.88019 8.875,-8.59675 1.2743,-0.6501 4.33865,-1.81678 6.80965,-2.59263 3.95668,-1.24231 5.67398,-1.41062 14.39274,-1.41062 8.71876,0 10.43606,0.16831 14.39274,1.41062 5.93013,1.86194 8.562,3.25629 11.85748,6.282 3.19362,2.9322 4.92343,6.34281 4.92343,9.70738 0,6.89787 -6.95889,13.26279 -17.77684,16.25954 -5.01263,1.38857 -19.05465,1.68209 -24.49681,0.51205 z m 22.64761,-7.18519 c 7.57925,-1.93074 13.62284,-6.89784 12.74076,-10.47138 -0.8182,-3.31477 -5.53799,-6.64547 -12.28837,-8.67177 -1.815,-0.54482 -5.865,-1.14893 -9,-1.34247 -9.54689,-0.58937 -18.32033,1.42422 -23.52661,5.39958 -1.36831,1.0448 -2.82952,2.73834 -3.24715,3.76341 -0.64545,1.58429 -0.60687,2.16914 0.25722,3.9 1.81209,3.62979 8.11806,6.89393 16.13094,8.34981 4.18432,0.76026 14.24264,0.26769 18.93321,-0.92718 z M 300.20951,693.73796 c -5.30544,-1.13672 -11.86533,-4.1979 -15.16373,-7.07619 -3.72999,-3.2549 -5.62921,-6.84609 -5.98863,-11.32378 -0.23969,-2.98598 -0.0356,-4.36451 1.00408,-6.78125 1.62611,-3.77999 5.85507,-7.98345 10.44971,-10.38671 4.16953,-2.1809 7.24119,-2.40754 8.20564,-0.60546 1.31275,2.45291 0.49152,3.73509 -3.91657,6.11485 -2.31,1.24708 -5.05963,3.18599 -6.11029,4.30867 -1.05067,1.12269 -2.23377,3.12091 -2.62913,4.44051 -0.63985,2.13561 -0.56969,2.70733 0.63845,5.20302 1.75919,3.634 5.55038,6.37701 11.70097,8.46593 4.03688,1.37105 5.84929,1.63511 11.4,1.66097 7.04312,0.0328 11.27252,-0.87036 16.47437,-3.51805 3.55912,-1.81155 7.08284,-5.394 7.77645,-7.90604 0.75116,-2.72046 -0.19182,-5.82838 -2.54467,-8.38689 -1.04838,-1.14003 -3.93115,-3.07378 -6.40615,-4.29724 -3.8491,-1.9027 -4.5282,-2.47024 -4.69498,-3.92363 -0.11518,-1.00387 0.22977,-2.1685 0.843,-2.84611 0.93518,-1.03336 1.94051,-1.14694 10.15198,-1.14694 8.06752,0 9.22804,0.12599 10.10701,1.09724 0.54615,0.60349 0.99299,1.54849 0.99299,2.1 0,1.59409 -2.23243,3.40276 -4.2,3.40276 -0.99,0 -1.8,0.12711 -1.8,0.28246 0,0.15535 0.80192,1.43785 1.78204,2.85 2.27381,3.27609 3.30871,7.23731 2.79163,10.68541 -1.60811,10.72366 -14.97229,18.63901 -31.27367,18.5228 -2.97,-0.0212 -7.28573,-0.44252 -9.5905,-0.93633 z m 204.6414,0.0998 c -5.48925,-1.14448 -12.21166,-4.39805 -15.66607,-7.58221 -3.94563,-3.63696 -5.68812,-7.33967 -5.67165,-12.05202 0.0166,-4.72891 1.43893,-7.99347 4.9841,-11.43897 3.25369,-3.16222 9.21221,-6.43097 11.72287,-6.43097 1.30371,0 2.13753,0.43549 2.81578,1.47062 1.51714,2.31545 0.61059,3.74812 -3.7024,5.85104 -4.13891,2.01806 -8.34558,6.02214 -8.97923,8.54682 -0.64405,2.5661 0.30209,5.67979 2.44747,8.05447 3.78728,4.19207 10.52414,6.85684 19.22417,7.60415 5.11811,0.43963 12.7689,-0.84161 17.23502,-2.88627 3.70628,-1.69679 7.32664,-4.6963 8.56969,-7.1001 1.24642,-2.41031 1.06841,-5.30177 -0.48429,-7.86648 -1.61443,-2.66668 -4.4474,-4.88545 -8.64555,-6.77118 -3.64129,-1.6356 -4.78751,-3.24894 -3.7321,-5.25307 0.39102,-0.7425 1.00801,-1.54837 1.37111,-1.79081 0.3631,-0.24245 4.77146,-0.44495 9.79635,-0.45 8.94883,-0.009 9.15523,0.0199 10.06594,1.40982 0.68623,1.04733 0.78048,1.8117 0.35979,2.91817 -0.61831,1.62629 -1.74659,2.26282 -4.01097,2.26282 -0.79801,0 -1.44602,0.2025 -1.44001,0.45 0.006,0.2475 0.79594,1.60825 1.7554,3.02389 2.31663,3.41804 3.22182,7.70929 2.39986,11.37702 -0.79575,3.5508 -2.29605,5.98095 -5.52015,8.94142 -3.58472,3.2916 -6.04022,4.68039 -11.54603,6.53025 -3.88793,1.30629 -6.1681,1.65395 -12,1.82969 -4.75306,0.14322 -8.61008,-0.077 -11.3491,-0.6481 z m -157.28338,-1.16954 c -0.83255,-1.27063 -0.86789,-2.07399 -0.26588,-6.04544 1.40223,-9.2506 4.95265,-16.63329 10.85015,-22.56167 2.66992,-2.6839 5.29737,-4.62241 8.1,-5.97613 3.72522,-1.79933 4.79062,-2.02741 10.44821,-2.2367 5.29976,-0.19607 6.91556,-0.0253 10.1771,1.07531 5.31141,1.79242 8.70452,3.89161 12.62126,7.80836 5.42815,5.42815 9.31836,14.04067 10.50983,23.26767 0.51482,3.98692 -0.63606,6.13397 -3.288,6.13397 -2.19448,0 -3.62019,-1.89328 -3.62019,-4.80745 0,-1.17723 -0.41672,-3.74034 -0.92605,-5.69578 -2.28019,-8.75424 -7.65723,-15.94998 -14.37395,-19.2357 -3.15877,-1.54523 -4.22507,-1.75568 -8.7,-1.71707 -7.2865,0.0629 -11.1273,1.67079 -16.24556,6.80113 -2.3939,2.39954 -4.57523,5.29424 -5.54664,7.36061 -1.73569,3.69209 -3.38475,9.90751 -3.39893,12.81075 -0.0128,2.61877 -1.52215,4.48351 -3.62906,4.48351 -1.19582,0 -2.057,-0.46527 -2.71229,-1.46537 z m 68.47534,0.52251 c -1.28729,-1.28729 -1.19779,-5.05655 0.25669,-10.81116 1.78204,-7.05058 4.89173,-12.88422 9.43585,-17.70122 2.90407,-3.07847 5.08937,-4.73395 8.42553,-6.38276 4.07347,-2.01322 5.06275,-2.24865 10.33953,-2.4606 6.33764,-0.25455 10.45918,0.59378 15.64021,3.21921 3.75286,1.90172 8.9599,6.7535 11.74844,10.94689 3.16049,4.75274 5.6439,12.00679 6.04887,17.66884 0.375,5.24281 -0.16682,6.46366 -2.86859,6.46366 -2.1192,0 -3.56632,-1.41197 -3.57981,-3.49286 -0.006,-0.88392 -0.39639,-3.42848 -0.86812,-5.65457 -1.94815,-9.19312 -7.84434,-17.37588 -14.85224,-20.61201 -3.23971,-1.49604 -4.48567,-1.73812 -8.86922,-1.72321 -4.277,0.0146 -5.67418,0.28344 -8.65808,1.66628 -4.67314,2.1657 -8.12458,5.05598 -10.68725,8.94962 -2.74907,4.17686 -4.53913,9.14811 -5.32139,14.77826 -0.35065,2.52367 -0.91714,4.92599 -1.25887,5.33849 -0.86995,1.05008 -3.80333,0.93536 -4.93155,-0.19286 z m 136.11246,-0.54111 c -0.7462,-1.13886 -0.87726,-2.22029 -0.56351,-4.65 0.72095,-5.58321 2.15211,-10.25106 4.57093,-14.90852 2.81622,-5.42264 7.17876,-10.489 11.32026,-13.1466 8.28147,-5.3142 20.04803,-5.61459 29.03271,-0.74116 4.27673,2.31976 8.916,6.75908 11.74552,11.23932 3.08453,4.884 5.45726,11.91184 5.87168,17.39142 0.26469,3.49989 0.14026,4.44062 -0.69827,5.27915 -1.33431,1.33431 -3.49626,1.29926 -4.74165,-0.0769 -0.54615,-0.60349 -0.99698,-2.02099 -1.00186,-3.15 -0.0155,-3.60032 -1.74992,-9.59885 -4.02971,-13.93731 -4.26612,-8.11844 -10.91756,-12.91496 -18.67962,-13.47033 -9.24309,-0.66134 -17.38599,4.01747 -22.72045,13.05488 -1.76853,2.99617 -3.0833,7.22617 -3.85158,12.39176 -0.36638,2.4634 -1.05525,4.86801 -1.53082,5.34357 -1.35175,1.35175 -3.62765,1.05336 -4.72363,-0.6193 z M 306.68048,680.91791 c -1.82343,-0.92603 -2.87945,-2.02302 -3.82224,-3.97056 -2.03802,-4.21001 -0.92683,-8.14115 3.16466,-11.19589 1.06597,-0.79586 2.52391,-1.1563 4.67711,-1.1563 3.3589,0 5.24162,0.99433 7.42831,3.92317 1.64497,2.20326 1.64497,7.02732 0,9.23058 -3.09497,4.14538 -7.25675,5.29744 -11.44784,3.169 z m 59.097,0.5275 c -2.07855,-0.76027 -2.64957,-2.55453 -1.4134,-4.44117 l 0.9636,-1.47062 12.79317,0 c 11.84779,0 12.87012,0.085 13.83438,1.15052 0.57267,0.63279 0.95201,1.77353 0.843,2.53498 -0.35823,2.50208 -2.34761,2.89976 -14.29822,2.85829 -6.105,-0.0212 -11.83014,-0.30559 -12.72253,-0.632 z m 145.33248,-0.42265 c -2.83645,-1.52121 -4.28581,-3.65439 -4.64439,-6.83566 -0.59339,-5.26457 3.26037,-9.65692 8.46707,-9.65038 5.15896,0.006 8.76099,3.56454 8.76513,8.65817 0.003,3.38061 -1.83394,6.39271 -4.80972,7.8878 -2.68788,1.35043 -5.18417,1.3312 -7.77809,-0.0599 z m 58.79005,0.337 c -1.84509,-0.93014 -2.24856,-3.136 -0.85522,-4.67562 0.96426,-1.0655 1.98659,-1.15052 13.83438,-1.15052 l 12.79317,0 0.9636,1.47062 c 1.28192,1.95647 0.64769,3.67826 -1.64998,4.47923 -2.7087,0.94426 -23.16759,0.84336 -25.08595,-0.12371 z" id="path4463" inkscape:connector-curvature="0"/>
-      <path style="fill:#0072bc;fill-opacity:1" d="m 197.00001,741.90717 c -3.34914,-1.57938 -5.30518,-3.44249 -6.26003,-5.96261 -0.42921,-1.13281 -0.63997,-14.4308 -0.63997,-40.3798 0,-42.0524 -0.14566,-40.18477 3.39643,-43.54931 3.66816,-3.48428 3.64413,-3.48183 34.10357,-3.48183 30.45943,0 30.43541,-0.002 34.10357,3.48183 3.54209,3.36454 3.39643,1.49691 3.39643,43.54931 0,25.949 -0.21076,39.24699 -0.63997,40.3798 -0.95485,2.52012 -2.91088,4.38323 -6.26003,5.96261 l -3,1.41473 -27.6,0 -27.6,0 -3,-1.41473 z m 39.9,-9.63189 c 15.35668,-2.78627 24.1426,-11.51084 20.69161,-20.54712 -3.10886,-8.14045 -14.93585,-13.44069 -29.99161,-13.44069 -15.05576,0 -26.88275,5.30024 -29.99162,13.44069 -3.41729,8.94806 5.2951,17.71416 20.39162,20.5173 5.53938,1.02856 13.3277,1.04085 18.9,0.0298 z m -18,-6.0374 c -4.89951,-0.98364 -8.58325,-2.4247 -11.84922,-4.63534 -3.08463,-2.0879 -4.57312,-4.69073 -4.04849,-7.07934 0.20812,-0.94756 1.46193,-2.70175 2.78625,-3.8982 4.60189,-4.15753 11.9518,-6.27054 21.81146,-6.27054 9.85966,0 17.20957,2.11301 21.81146,6.27054 2.85652,2.5807 3.54587,4.88384 2.22581,7.43654 -1.07666,2.08203 -4.8102,4.7851 -8.73727,6.32574 -6.67944,2.62044 -16.42316,3.37176 -24,1.8506 z m 16.72115,-34.17584 c 10.02855,-2.6692 17.98085,-10.12494 21.45523,-20.11551 1.59354,-4.58224 1.98439,-9.71427 0.84443,-11.08784 -1.13172,-1.36364 -3.45858,-1.14072 -4.43554,0.42493 -0.46332,0.7425 -0.9993,2.78834 -1.19105,4.54631 -0.49008,4.49285 -2.80249,9.14985 -6.46756,13.02512 -5.56352,5.88261 -14.97743,9.06201 -22.62226,7.6403 -5.28778,-0.98336 -9.84425,-3.47082 -13.63211,-7.44199 -3.73968,-3.92067 -6.19052,-8.82609 -6.6851,-13.38041 -0.18153,-1.67163 -0.70914,-3.64683 -1.17246,-4.38933 -0.97696,-1.56565 -3.30382,-1.78857 -4.43554,-0.42493 -1.07186,1.29152 -0.78692,6.07599 0.63629,10.68381 3.07099,9.9427 11.79269,17.82848 22.61961,20.45166 4.5597,1.10474 11.08021,1.13408 15.08606,0.0679 z m -2.62009,-14.37394 c 3.36148,-2.20253 4.52778,-8.04415 2.34894,-11.76511 -1.88188,-3.21382 -4.03038,-4.44651 -7.75,-4.44651 -3.71962,0 -5.86812,1.23269 -7.75,4.44651 -2.18743,3.73563 -1.01166,9.56316 2.37752,11.78383 3.15163,2.06504 7.60513,2.0573 10.77354,-0.0187 z m 67.54405,56.62862 c -9.64246,-2.02059 -16.58327,-5.97497 -19.63876,-11.18878 -3.00228,-5.123 -1.72177,-11.48584 3.17714,-15.78714 3.09595,-2.71828 9.83852,-5.7948 15.10574,-6.89247 6.34895,-1.32311 17.21808,-1.19224 23.36461,0.28134 8.68327,2.08173 15.16884,6.19306 17.55937,11.13124 1.04325,2.15505 1.27189,3.49011 1.07171,6.2576 -0.19114,2.6425 -0.6938,4.15395 -2.0197,6.07306 -2.31282,3.34757 -7.69356,6.77205 -13.71817,8.73069 -4.14381,1.34718 -6.1093,1.60302 -13.54705,1.7633 -4.785,0.10312 -9.8947,-0.0629 -11.35489,-0.36884 z m 18.22051,-6.85771 c 2.51414,-0.48104 6.18608,-1.59934 8.15986,-2.48511 3.98128,-1.7867 7.77452,-5.49893 7.77452,-7.6085 0,-1.49162 -1.37353,-3.74139 -3.28154,-5.375 -2.20593,-1.88867 -7.14339,-3.9325 -11.84316,-4.90238 -8.98035,-1.85327 -19.30209,-0.80249 -26.71404,2.71956 -3.94922,1.87661 -6.76126,4.81392 -6.76126,7.06247 0,2.14885 1.56239,4.54686 4.02362,6.17563 2.82839,1.87174 8.49203,3.97942 12.48803,4.64731 4.79314,0.80114 11.23126,0.70789 16.15397,-0.23398 z m 184.83438,6.5462 c -2.31,-0.49664 -6.40722,-1.97895 -9.10493,-3.29402 -9.28462,-4.52602 -13.00643,-11.41646 -9.87246,-18.27757 1.26384,-2.76691 5.51026,-6.88019 8.875,-8.59675 1.2743,-0.6501 4.33865,-1.81678 6.80965,-2.59263 3.95668,-1.24231 5.67398,-1.41062 14.39274,-1.41062 8.71876,0 10.43606,0.16831 14.39274,1.41062 5.93013,1.86194 8.562,3.25629 11.85748,6.282 3.19362,2.9322 4.92343,6.34281 4.92343,9.70738 0,6.89787 -6.95889,13.26279 -17.77684,16.25954 -5.01263,1.38857 -19.05465,1.68209 -24.49681,0.51205 z m 22.64761,-7.18519 c 7.57925,-1.93074 13.62284,-6.89784 12.74076,-10.47138 -0.8182,-3.31477 -5.53799,-6.64547 -12.28837,-8.67177 -1.815,-0.54482 -5.865,-1.14893 -9,-1.34247 -9.54689,-0.58937 -18.32033,1.42422 -23.52661,5.39958 -1.36831,1.0448 -2.82952,2.73834 -3.24715,3.76341 -0.64545,1.58429 -0.60687,2.16914 0.25722,3.9 1.81209,3.62979 8.11806,6.89393 16.13094,8.34981 4.18432,0.76026 14.24264,0.26769 18.93321,-0.92718 z M 300.20951,693.73796 c -5.30544,-1.13672 -11.86533,-4.1979 -15.16373,-7.07619 -3.72999,-3.2549 -5.62921,-6.84609 -5.98863,-11.32378 -0.23969,-2.98598 -0.0356,-4.36451 1.00408,-6.78125 1.62611,-3.77999 5.85507,-7.98345 10.44971,-10.38671 4.16953,-2.1809 7.24119,-2.40754 8.20564,-0.60546 1.31275,2.45291 0.49152,3.73509 -3.91657,6.11485 -2.31,1.24708 -5.05963,3.18599 -6.11029,4.30867 -1.05067,1.12269 -2.23377,3.12091 -2.62913,4.44051 -0.63985,2.13561 -0.56969,2.70733 0.63845,5.20302 1.75919,3.634 5.55038,6.37701 11.70097,8.46593 4.03688,1.37105 5.84929,1.63511 11.4,1.66097 7.04312,0.0328 11.27252,-0.87036 16.47437,-3.51805 3.55912,-1.81155 7.08284,-5.394 7.77645,-7.90604 0.75116,-2.72046 -0.19182,-5.82838 -2.54467,-8.38689 -1.04838,-1.14003 -3.93115,-3.07378 -6.40615,-4.29724 -3.8491,-1.9027 -4.5282,-2.47024 -4.69498,-3.92363 -0.11518,-1.00387 0.22977,-2.1685 0.843,-2.84611 0.93518,-1.03336 1.94051,-1.14694 10.15198,-1.14694 8.06752,0 9.22804,0.12599 10.10701,1.09724 0.54615,0.60349 0.99299,1.54849 0.99299,2.1 0,1.59409 -2.23243,3.40276 -4.2,3.40276 -0.99,0 -1.8,0.12711 -1.8,0.28246 0,0.15535 0.80192,1.43785 1.78204,2.85 2.27381,3.27609 3.30871,7.23731 2.79163,10.68541 -1.60811,10.72366 -14.97229,18.63901 -31.27367,18.5228 -2.97,-0.0212 -7.28573,-0.44252 -9.5905,-0.93633 z m 204.6414,0.0998 c -5.48925,-1.14448 -12.21166,-4.39805 -15.66607,-7.58221 -3.94563,-3.63696 -5.68812,-7.33967 -5.67165,-12.05202 0.0166,-4.72891 1.43893,-7.99347 4.9841,-11.43897 3.25369,-3.16222 9.21221,-6.43097 11.72287,-6.43097 1.30371,0 2.13753,0.43549 2.81578,1.47062 1.51714,2.31545 0.61059,3.74812 -3.7024,5.85104 -4.13891,2.01806 -8.34558,6.02214 -8.97923,8.54682 -0.64405,2.5661 0.30209,5.67979 2.44747,8.05447 3.78728,4.19207 10.52414,6.85684 19.22417,7.60415 5.11811,0.43963 12.7689,-0.84161 17.23502,-2.88627 3.70628,-1.69679 7.32664,-4.6963 8.56969,-7.1001 1.24642,-2.41031 1.06841,-5.30177 -0.48429,-7.86648 -1.61443,-2.66668 -4.4474,-4.88545 -8.64555,-6.77118 -3.64129,-1.6356 -4.78751,-3.24894 -3.7321,-5.25307 0.39102,-0.7425 1.00801,-1.54837 1.37111,-1.79081 0.3631,-0.24245 4.77146,-0.44495 9.79635,-0.45 8.94883,-0.009 9.15523,0.0199 10.06594,1.40982 0.68623,1.04733 0.78048,1.8117 0.35979,2.91817 -0.61831,1.62629 -1.74659,2.26282 -4.01097,2.26282 -0.79801,0 -1.44602,0.2025 -1.44001,0.45 0.006,0.2475 0.79594,1.60825 1.7554,3.02389 2.31663,3.41804 3.22182,7.70929 2.39986,11.37702 -0.79575,3.5508 -2.29605,5.98095 -5.52015,8.94142 -3.58472,3.2916 -6.04022,4.68039 -11.54603,6.53025 -3.88793,1.30629 -6.1681,1.65395 -12,1.82969 -4.75306,0.14322 -8.61008,-0.077 -11.3491,-0.6481 z m -157.28338,-1.16954 c -0.83255,-1.27063 -0.86789,-2.07399 -0.26588,-6.04544 1.40223,-9.2506 4.95265,-16.63329 10.85015,-22.56167 2.66992,-2.6839 5.29737,-4.62241 8.1,-5.97613 3.72522,-1.79933 4.79062,-2.02741 10.44821,-2.2367 5.29976,-0.19607 6.91556,-0.0253 10.1771,1.07531 5.31141,1.79242 8.70452,3.89161 12.62126,7.80836 5.42815,5.42815 9.31836,14.04067 10.50983,23.26767 0.51482,3.98692 -0.63606,6.13397 -3.288,6.13397 -2.19448,0 -3.62019,-1.89328 -3.62019,-4.80745 0,-1.17723 -0.41672,-3.74034 -0.92605,-5.69578 -2.28019,-8.75424 -7.65723,-15.94998 -14.37395,-19.2357 -3.15877,-1.54523 -4.22507,-1.75568 -8.7,-1.71707 -7.2865,0.0629 -11.1273,1.67079 -16.24556,6.80113 -2.3939,2.39954 -4.57523,5.29424 -5.54664,7.36061 -1.73569,3.69209 -3.38475,9.90751 -3.39893,12.81075 -0.0128,2.61877 -1.52215,4.48351 -3.62906,4.48351 -1.19582,0 -2.057,-0.46527 -2.71229,-1.46537 z m 68.47534,0.52251 c -1.28729,-1.28729 -1.19779,-5.05655 0.25669,-10.81116 1.78204,-7.05058 4.89173,-12.88422 9.43585,-17.70122 2.90407,-3.07847 5.08937,-4.73395 8.42553,-6.38276 4.07347,-2.01322 5.06275,-2.24865 10.33953,-2.4606 6.33764,-0.25455 10.45918,0.59378 15.64021,3.21921 3.75286,1.90172 8.9599,6.7535 11.74844,10.94689 3.16049,4.75274 5.6439,12.00679 6.04887,17.66884 0.375,5.24281 -0.16682,6.46366 -2.86859,6.46366 -2.1192,0 -3.56632,-1.41197 -3.57981,-3.49286 -0.006,-0.88392 -0.39639,-3.42848 -0.86812,-5.65457 -1.94815,-9.19312 -7.84434,-17.37588 -14.85224,-20.61201 -3.23971,-1.49604 -4.48567,-1.73812 -8.86922,-1.72321 -4.277,0.0146 -5.67418,0.28344 -8.65808,1.66628 -4.67314,2.1657 -8.12458,5.05598 -10.68725,8.94962 -2.74907,4.17686 -4.53913,9.14811 -5.32139,14.77826 -0.35065,2.52367 -0.91714,4.92599 -1.25887,5.33849 -0.86995,1.05008 -3.80333,0.93536 -4.93155,-0.19286 z m 136.11246,-0.54111 c -0.7462,-1.13886 -0.87726,-2.22029 -0.56351,-4.65 0.72095,-5.58321 2.15211,-10.25106 4.57093,-14.90852 2.81622,-5.42264 7.17876,-10.489 11.32026,-13.1466 8.28147,-5.3142 20.04803,-5.61459 29.03271,-0.74116 4.27673,2.31976 8.916,6.75908 11.74552,11.23932 3.08453,4.884 5.45726,11.91184 5.87168,17.39142 0.26469,3.49989 0.14026,4.44062 -0.69827,5.27915 -1.33431,1.33431 -3.49626,1.29926 -4.74165,-0.0769 -0.54615,-0.60349 -0.99698,-2.02099 -1.00186,-3.15 -0.0155,-3.60032 -1.74992,-9.59885 -4.02971,-13.93731 -4.26612,-8.11844 -10.91756,-12.91496 -18.67962,-13.47033 -9.24309,-0.66134 -17.38599,4.01747 -22.72045,13.05488 -1.76853,2.99617 -3.0833,7.22617 -3.85158,12.39176 -0.36638,2.4634 -1.05525,4.86801 -1.53082,5.34357 -1.35175,1.35175 -3.62765,1.05336 -4.72363,-0.6193 z" id="path4461" inkscape:connector-curvature="0"/>
-    </g>
-  </g>
-</svg>
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/static/js/cli.js b/ganga/GangaGUI/gui/static/js/cli.js
deleted file mode 100644
index c0ac4a3671..0000000000
--- a/ganga/GangaGUI/gui/static/js/cli.js
+++ /dev/null
@@ -1,72 +0,0 @@
-
-// Apply XtermJS Addons
-Terminal.applyAddon(fullscreen)
-Terminal.applyAddon(fit)
-Terminal.applyAddon(webLinks)
-Terminal.applyAddon(search)
-
-// Create new xtermjs terminal
-const term = new Terminal({
-    cursorBlink: true,
-    macOptionIsMeta: true,
-    scrollback: true,
-});
-
-term.open(document.getElementById('terminal'));
-
-term.fit()
-term.resize(40, 50)
-
-// term.toggleFullScreen(true)
-term.fit()
-
-term.write("Welcome to Ganga CLI - Ganga GUI\n")
-
-term.on('key', (key, ev) => {
-    console.log("pressed key", key)
-    console.log("event", ev)
-    socket.emit("pty-input", {"input": key})
-});
-
-const socket = io.connect('/pty')
-
-const status = document.getElementById("status")
-const statusBar = document.querySelector(".status-bar")
-
-socket.on("pty-output", function (data) {
-    console.log("new output", data)
-    term.write(data.output)
-})
-
-socket.on("connect", () => {
-        fitToScreen()
-        status.innerHTML = 'Connected';
-        statusBar.className = "status-bar connected";
-    }
-)
-
-socket.on("disconnect", () => {
-    status.innerHTML = 'Disconnected';
-    statusBar.className = "status-bar disconnected";
-})
-
-function fitToScreen() {
-    term.fit()
-    socket.emit("resize", {"cols": term.cols, "rows": term.rows})
-}
-
-function debounce(func, wait_ms) {
-    let timeout
-    return function (...args) {
-        const context = this
-        clearTimeout(timeout)
-        timeout = setTimeout(() => func.apply(context, args), wait_ms)
-    }
-}
-
-const wait_ms = 50;
-window.onresize = debounce(fitToScreen, wait_ms)
-
-function clear() {
-    term.clear();
-}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/static/js/create.js b/ganga/GangaGUI/gui/static/js/create.js
deleted file mode 100644
index 95a1453da8..0000000000
--- a/ganga/GangaGUI/gui/static/js/create.js
+++ /dev/null
@@ -1,76 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Add event listener to update the loadfile label to the selected file
-    loadfileInput = document.querySelector('#loadfile-input');
-    loadfileInput.addEventListener('change', updateLoadfileFilename);
-
-    // Add event listener to update the runfile label to the selected file
-    runfileInput = document.querySelector('#runfile-input');
-    runfileInput.addEventListener('change', updateRunfileFilename);
-
-    // Add event listeners to create buttons
-    const btnCreateList = document.querySelectorAll('.btn-create');
-    Array.from(btnCreateList).map(btnCreate => btnCreate.addEventListener('click', createJobHandler));
-
-});
-
-function createJobHandler(e) {
-
-    // Get template id from the dataset of button
-    const templateId = e.target.dataset.id;
-
-    // Make ajax request to the server with template id in the body
-    fetch(`/api/jobs/create`, {
-        method: 'POST',
-        headers: {
-            'Content-Type': 'application/json',
-            'X-Access-Token': localStorage.getItem('token')
-        },
-        body: JSON.stringify({
-            template_id: templateId
-        })
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            // Display server response
-            displayToast(data['message'], data['success'] ? 'success' : 'danger');
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, "danger");
-
-        })
-    ;
-
-}
-
-
-// For updating the loadfile label to the filename of selected file
-function updateLoadfileFilename(e) {
-
-    // loadfile Input
-    const loadfileInput = e.target;
-
-    // Label to be updated
-    const loadfileLabel = document.querySelector("#loadfile-input-label");
-
-    // Update label
-    loadfileLabel.innerHTML = loadfileInput.files[0].name;
-}
-
-
-// For updating the runfile label to the filename of selected file
-function updateRunfileFilename(e) {
-
-    // runfile Input
-    const runfileInput = e.target;
-
-    // Label to be update
-    const runfileLabel = document.querySelector("#runfile-input-label");
-
-    // Update label
-    runfileLabel.innerHTML = runfileInput.files[0].name;
-}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/static/js/credentials.js b/ganga/GangaGUI/gui/static/js/credentials.js
deleted file mode 100644
index bc0f43f480..0000000000
--- a/ganga/GangaGUI/gui/static/js/credentials.js
+++ /dev/null
@@ -1,34 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Add event listener to renew button
-    const btnRenew = document.querySelector('#btn-renew')
-    btnRenew.addEventListener('click', renewCredentials)
-
-});
-
-// Renew Credentials
-function renewCredentials() {
-
-    // Make ajax request to the server to renew credentials
-    fetch(`/api/credentials/renew`, {
-        method: 'PUT',
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            // Display server response
-            displayToast(data["message"], data["success"] ? "success" : "danger");
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, "danger")
-
-        })
-    ;
-
-}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/static/js/dashboard.js b/ganga/GangaGUI/gui/static/js/dashboard.js
deleted file mode 100644
index d0c206dc42..0000000000
--- a/ganga/GangaGUI/gui/static/js/dashboard.js
+++ /dev/null
@@ -1,229 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Refresh initial stats and statuses
-    setTimeout(refreshStatistics, 0)
-    setTimeout(refreshRecentJobs, 0)
-    setTimeout(refreshPinnedJobs, 0)
-
-    // Add event listeners to copy button
-    const btnCopyList = document.querySelectorAll('.btn-copy')
-    Array.from(btnCopyList).map(btnCopy => btnCopy.addEventListener('click', copyHandler))
-
-    // Add event listeners to unpin button
-    const btnUnpinList = document.querySelectorAll('.btn-unpin')
-    Array.from(btnUnpinList).map(btnUnpin => btnUnpin.addEventListener('click', unpinHandler))
-
-});
-
-
-// Handles copy of the job
-function copyHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get job id from the copy button dataset
-    const jobId = e.target.dataset.id;
-
-    // Make ajax request to server
-    fetch(`/api/jobs/${jobId}/copy`, {
-        method: 'PUT',
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            // Display server response
-            displayToast(data['message'], data['success'] ? 'success' : 'danger');
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-    ;
-
-}
-
-
-// Handles unpin of the job
-function unpinHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get job id from the copy button dataset
-    const jobId = e.target.dataset.id;
-
-    // Make ajax request to server
-    fetch(`/api/jobs/${jobId}/unpin`, {
-        method: 'PUT',
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            // Display server response
-            displayToast(data['message'], data['success'] ? 'success' : 'danger');
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-    ;
-
-}
-
-
-// Refresh stat cards of dashboard
-function refreshStatistics() {
-
-    // Status category
-    const statuses = ['new', 'running', 'completed', 'failed', 'killed'];
-
-    // Get status card nodes
-    const statCards = statuses.map((stat) => document.querySelector(`#stat-${stat}`));
-
-    // Make ajax request to the server
-    fetch('/api/jobs/statistics', {
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If API response false, display error
-                displayToast(data['message'], 'danger');
-
-            } else {
-
-                // Update stats
-                for (let i = 0; i < statCards.length; i++) {
-                    statCards[i].innerHTML = data[statuses[i]];
-                }
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-
-    // Recursively refresh
-    const refreshInterval = Number(localStorage.getItem('refreshInterval')) || 5000;
-    setTimeout(refreshStatistics, refreshInterval);
-}
-
-
-// Refresh recent jobs of dashboard
-function refreshRecentJobs() {
-
-    // Get HTML nodes
-    let recentJobNodes = document.querySelectorAll('.recent-job');
-
-    // Extract job ids from the nodes
-    let jobIds = JSON.stringify(Array.from(recentJobNodes).map(node => node.dataset['id']));
-
-    // Make ajax request to the server
-    fetch(`/api/jobs?ids=${jobIds}`, {
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If API response false, display error
-                displayToast(data['message'], 'danger');
-
-            } else {
-
-                // Update status
-                for (let i = 0; i < data.length; i++) {
-                    document.querySelector(`#job-id-${data[i]['id']}-status`).innerHTML = data[i]['status'];
-                    document.querySelector(`#job-id-${data[i]['id']}-status`).className = `badge badge-${statusColor[data[i]['status']]} badge-pill`;
-                    document.querySelector(`#subjob-statuses-job-id-${data[i]['id']}`).innerHTML = 'subjobs statuses: ' + data[i]['subjob_statuses'];
-
-                }
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-
-    // Recursively refresh
-    let refreshInterval = Number(localStorage.getItem('refreshInterval')) || 5000;
-    setTimeout(refreshRecentJobs, refreshInterval);
-}
-
-
-// Refresh pinned jobs
-function refreshPinnedJobs() {
-
-    // Get HTML nodes
-    let pinnedJobNodes = document.querySelectorAll('.pinned-job');
-
-    // Extract job ids from the nodes
-    let jobIds = JSON.stringify(Array.from(pinnedJobNodes).map(node => node.dataset['id']));
-
-    // Make ajax request to the server
-    fetch(`/api/jobs?ids=${jobIds}`, {
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If API response false, display error
-                displayToast(data['message'], 'danger');
-
-            } else {
-
-                // Update status
-                for (let i = 0; i < data.length; i++) {
-                    document.querySelector(`#pinned-job-id-${data[i]['id']}-status`).innerHTML = data[i]['status'];
-                    document.querySelector(`#pinned-job-id-${data[i]['id']}-status`).className = `badge badge-${statusColor[data[i]['status']]} badge-pill`;
-                    document.querySelector(`#subjob-statuses-pinned-job-id-${data[i]['id']}`).innerHTML = 'subjobs statuses: ' + data[i]['subjob_statuses'];
-
-                }
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-
-    // Recursively refresh
-    let refreshInterval = Number(localStorage.getItem('refreshInterval')) || 5000;
-    setTimeout(refreshPinnedJobs, refreshInterval);
-}
-
diff --git a/ganga/GangaGUI/gui/static/js/job.js b/ganga/GangaGUI/gui/static/js/job.js
deleted file mode 100644
index 015b93a59e..0000000000
--- a/ganga/GangaGUI/gui/static/js/job.js
+++ /dev/null
@@ -1,375 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Refresh Job status
-    setTimeout(refreshJobStatus, 0);
-
-    // Add event listener to copy button
-    const btnCopy = document.querySelector('#btn-copy');
-    btnCopy.addEventListener('click', copyHandler);
-
-    // Add event listener to pin button
-    const btnPin =  document.querySelector('#btn-pin');
-    btnPin.addEventListener('click', pinHandler);
-
-    // Add event listener to submit button
-    const btnSubmit =  document.querySelector('#btn-submit');
-    btnSubmit.addEventListener('click', submitHandler);
-
-    // Add event listener to kill button
-    const btnKill =  document.querySelector('#btn-kill');
-    btnKill.addEventListener('click', killHandler);
-
-    // Add event listener to freeze button
-    const btnFreeze = document.querySelector('#btn-freeze');
-    btnFreeze.addEventListener('click', freezeHandler);
-
-    // Add event listener to unfreeze button
-    const btnUnFreeze = document.querySelector('#btn-unfreeze');
-    btnUnFreeze.addEventListener('click', unfreezeHandler);
-
-    // Add event listener to remove button
-    const btnRemove =  document.querySelector('#btn-remove');
-    btnRemove.addEventListener('click', removeHandler);
-
-    // Add event listener to display attribute information
-    const attributeSelect =  document.querySelector('#attribute-select');
-    attributeSelect.addEventListener('change', attributeSelectHandler);
-
-    // Add event listener to display attribute information
-    const btnExecute =  document.querySelector('#btn-execute');
-    btnExecute.addEventListener('click', executeHandler);
-
-});
-
-
-// Handles copying of the job
-function copyHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get job id from the copy button dataset
-    const jobId = e.target.dataset.id;
-
-    // Make ajax request to server
-    fetch(`/api/jobs/${jobId}/copy`, {
-        method: 'PUT',
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            // Display server response
-            displayToast(data['message'], data['success'] ? 'success' : 'danger');
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-    ;
-
-}
-
-
-// Handles pinning of the job
-function pinHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get job id from the copy button dataset
-    const jobId = e.target.dataset.id;
-
-    // Make ajax request to server
-    fetch(`/api/jobs/${jobId}/pin`, {
-        method: 'PUT',
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            // Display server response
-            displayToast(data['message'], data['success'] ? 'success' : 'danger');
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-    ;
-
-}
-
-
-// Handles submitting of the job
-function submitHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get job id from the copy button dataset
-    const jobId = e.target.dataset.id;
-
-    // Execute submit action
-    executeAction(jobId, 'submit');
-
-}
-
-
-// Handles killing of the job
-function killHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get job id from the copy button dataset
-    const jobId = e.target.dataset.id;
-
-    // Execute kill action
-    executeAction(jobId, 'kill');
-
-}
-
-// Handles freezing of the job
-function freezeHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get job id from the copy button dataset
-    const jobId = e.target.dataset.id;
-
-    // Execute freeze action
-    executeAction(jobId, 'freeze');
-
-}
-
-// Handles unfreezing of the job
-function unfreezeHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get job id from the copy button dataset
-    const jobId = e.target.dataset.id;
-
-    // Execute unfreeze action
-    executeAction(jobId, 'unfreeze');
-
-}
-
-
-// Handles removing of the job
-function removeHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get job id from the copy button dataset
-    const jobId = e.target.dataset.id;
-
-    // Make ajax request to server to remove the job
-    fetch(`/api/jobs/${jobId}`, {
-        method: "DELETE",
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If API response false, display error
-                displayToast(data['message'], 'danger');
-
-            } else {
-
-                // Display remove message
-                displayToast(data['message'], 'success');
-
-                console.log("Navigating 4...")
-
-                // Change page after 3 seconds
-                setTimeout(() => window.location.href = document.referrer, 2000)
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-    ;
-
-    // Execute remove action
-    // executeAction(jobId, 'remove');
-
-}
-
-
-// Handles displaying of attribute information of the job
-function attributeSelectHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get job id from the copy button dataset
-    const jobId = e.target.dataset.id;
-
-    // Get attribute to query
-    const attribute = e.target.value
-
-    // Make ajax request to server
-    fetch(`/api/jobs/${jobId}/${attribute}`, {
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If API response false, display error
-                displayToast(data['message'], 'danger');
-
-            } else {
-
-                // Display attribute info
-                const attributeInfoBox = document.querySelector('#attribute-info-box');
-                attributeInfoBox.innerHTML = data[attribute];
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-    ;
-
-}
-
-
-// Handles execution of action on the job
-function executeHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Job id
-    const jobId = e.target.dataset.id;
-
-    // Action to execute
-    const action = document.querySelector('#action-select').value;
-
-    // Action argument
-    const actionArgument = document.querySelector('#action-argument').value;
-
-    // Execute action
-    executeAction(jobId, action, actionArgument.trim());
-
-}
-
-
-// Execute action on the job
-function executeAction(jobId, action, argument='') {
-
-    const actionArgument = {};
-
-    // If action data is empty, don't add it to body
-    if (argument.length !== 0) {
-        actionArgument[action] = argument;
-    }
-
-    // Make ajax request to server
-    fetch(`/api/jobs/${jobId}/${action}`, {
-        method: 'PUT',
-        body: JSON.stringify(actionArgument),
-        headers: {
-            'Content-Type': 'application/json',
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            // Display server response
-            displayToast(data['message'],data['success'] ? 'success' : 'danger');
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-    ;
-
-}
-
-
-// Refresh job status
-function refreshJobStatus() {
-
-    // Job id
-    const jobId = document.querySelector('#job-info').dataset.job_id;
-
-    // Make request to server for job information
-    fetch(`/api/jobs/${jobId}`, {
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If server responds with failure, display message
-                displayToast(data['message'], 'danger');
-
-            } else {
-
-                // Get locations to update
-                document.querySelector(`#job-id-${data['id']}-status`).innerHTML = data['status'];
-                document.querySelector(`#job-id-${data['id']}-status`).className = `badge badge-${statusColor[data['status']]} badge-pill ml-2`;
-
-                // Get subjob status card nodes
-                const statCards = ['running', 'failed-killed', 'completing', 'completed'].map((stat) => document.querySelector(`#stat-${stat}`));
-                let subjobStatuses = data['subjob_statuses'].split('/')
-                for (let i = 0; i < statCards.length; i++) {
-                    statCards[i].innerHTML = subjobStatuses[i]
-                }
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error, if any
-            displayToast(err, 'danger');
-
-        });
-
-    // Recursively refresh
-    let refreshInterval = Number(localStorage.getItem('refreshInterval')) || 5000;
-    setTimeout(refreshJobStatus, refreshInterval);
-
-}
-
-
diff --git a/ganga/GangaGUI/gui/static/js/jobs.js b/ganga/GangaGUI/gui/static/js/jobs.js
deleted file mode 100644
index 8f463b0551..0000000000
--- a/ganga/GangaGUI/gui/static/js/jobs.js
+++ /dev/null
@@ -1,55 +0,0 @@
-
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Refresh jobs statuses
-    setTimeout(refreshJobs, 0)
-
-});
-
-
-// Refresh jobs
-function refreshJobs() {
-
-    // Get HTML node containing job id in their dataset
-    const jobNodes = document.querySelectorAll('.job');
-
-    // Extract job id from the dataset of the HTML nodes
-    const jobIds = JSON.stringify(Array.from(jobNodes).map(node => node.dataset['id']));
-
-    // Make ajax request to server and update the status of the job
-    fetch(`/api/jobs?ids=${jobIds}`, {
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If server response is false display error
-                displayToast(data['message'],  'danger');
-
-            } else {
-
-                // Update status
-                for (let i = 0; i < data.length; i++) {
-                    document.querySelector(`#job-id-${data[i]['id']}-status`).innerHTML = data[i]['status'];
-                    document.querySelector(`#job-id-${data[i]['id']}-status`).className = `badge badge-${statusColor[data[i]['status']]} badge-pill`;
-                }
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display js error, if any
-            displayToast(err, "danger");
-
-        })
-
-    // Recursively refresh
-    const refreshInterval = Number(localStorage.getItem('refreshInterval')) || 5000;
-    setTimeout(refreshJobs, refreshInterval);
-
-}
diff --git a/ganga/GangaGUI/gui/static/js/login.js b/ganga/GangaGUI/gui/static/js/login.js
deleted file mode 100644
index 94631debe4..0000000000
--- a/ganga/GangaGUI/gui/static/js/login.js
+++ /dev/null
@@ -1,65 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Login handler
-    const btnSubmit = document.querySelector('#btn-submit');
-    btnSubmit.addEventListener('click', loginHandler);
-
-});
-
-
-function loginHandler(e) {
-
-    // Prevent form from submitting
-    e.preventDefault();
-
-    // Get form username and password
-    const username = document.querySelector('#username').value;
-    const password = document.querySelector('#password').value;
-
-    // For displaying any error
-    const errorNode = document.querySelector('#error');
-
-    // Clear exisiting errors
-    errorNode.innerHTML = '';
-
-    // Convert the username and password into JSON
-    const jsonBody = JSON.stringify({
-        username: username,
-        password: password
-    });
-
-    // Make server request to get token
-    fetch('/token', {
-        method: 'post',
-        headers: {
-            'Content-Type': 'application/json'
-        },
-        body: jsonBody,
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-                // If API responds with failure, display the error message
-                errorNode.innerHTML = data['message'];
-            } else {
-                // Extract token from the data and store it
-                const token = data['token'];
-                if (token !== undefined) {
-                    localStorage.setItem('token', token);
-
-                    // After storing the token, submit the form
-                    loginForm = document.querySelector('#login-form');
-                    loginForm.submit();
-                } else {
-                    errorNode.innerHTML = 'Token not found!';
-                }
-            }
-
-        })
-        .catch(err => {
-            // Display error, if any
-            errorNode.innerHTML = err;
-        })
-
-}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/static/js/main.js b/ganga/GangaGUI/gui/static/js/main.js
deleted file mode 100644
index 6160fe4e71..0000000000
--- a/ganga/GangaGUI/gui/static/js/main.js
+++ /dev/null
@@ -1,86 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Set the refresh interval selector value to the active value
-    document.querySelector('#refresh-interval').value = localStorage.getItem('refreshInterval');
-
-    // Add event listener to refresh interval selector in the footer
-    const refreshIntervalSelector = document.querySelector('#refresh-interval');
-    refreshIntervalSelector.addEventListener('change', updateRefreshInterval);
-
-    // Add event listen to logout button to trigger logout function
-    const btnLogout = document.querySelector('#btn-logout');
-    btnLogout.addEventListener('click', logoutHandler);
-
-});
-
-
-// Global variables
-let notificationCount = 0;
-const statusColor = {
-    'new': 'info',
-    'completed': 'success',
-    'completed_frozen': 'success',
-    'failed': 'danger',
-    'failed_frozen': 'danger',
-    'running': 'primary',
-    'submitted': 'secondary',
-    'killed': 'warning'
-};
-
-
-// Returns time in readable format
-function currentTime() {
-    const date = new Date();
-    return 'Timestamp ' + date.getHours() + ":" + date.getMinutes();
-}
-
-
-// Display notification
-function displayToast(message, type, id=notificationCount, time=currentTime()) {
-
-    // Notification template based on Bootstrap CSS Toast
-    const bootstrapToast = `
-        <div class='toast' data-delay='10000' id='notification-{{id}}' role='alert' aria-live='assertive' aria-atomic='true'>
-            <div class='toast-header d-flex'>
-                <strong class='flex-grow-1 text-{{type}}'>Notification</strong>
-                <small class='text-muted mx-3'>{{ time }}</small>
-                <button type='button' class='ml-2 mb-1 close' data-dismiss='toast' aria-label='Close'>
-                    <span aria-hidden='true'>&times;</span>
-                </button>
-            </div>
-            <div class='toast-body'>
-                {{message}}
-            </div>
-        </div>
-    `;
-
-    // Compile the template
-    const template = Handlebars.compile(bootstrapToast);
-    const toastContainer = document.querySelector('#toast-container');
-    toastContainer.insertAdjacentHTML('beforeend', template({message: message, time: time, id: id, type: type}));
-    $(`#notification-${id}`).toast('show');
-    notificationCount++;
-
-}
-
-
-// Handle update of refresh interval time
-function updateRefreshInterval(e) {
-    let refreshInterval = e.target.value;
-    localStorage.setItem('refreshInterval', refreshInterval);
-}
-
-
-// Handle logout
-function logoutHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Remove token from the browser storage
-    localStorage.removeItem('token');
-
-    // Navigate to logout route
-    window.location.href = '/logout';
-
-}
diff --git a/ganga/GangaGUI/gui/static/js/queue.js b/ganga/GangaGUI/gui/static/js/queue.js
deleted file mode 100644
index 8bd94f7130..0000000000
--- a/ganga/GangaGUI/gui/static/js/queue.js
+++ /dev/null
@@ -1,49 +0,0 @@
-var chart;
-
-function requestData()
-{
-            
-    var requests = $.get('/api/queue/chart');
-
-
-    var tm = requests.done(function (result)
-    {
-        var series = chart.series[0],
-            shift = series.data.length > 20;
-        chart.series[0].addPoint(result, true, shift);
-        setTimeout(requestData, 2000);
-    });
-}
-
-$(document).ready(function() {
-    chart = new Highcharts.Chart({
-        chart: {
-            renderTo: 'data-container',
-            defaultSeriesType: 'spline',
-            events: {
-                load: requestData
-            }
-        },
-        title: {
-            text: 'Queue'
-        },
-        xAxis: {
-            type: 'datetime',
-            tickPixelInterval: 150,
-            maxZoom: 20 * 1000
-        },
-        yAxis: {
-            minPadding: 0.2,
-            maxPadding: 0.2,
-            title: {
-                text: 'Worker_Threads',
-                margin: 80
-            }
-        },
-        series: [{
-            name: 'Time',
-            data: []
-        }]
-    });
-
-});
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/static/js/slidecli.js b/ganga/GangaGUI/gui/static/js/slidecli.js
deleted file mode 100644
index 2942ac7bc1..0000000000
--- a/ganga/GangaGUI/gui/static/js/slidecli.js
+++ /dev/null
@@ -1,16 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Add event listener to button to toggle web cli
-    const btnCliList = document.querySelectorAll('.btn-cli');
-    Array.from(btnCliList).map(btnCli => btnCli.addEventListener('click', toggleCli));
-
-
-});
-
-
-// Show/Hide CLI
-let cliOpen = false;
-function toggleCli() {
-    document.querySelector('#cli-container').style['display'] = cliOpen ? 'none' : 'initial';
-    cliOpen = !cliOpen;
-}
diff --git a/ganga/GangaGUI/gui/static/js/style.js b/ganga/GangaGUI/gui/static/js/style.js
deleted file mode 100644
index 75ec557b33..0000000000
--- a/ganga/GangaGUI/gui/static/js/style.js
+++ /dev/null
@@ -1,49 +0,0 @@
-(function($) {
-  "use strict"; 
-  $("#sidebarToggle, #sidebarToggleTop").on('click', function(e) {
-    $("body").toggleClass("sidebar-toggled");
-    $(".sidebar").toggleClass("toggled");
-    if ($(".sidebar").hasClass("toggled")) {
-      $('.sidebar .collapse').collapse('hide');
-    };
-  });
-  $(window).resize(function() {
-    if ($(window).width() < 768) {
-      $('.sidebar .collapse').collapse('hide');
-    };
-    
-    if ($(window).width() < 480 && !$(".sidebar").hasClass("toggled")) {
-      $("body").addClass("sidebar-toggled");
-      $(".sidebar").addClass("toggled");
-      $('.sidebar .collapse').collapse('hide');
-    };
-  });
-
-  $('body.fixed-nav .sidebar').on('mousewheel DOMMouseScroll wheel', function(e) {
-    if ($(window).width() > 768) {
-      var e0 = e.originalEvent,
-        delta = e0.wheelDelta || -e0.detail;
-      this.scrollTop += (delta < 0 ? 1 : -1) * 30;
-      e.preventDefault();
-    }
-  });
-
-
-  $(document).on('scroll', function() {
-    var scrollDistance = $(this).scrollTop();
-    if (scrollDistance > 100) {
-      $('.scroll-to-top').fadeIn();
-    } else {
-      $('.scroll-to-top').fadeOut();
-    }
-  });
-
-  $(document).on('click', 'a.scroll-to-top', function(e) {
-    var $anchor = $(this);
-    $('html, body').stop().animate({
-      scrollTop: ($($anchor.attr('href')).offset().top)
-    }, 1000, 'easeInOutExpo');
-    e.preventDefault();
-  });
-
-})(jQuery);
diff --git a/ganga/GangaGUI/gui/static/js/subjob.js b/ganga/GangaGUI/gui/static/js/subjob.js
deleted file mode 100644
index c82cadc881..0000000000
--- a/ganga/GangaGUI/gui/static/js/subjob.js
+++ /dev/null
@@ -1,142 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Refresh subjob status
-    setTimeout(refreshStatus, 0)
-
-    // Add event listener to copy button
-    const btnCopy = document.querySelector('#btn-copy');
-    btnCopy.addEventListener('click', copyHandler);
-
-    // Add event listener to display attribute information
-    const attributeSelect =  document.querySelector('#attribute-select');
-    attributeSelect.addEventListener('change', attributeSelectHandler);
-
-});
-
-
-// Handles copying of the subjob to a new job
-function copyHandler(e) {
-
-    // Prevent default behavior
-    e.preventDefault();
-
-    // Get job id from the btn dataset
-    const jobId = e.target.dataset.job_id;
-
-    // Get subjob id from the btn dataset
-    const subjobId = e.target.dataset.subjob_id;
-
-    // Make ajax request to server
-    fetch(`/api/jobs/${jobId}/subjobs/${subjobId}/copy`, {
-        method: 'PUT',
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            // Display server response
-            displayToast(data['message'], data['success'] ? 'success' : 'danger');
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, 'danger');
-
-        })
-    ;
-
-}
-
-
-// Handles displaying attribute information of the subjob
-function attributeSelectHandler(e) {
-
-    // Get job id value from the select dataset
-    const jobId = e.target.dataset.job_id;
-
-    // Get the subjob id value from the select dataset
-    const subjobId = e.target.dataset.subjob_id;
-
-    // Get attribute value from the select value
-    const attribute = e.target.value;
-
-    // Make a request to the server
-    fetch(`/api/jobs/${jobId}/subjobs/${subjobId}/${attribute}`, {
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If API response false, display error
-                displayToast(data['message'], 'danger');
-
-            } else {
-
-                // Display attribute information
-                const attributeInfoBox = document.querySelector('#attribute-info-box');
-                attributeInfoBox.innerHTML = data[attribute];
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error while making the request, if any
-            displayToast(err, 'danger');
-
-        })
-    ;
-}
-
-
-// Refreshes status of the job
-function refreshStatus() {
-
-    // Job id and subjob id
-    const jobId = document.querySelector('#subjob-info').dataset.job_id;
-    const subjobId = document.querySelector('#subjob-info').dataset.subjob_id;
-
-    // Get subjob information from the server
-    fetch(`/api/jobs/${jobId}/subjobs/${subjobId}/status`, {
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If API response false, display error
-                displayToast(data['message'], 'danger');
-
-            } else {
-
-                // Update status
-                document.querySelector(`#subjob-id-${subjobId}-status`).innerHTML = data['status'];
-                document.querySelector(`#subjob-id-${subjobId}-status`).className = `badge badge-${statusColor[data['status']]} badge-pill ml-2`;
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error while making the request, if any
-            displayToast(err, 'danger');
-
-        })
-    ;
-
-    // Recursively refresh
-    const refreshInterval = Number(localStorage.getItem('refreshInterval')) || 5000;
-    setTimeout(refreshStatus, refreshInterval);
-
-}
-
diff --git a/ganga/GangaGUI/gui/static/js/subjobs.js b/ganga/GangaGUI/gui/static/js/subjobs.js
deleted file mode 100644
index 165a9e7686..0000000000
--- a/ganga/GangaGUI/gui/static/js/subjobs.js
+++ /dev/null
@@ -1,57 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Refresh subjobs statuses
-    setTimeout(refreshSubjobs, 0);
-
-});
-
-
-// Refresh subjobs
-function refreshSubjobs() {
-
-    // Get HTML nodes containing subjob id in dataset
-    const subjobNodes = document.querySelectorAll('.subjob');
-
-    // Extract subjob id from the HTML nodes
-    const subjobIds = JSON.stringify(Array.from(subjobNodes).map(node => node.dataset['id']));
-
-    // Extract job id from the subjob HTML node dataset
-    const jobId = document.querySelector('.subjob').dataset['job_id']
-
-    // Make request to the server
-    fetch(`/api/jobs/${jobId}/subjobs?ids=${subjobIds}`, {
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If server responds to failure, display the error message
-                displayToast(data['message'], 'danger');
-
-            } else {
-
-                // Refresh statuses
-                for (let i = 0; i < data.length; i++) {
-                    document.querySelector(`#subjob-id-${data[i]['id']}-status`).innerHTML = data[i]['status'];
-                    document.querySelector(`#subjob-id-${data[i]['id']}-status`).className = `badge badge-${statusColor[data[i]['status']]} badge-pill`;
-                }
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error, if any
-            displayToast(err, "danger");
-
-        });
-
-    // Recursively refresh
-    const refreshInterval = Number(localStorage.getItem('refreshInterval')) || 5000;
-    setTimeout(refreshSubjobs, refreshInterval);
-
-}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/static/js/templates.js b/ganga/GangaGUI/gui/static/js/templates.js
deleted file mode 100644
index 2db360d77d..0000000000
--- a/ganga/GangaGUI/gui/static/js/templates.js
+++ /dev/null
@@ -1,143 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
-
-    // Add event listeners to create buttons
-    const btnCreateList = document.querySelectorAll('.btn-create');
-    Array.from(btnCreateList).map(btnCreate => btnCreate.addEventListener('click', createJobHandler));
-
-    // Add event listeners to delete buttons
-    const btnTemplateInfoList = document.querySelectorAll('.btn-template-info');
-    Array.from(btnTemplateInfoList).map(btnTemplateInfo => btnTemplateInfo.addEventListener('click', templateInfoHandler));
-
-    // Add event listeners to delete buttons
-    const btnDeleteList = document.querySelectorAll('.btn-delete');
-    Array.from(btnDeleteList).map(btnDelete => btnDelete.addEventListener('click', deleteTemplateHandler));
-
-});
-
-
-// Make an request to create a job using template
-function createJobHandler(e) {
-
-    // Get template id from the dataset of button
-    const templateId = e.target.dataset.id;
-
-    // Make ajax request to the server with template id in the body
-    fetch(`/api/jobs/create`, {
-        method: 'POST',
-        headers: {
-            'Content-Type': 'application/json',
-            'X-Access-Token': localStorage.getItem('token')
-        },
-        body: JSON.stringify({
-            template_id: templateId
-        })
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            // Display server response
-            displayToast(data['message'], data['success'] ? 'success' : 'danger');
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, "danger");
-
-        })
-    ;
-
-}
-
-// Display template information
-function templateInfoHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get template id from the dataset of button
-    const templateId = e.target.dataset.id;
-
-    // Make ajax request to the server to get the template full print
-    fetch(`/api/templates/${templateId}/full-print`, {
-        method: 'GET',
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If server response is false display error
-                displayToast(data['message'],  'danger');
-
-            } else {
-
-                // Display toast
-                const templateInfoBox = document.querySelector("#template-info-box");
-                templateInfoBox.innerHTML = data;
-                $('#template-info-modal').modal('show')
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, "danger");
-
-        })
-    ;
-
-}
-
-
-// Make an request to delete the template
-function deleteTemplateHandler(e) {
-
-    // Prevent default behaviour
-    e.preventDefault();
-
-    // Get template id from the dataset of button
-    const templateId = e.target.dataset.id;
-
-    // Make ajax request to the server to delete the template
-    fetch(`/api/templates/${templateId}`, {
-        method: 'DELETE',
-        headers: {
-            'X-Access-Token': localStorage.getItem('token')
-        }
-    })
-        .then(response => response.json())
-        .then(data => {
-
-            if (data['success'] === false) {
-
-                // If server response is false display error
-                displayToast(data['message'],  'danger');
-
-            } else {
-
-                // Display success message
-                displayToast(data['message'],  'success');
-
-                // Delete row
-                const templateRow = document.querySelector(`#template-${templateId}`);
-                templateRow.remove();
-
-            }
-
-        })
-        .catch(err => {
-
-            // Display error if any
-            displayToast(err, "danger");
-
-        })
-    ;
-
-}
-
-
diff --git a/ganga/GangaGUI/gui/templates/base.html b/ganga/GangaGUI/gui/templates/base.html
deleted file mode 100644
index 6f8d283990..0000000000
--- a/ganga/GangaGUI/gui/templates/base.html
+++ /dev/null
@@ -1,223 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <!-- Meta Tags -->
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
-    <!-- Bootstrap CSS -->
-    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
-    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/css/dataTables.bootstrap4.min.css" integrity="sha512-PT0RvABaDhDQugEbpNMwgYBCnGCiTZMh9yOzUsJHDgl/dMhD9yjHAwoumnUk3JydV3QTcIkNDuN40CJxik5+WQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
-     <link href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
-        rel="stylesheet">
-    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
-
-    <!-- Custom Style Sheet -->
-    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
-
-    <!-- Include Handlebars from a CDN -->
-    <script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script>
-
-    <!-- Title -->
-    <title>{{ title + ' - Ganga GUI' if title else 'Ganga GUI' }}</title>
-
-    <!-- Head Block -->
-    {% block head %}{% endblock head %}
-</head>
-<body id="page-top">
-    <div id="wrapper">
-        <ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">
-
-            <a class="sidebar-brand d-flex align-items-center justify-content-center" href="{{ url_for('dashboard') }}">
-                <div class="sidebar-brand-text mx-3">Dashboard</div>
-            </a>
-            <hr class="sidebar-divider my-0">
-
-            <li class="nav-item {{ 'active' if request.path == url_for('create_page') }}">
-                <a class="nav-link" href="{{ url_for('create_page') }}">
-                    <i class="fas fa-fw fa-table"></i>
-                    <span>Create</span>
-             </a>
-            </li>
-            <li class="nav-item {{ 'active' if request.path == url_for('jobs_page') }}">
-               <a class="nav-link" href="{{ url_for('jobs_page') }}">
-                    <i class="fas fa-fw fa-table"></i>
-                    <span>Jobs</span>
-                </a>
-            </li>
-            <li class="nav-item {{ 'active' if request.path == url_for('credentials_page') }}">
-               <a class="nav-link" href="{{ url_for('credentials_page') }}">
-                    <i class="fas fa-fw fa-table"></i>
-                    <span>Credentials</span>
-                </a>
-            </li>
-            <li class="nav-item {{ 'active' if request.path == url_for('plugins_page') }}">
-               <a class="nav-link" href="{{ url_for('plugins_page') }}">
-                    <i class="fas fa-fw fa-table"></i>
-                    <span>Plugins</span>
-                </a>
-            </li>
-            <li class="nav-item {{ 'active' if request.path == url_for('config_page') }}">
-               <a class="nav-link" href="{{ url_for('config_page') }}">
-                    <i class="fas fa-fw fa-table"></i>
-                    <span>Config</span>
-                </a>
-            </li>
-            <li class="nav-item {{ 'active' if request.path == url_for('queue_page') }}">
-               <a class="nav-link" href="{{ url_for('queue_page') }}">
-                    <i class="fas fa-fw fa-table"></i>
-                    <span>Queue</span>
-                </a>
-            </li>
-            <li class="nav-item">
-               <a class="nav-link btn-cli {{ 'd-none' if session['WEB_CLI'] == False }}" href="#">
-                    <i class="fas fa-fw fa-table"></i>
-                    <span>CLI</span>
-                </a>
-            </li>
-            <li class="nav-item">
-               <a class="nav-link" href="http://ganga.readthedocs.io" target="_blank">
-                    <i class="fas fa-fw fa-table"></i>
-                    <span>Help</span>
-                </a>
-            </li>
-            <li class="nav-item nav-down">
-               <a class="nav-link" id="btn-logout" href="#">
-                    <i class="fas fa-fw fa-table"></i>
-                    <span>Logout</span>
-                </a>
-            </li>
-            <li class="nav-item">
-               <a class="nav-link" href="{{ url_for('shutdown') }}">
-                    <i class="fas fa-fw fa-table"></i>
-                    <span>Shutdown</span>
-                </a>
-            </li>
-            <li class="nav-item">
-                <a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseSetting"
-                    aria-expanded="true" aria-controls="collapseSetting">
-                    <i class="fas fa-fw fa-wrench"></i>
-                    <span>Settings</span>
-                </a>
-                <div id="collapseSetting" class="collapse" aria-labelledby="headingUtilities"
-                    data-parent="#accordionSidebar">
-                    <div class="bg-white py-2 collapse-inner rounded">
-                        <a class="collapse-item" href="{{ url_for('logs_page') }}">Logs</a>
-                        <a class="collapse-item" href="{{ url_for('runfile_page') }}">Quick Run</a>
-                        <a class="collapse-item" href="{{ url_for('storage_page') }}">Storage Pod</a>
-                        
-                    </div>
-                </div>
-            </li>
-            <hr class="sidebar-divider d-none d-md-block">
-            <div class="text-center d-none d-md-inline">
-                <button class="rounded-circle border-0" id="sidebarToggle"></button>
-            </div>
-        </ul>
-
-        <div id="content-wrapper" class="d-flex flex-column">
-            <div id="content">
-                <nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
-                    <button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
-                        <i class="fa fa-bars"></i>
-                    </button>
-                    <ul class="navbar-nav ml-auto">
-                        <li class="nav-item dropdown no-arrow">
-                            <img width="150" height="42" src="{{ url_for('static', filename='img/logo.svg') }}">
-                        </li>
-                    </ul>
-                </nav>
-            {% with messages = get_flashed_messages(with_categories=true) %}
-                {% if messages %}
-                    {% for category, message in messages %}
-                        <div class="alert alert-{{ category }} btn-block" style="border-radius: 0" role="alert">
-                            {{ message }}
-                        </div>
-                    {% endfor %}
-                {% endif %}
-            {% endwith %}
-                
-                
-            <div class="container-fluid">
-                <div class="d-sm-flex align-items-center justify-content-between mb-4">
-                    <div class="h3 mb-0 text-gray-800"></div>
-                    <a href="#" data-toggle="modal" data-target="#refreshModal" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i class="fas fa-cog fa-sm text-white-50"></i> Refresh</a>
-                </div>
-
-                {% block content %}{% endblock content %}
-            </div>
-        </div>
-           
-
-        <div id="cli-container"
-             style="display: none; position: fixed; bottom: 0; left: 0; height: 50vh; width: 100%; z-index: 50; box-shadow: 0 -2px 6px rgba(0,0,0,0.30);"
-             class="rounded-top overflow-hidden">
-            <div class="d-flex justify-content-end align-items-center mt-2 px-2" style="position: absolute; top: 0; right:0;">
-                <a href="{{ url_for('serve_cli') if session['WEB_CLI'] == True }}" target="_blank"
-                  class="btn btn-primary btn-sm text-white" style="cursor: pointer">Open in New Tab</a>
-                <a class="btn btn-danger btn-sm text-white btn-cli ml-2" style="cursor: pointer">Hide</a>
-            </div>
-            <iframe src="{{ url_for('serve_cli') if session['WEB_CLI'] == True }}" id="cli-iframe" title="Web CLI" style="width: 100%; height: 100%; border: none;"></iframe>
-        </div>   
-    </div> 
-
-    
-    <a class="scroll-to-top rounded" href="#page-top">
-        <i class="fas fa-angle-up"></i>
-    </a>
-    <div class="modal fade" id="refreshModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
-        aria-hidden="true">
-        <div class="modal-dialog" role="document">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title" id="exampleModalLabel">Refresh</h5>
-                    <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-                        <span aria-hidden="true">×</span>
-                    </button>
-                </div>
-                <div class="modal-body">
-                <div class="form-group col-md-12 align-items-right">
-                <label for="refresh-interval" class="small text-muted">Refresh:</label>
-                <select id="refresh-interval" class="custom-select">
-                    <option value="1000">1</option>
-                    <option value="2000">2</option>
-                    <option value="5000" selected>5</option>
-                    <option value="10000">10</option>
-                    <option value="30000">30</option>
-                    <option value="60000">60</option>
-                    <option value="120000">120</option>
-                </select>
-                </div>
-                </div>
-                <div class="modal-footer">
-                    <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                </div>
-            </div>
-        </div>
-    </div>
-
-  
-
-{# JavaScript files #}
-<script defer src="{{ url_for('static', filename='js/main.js') }}"></script>
-<script defer src="{{ url_for('static', filename='js/style.js') }}"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/js/jquery.dataTables.min.js" integrity="sha512-BkpSL20WETFylMrcirBahHfSnY++H2O1W+UnEEO4yNIl+jI2+zowyoGJpbtk6bx97fBXf++WJHSSK2MV4ghPcg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
-<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
-<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
-<script src="http://code.highcharts.com/highcharts.js"></script>
-<script src="http://code.highcharts.com/highcharts-more.js"></script>
-<script src="http://code.highcharts.com/modules/exporting.js"></script>
-
-
-
-{# JS file specific to web cli mode#}
-<script defer src="{{ url_for('static', filename='js/slidecli.js') if session['WEB_CLI'] == True else '#' }}"></script>
-
-{% block footer %}{% endblock footer %}
-
-
-
-
-</body>
-</html>
diff --git a/ganga/GangaGUI/gui/templates/cli.html b/ganga/GangaGUI/gui/templates/cli.html
deleted file mode 100644
index f89f602f85..0000000000
--- a/ganga/GangaGUI/gui/templates/cli.html
+++ /dev/null
@@ -1,82 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta name="viewport"
-          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
-    <meta http-equiv="X-UA-Compatible" content="ie=edge">
-
-    <!-- Xterm.js Style Sheet -->
-    <link rel="stylesheet" href="https://unpkg.com/xterm@3.6.0/dist/xterm.css"/>
-
-    <title>CLI - Ganga GUI</title>
-
-    <!-- Customs styles -->
-    <style>
-
-        body {
-            margin: 0;
-            padding: 0;
-            overflow: hidden;
-
-        }
-
-        div {
-            margin: 0;
-            padding: 0;
-        }
-
-        .status-bar {
-            position: fixed;
-            bottom: 0.5rem;
-            right: 1rem;
-            background-color: lightgray;
-            z-index: 100;
-            border-radius: 3px;
-            padding: 0.25rem 0.5rem;
-            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
-            font-size: 0.75rem;
-        }
-
-        .connected {
-            background-color: green;
-            color: white;
-        }
-
-        .disconnected {
-            background-color: darkred;
-            color: white;
-        }
-
-        #terminal {
-            width: calc(100% - 1rem);
-            height: calc(100% - 1rem);
-        }
-
-        .container {
-            width: 100vw;
-            height: 100vh;
-            background-color: black;
-            padding: 0.5rem;
-        }
-    </style>
-
-</head>
-<body>
-
-<div class="container">
-    <p onclick="clear();" class="status-bar">Status: <span id="status">Connecting...</span></p>
-    <div id="terminal"></div>
-</div>
-
-<!-- Xterm JS, then Socketio -->
-<script src="https://unpkg.com/xterm@3.6.0/dist/xterm.js"></script>
-<script src="https://unpkg.com/xterm@3.6.0/dist/addons/fit/fit.js"></script>
-<script src="https://unpkg.com/xterm@3.6.0/dist/addons/webLinks/webLinks.js"></script>
-<script src="https://unpkg.com/xterm@3.6.0/dist/addons/fullscreen/fullscreen.js"></script>
-<script src="https://unpkg.com/xterm@3.6.0/dist/addons/search/search.js"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.js"></script>
-<script defer src="{{ url_for('static', filename='js/cli.js') }}"></script>
-
-</body>
-</html>
diff --git a/ganga/GangaGUI/gui/templates/config.html b/ganga/GangaGUI/gui/templates/config.html
deleted file mode 100644
index 0b04226f63..0000000000
--- a/ganga/GangaGUI/gui/templates/config.html
+++ /dev/null
@@ -1,72 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    <div class="d-sm-flex align-items-center justify-content-between mb-4">
-        <div class="h3 mb-0 text-gray-800"></div>
-        <a href="{{ url_for('edit_config_page') }}" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm">Edit gangarc</a>
-    </div>
-   
-    <form method="post">
-        <div class="form-row">
-            <div class="form-group col-md-9">
-                <select class="form-control custom-select" name="section">
-                    <option selected value="">Select Config</option>
-                    {% for s in full_config_info %}
-                        <option value="{{ s.get('name') }}">{{ s.get('name') }}</option>
-                    {% endfor %}
-                </select>
-            </div>
-            <div class="form-group col-md-3">
-                <button type="submit" class="btn btn-block btn-primary">Show Config</button>
-            </div>
-        </div>
-    </form>
-    <hr class="my-1 mb-3 mt-3">
-    <div class="row justify-content-center">
-        <div class="col-12">
-            <div class="accordion" id="config">
-                <div class="list-group">
-                    {% for section in config_info %}
-                        <a href="#"
-                            class="list-group-item d-flex justify-content-between font-weight-medium align-items-center list-group-item-action {{ 'rounded-bottom' if loop.last }}"
-                            data-toggle="collapse"
-                            data-target="#collapse-config-{{ section.get('name') }}" aria-expanded="true"
-                            aria-controls="collapse-config-{{ section.get('name') }}">
-                            {{ section.get('name') }}
-                        </a>
-                        <div id="collapse-config-{{ section.get('name') }}"
-                            class="collapse border-left border-right {{ 'border-bottom rounded-bottom' if loop.last }}"
-                            data-parent="#config">
-                            <div class="card-body">
-                                <h3 class="font-weight-normal mb-n2 pb-2">{{ section.get('name') }}</h3>
-                                <small class="text-muted">{{ section.get('docstring') }}</small>
-                                <table class="table table-striped table-bordered text-center mt-2 table-responsive-sm">
-                                    <thead>
-                                    <tr>
-                                        <th class="align-middle" scope="col">ID</th>
-                                        <th class="align-middle" style="width: 70%;" scope="col">Option Name</th>
-                                        <th class="align-middle" style="width: 25%;" scope="col">Effective Value
-                                        </th>
-                                    </tr>
-                                    </thead>
-                                    <tbody>
-                                    {% for option in section.get('options') %}
-                                        <tr>
-                                            <th class="align-middle" scope="row">{{ loop.index }}</th>
-                                            <td class="align-middle text-left">{{ option.get('name') }}<br><small
-                                                class="text-muted">{{ option.get('docstring') }}</small>
-                                            </td>
-                                            <td class="align-middle text-break">{{ option.get('value') }}</td>
-                                        </tr>
-                                    {% endfor %}
-                                    </tbody>
-                                </table>
-                            </div>
-                        </div>
-                    {% endfor %}
-                </div>
-            </div>
-        </div>
-    </div>
-    
-{% endblock content %}
diff --git a/ganga/GangaGUI/gui/templates/config_edit.html b/ganga/GangaGUI/gui/templates/config_edit.html
deleted file mode 100644
index 9f195d425e..0000000000
--- a/ganga/GangaGUI/gui/templates/config_edit.html
+++ /dev/null
@@ -1,44 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    
-    <h3 class="text-gray-900">Edit gangarc</h3>
-    <hr class="my-2">
-
-        <form method="post">
-        <div class="form-group">
-            <label for="runfile" class="text-gray-900">Edit gangarc file.</label>
-            <textarea class="form-control" data-editor="markdown" id="config" name="config-data" rows="20">{{ ganga_config }}</textarea>
-        </div>
-        <div class="d-flex justify-content-center">
-            <button class="btn btn-primary" type="submit">Save</button>
-        </div>
-    </form>
-    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
-    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/ace.js"></script>
-    <script type="text/javascript">
-    $('textarea[data-editor]').each(function() {
-        var textarea = $(this);
-        var mode = textarea.data('editor');
-        var div = $('<div>', {
-            'width': textarea.outerWidth(),
-            'height': textarea.outerHeight(),
-            'class': textarea.attr('class')
-        }).insertBefore(textarea);
-        textarea.hide();
-        var editor = ace.edit(div[0]);
-        var session = editor.getSession();
-        editor.setTheme("ace/theme/monokai");
-        session.setValue(textarea.val());
-        session.setMode('ace/mode/' + mode);
-        session.setNewLineMode('unix');
-        session.setTabSize(4);
-        session.setUseSoftTabs(true);
-        session.setUseWrapMode(true);
-        textarea.closest('form').submit(function() {
-            textarea.val(editor.getSession().getValue());
-        });
-    });
-    </script>
-    
-{% endblock content %}
diff --git a/ganga/GangaGUI/gui/templates/create.html b/ganga/GangaGUI/gui/templates/create.html
deleted file mode 100644
index 3743fa539c..0000000000
--- a/ganga/GangaGUI/gui/templates/create.html
+++ /dev/null
@@ -1,70 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-
-    <div class="row">
-        <div class="col-md-6">
-            <div class="mb-2 d-flex align-items-center justify-content-between">
-                <h3 class="h3 mb-0 text-gray-900">Load Job</h3>
-            </div>
-            <form method=post enctype=multipart/form-data>
-                <div class="input-group mb-3">
-                    <div class="custom-file">
-                        <input type="file" name="loadfile" class="custom-file-input" id="loadfile-input">
-                        <label class="custom-file-label" id="loadfile-input-label" for="loadfile-input"
-                                   aria-describedby="loadfileInputAddon">Choose file</label>
-                    </div>
-                    <div class="input-group-append">
-                        <input class="input-group-text" id="loadfileInputAddon" type=submit value=Upload>
-                    </div>
-                </div>
-            </form>
-        </div>
-        <div class="col-md-6">
-            <div class="mb-2 d-flex align-items-center justify-content-between">
-                <h3 class="h3 mb-0 text-gray-900">Run File</h3><a href="{{ url_for('runfile_page') }}">Quick Create Run File</a>
-            </div>
-            <form method=post enctype=multipart/form-data>
-                <div class="input-group mb-3">
-                    <div class="custom-file">
-                        <input type="file" name="runfile" class="custom-file-input" id="runfile-input">
-                        <label class="custom-file-label" for="runfile-input" id="runfile-input-label"
-                                   aria-describedby="runfileInputAddon">Choose file</label>
-                    </div>
-                    <div class="input-group-append">
-                        <input class="input-group-text" id="runfileInputAddon" type=submit value=Upload>
-                    </div>
-                </div>
-            </form>
-        </div>
-    </div>
-    <hr class="my-3">
-    <div class="mb-2 d-flex align-items-center justify-content-between">
-        <h3 class="h3 mb-0 text-gray-900">From Templates</h3><a href="{{ url_for('templates_page') }}">Explore All Templates</a>
-    </div>
-    <div class="row">
-        {% for t in templates_info %}
-            <div class="col-md-4 mb-4">
-                <div class="card" id="template-card" data-template_id="{{ t.get('id') }}">
-                    <div class="card-body">
-                        <h6 class="card-title">{{ t.get('name') if t.get('name').strip() != '' else 'Unnamed Template' }}</h6>
-                        <hr class="my-1">
-                        <p class="m-0 p-0">id: {{ t.get('id') }}</p>
-                        <p class="m-0 p-0">application: {{ t.get('application').split('(')[0] }}</p>
-                        <p class="m-0 p-0">backend: {{ t.get('backend').split('(')[0] }}</p>
-                        <p class="m-0 p-0">backend.actualCE: {{ t.get('backend.actualCE') }}</p>
-                        <p class="m-0 p-0">comment: {{ t.get('comment') }}</p>
-                        <a href="#" data-id="{{ t.get('id') }}" class="btn btn-sm btn-block btn-primary mt-2 btn-create">
-                                Create
-                        </a>
-                    </div>
-                </div>
-            </div>
-        {% endfor %}
-    </div>
-
-{% endblock content %}
-
-{% block footer %}
-    <script defer src="{{ url_for('static', filename='js/create.js') }}"></script>
-{% endblock footer %}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/templates/credentials.html b/ganga/GangaGUI/gui/templates/credentials.html
deleted file mode 100644
index 0371768f84..0000000000
--- a/ganga/GangaGUI/gui/templates/credentials.html
+++ /dev/null
@@ -1,38 +0,0 @@
-{% extends 'base.html' %}
-{% block content %}
-   
-    <div class="row">
-        <div class="col-md-6 offset-md-3">
-            <div class="mb-0 d-flex align-items-center justify-content-between">
-                <h3 class="my-0 d-inline-block text-gray-900">Credential Store</h3><a href="#" id="btn-renew">Renew All</a>
-            </div>
-            <hr class="my-2 mb-3">
-            <table class="table table-striped table-bordered text-center table-responsive-sm">
-                <thead>
-                <tr>
-                    <th class="align-middle" scope="col">Location</th>
-                    <th class="align-middle" scope="col">Time Left</th>
-                    <th class="align-middle" scope="col">Expiry Time</th>
-                    <th class="align-middle" scope="col">Valid</th>
-                    <th class="align-middle" scope="col">Exists</th>
-                </tr>
-                </thead>
-                <tbody>
-                {% for c in credential_info_list %}
-                    <tr>
-                        <th class="align-middle" scope="row">{{ c['location'] }}</th>
-                        <td class="align-middle">{{ c['time_left'] }}</td>
-                        <td class="align-middle text-break">{{ c['expiry_time'] }}</td>
-                        <td class="align-middle text-break">{{ c['is_valid'] }}</td>
-                        <td class="align-middle">{{ c['exists'] }}</td>
-                    </tr>
-                {% endfor %}
-                </tbody>
-            </table>
-        </div>
-    </div>
-   
-{% endblock content %}
-{% block footer %}
-    <script defer src="{{ url_for('static', filename='js/credentials.js') }}"></script>
-{% endblock footer %}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/templates/dashboard.html b/ganga/GangaGUI/gui/templates/dashboard.html
deleted file mode 100644
index 984f122df3..0000000000
--- a/ganga/GangaGUI/gui/templates/dashboard.html
+++ /dev/null
@@ -1,229 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    
-    {# Quick Statistics Section #}
-    <h3 class="text-gray-800">Quick Statistics</h3>
-    <div class="row">
-
-            
-        <div class="col-lg mb-4">
-        {# Statistics Card - New #}
-            <div class="card border-left-primary shadow h-100 py-2 mx-auto">
-                <div class="card-body">
-                    <div class="row no-gutters align-items-center">
-                        <div class="col mr-2">
-                            <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">NEW</div>
-                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ quick_statistics.get('new') }}</div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-
-        <div class="col-lg mb-4">
-        {# Statistics Card - Running #}
-            <div class="card border-left-success shadow h-100 py-2 mx-auto">
-                <div class="card-body">
-                    <div class="row no-gutters align-items-center">
-                        <div class="col mr-2">
-                            <div class="text-xs font-weight-bold text-success text-uppercase mb-1">RUNNING</div>
-                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ quick_statistics.get('running') }}</div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-
-        <div class="col-lg mb-4">
-        {# Statistics Card - Completed #}
-            <div class="card border-left-info shadow h-100 py-2 mx-auto">
-                <div class="card-body">
-                    <div class="row no-gutters align-items-center">
-                        <div class="col mr-2">
-                            <div class="text-xs font-weight-bold text-info text-uppercase mb-1">COMPLETED</div>
-                            <div class="row no-gutters align-items-center">
-                                <div class="col-auto">
-                                    <div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">{{ quick_statistics.get('completed') }}</div>
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div> 
-
-        <div class="col-lg mb-4">
-        {# Statistics Card - Failed #}
-            <div class="card border-left-warning shadow h-100 py-2 mx-auto">
-                <div class="card-body">
-                    <div class="row no-gutters align-items-center">
-                        <div class="col mr-2">
-                            <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">FAILED</div>
-                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ quick_statistics.get('failed') }}</div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-
-        <div class="col-lg mb-4">
-        {# Statistics Card - Killed #}
-            <div class="card border-left-danger shadow h-100 py-2 mx-auto">
-                <div class="card-body">
-                    <div class="row no-gutters align-items-center">
-                        <div class="col mr-2">
-                            <div class="text-xs font-weight-bold text-danger text-uppercase mb-1">KILLED</div>
-                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ quick_statistics.get('killed') }}</div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-
-    <div class="row mt-4">
-        {# Recent Jobs Section #}
-        <div class="col-md-6">
-            <h3 class="text-gray-900">Recent Jobs</h3>
-            <div class="accordion" id="recent-jobs">
-                <div class="list-group">
-                    {% for j in recent_jobs_info|reverse %}
-                        <a href="#" id="job-id-{{ j.get('id') }}"
-                            class="recent-job list-group-item d-flex justify-content-between font-weight-medium align-items-center list-group-item-action {{ 'rounded-bottom' if loop.last }}"
-                            data-id="{{ j.get('id') }}"
-                            data-toggle="collapse"
-                            data-target="#collapse-job-id-{{ j.get('id') }}"
-                            aria-expanded="true"
-                            aria-controls="collapse-job-id-{{ j.get('id') }}">
-
-                            {# Job name #}
-                            {{ j.get('id') + '. ' + j.get('name') if j.get('name').strip() != '' else j.get('id') + '. '+ 'Unnamed Job' }}
-                            
-                            
-                            {% if j.get('subjobs') != '0' %}
-                                <span class="badge badge-pill">
-                                     Subjobs
-                                </span>
-                                
-                            {% endif %} 
-                            <span id="job-id-{{ j.get('id') }}-status"
-                                class="badge badge-{{ status_color[j.get('status')] }} badge-pill">
-                                {{ j.get('status') }}
-                            </span>   
-                        </a>
-                        {# Job info after uncollapsing #}
-                        <div id="collapse-job-id-{{ j.get('id') }}"
-                                class="collapse border-left border-right {{ 'border-bottom rounded-bottom' if loop.last }}"
-                            data-parent="#recent-jobs">
-                            <div class="card-body">
-                                <p class="m-0 p-0">fqid: {{ j.get('fqid') }}</p>
-                                <p class="m-0 p-0">subjobs: {{ j.get('subjobs') }}</p>
-                                <p class="m-0 p-0">Job Status: {{ j.get('status') }}</p>
-                                <p class="m-0 p-0">
-                                    application: {{ (j.get('application')|string).split('(')[0] }}
-                                </p>
-                                <p class="m-0 p-0">backend: {{ (j.get('backend')|string).split('(')[0] }}</p>
-                                <p class="m-0 p-0">backend.actualCE: {{ j.get('backend.actualCE') }}</p>
-                                <p class="m-0 p-0">comment: {{ j.get('comment') }}</p>
-                                <p class="m-0 p-0" id="subjob-statuses-job-id-{{ j.get('id') }}">
-                                    subjobs statuses: {{ j.get('subjob_statuses') }}
-                                </p>
-                                
-                               
-                                <a href="{{ url_for('job_page', job_id=j.get('id')) }}"
-                                    class="btn btn-sm btn-primary mt-3">
-                                    Job Info
-                                </a>
-                                
-                                {% if j.get('subjobs') != '0' %}
-                                    <a href="{{ url_for('subjobs_page', job_id=j.get('id')) }}"
-                                        class="btn btn-sm btn-primary mt-3">
-                                        Subjobs Info
-                                    </a>
-                                {% endif %} 
-                                <a href="#" data-id="{{ j.get('id') }}" class="btn btn-sm btn-primary mt-3 btn-copy">
-                                    Copy Job
-                                </a>
-                                <a href="#" data-id="{{ j.get('id') }}" class="btn btn-sm btn-primary mt-3 btn-unpin">Unpin Job</a>
-                            </div>
-                        </div>
-                    {% endfor %}
-                </div>
-            </div>
-        </div>
-
-        {# Pinned Jobs Section #}
-        <div class="col-md-6 mt-3 mt-md-0">
-            <h3 class="text-gray-900">Pinned Jobs</h3>
-            <div class="accordion" id="pinned-jobs">
-                <div class="list-group">
-                    {% for j in pinned_jobs_info|reverse %}
-                        <a href="#" id="job-id-{{ j.get('id') }}"
-                            class="pinned-job list-group-item d-flex justify-content-between font-weight-medium align-items-center list-group-item-action {{ 'rounded-bottom' if loop.last }}"
-                            data-id="{{ j.get('id') }}"
-                            data-toggle="collapse"
-                            data-target="#collapse-pinned-job-id-{{ j.get('id') }}"
-                            aria-expanded="true"
-                            aria-controls="collapse-pinned-job-id-{{ j.get('id') }}">
-                            {# Job name #}
-                            {{ j.get('id') + '. ' + j.get('name') if j.get('name').strip() != '' else j.get('id') + '. '+ 'Unnamed Job' }}
-                            {% if j.get('subjobs') != '0' %}
-                                <span id="job-id-{{ j.get('id') }}-status"
-                                    class="badge badge-pill">
-                                     Subjobs
-                                </span>
-                                
-                            {% endif %} 
-                            <span id="pinned-job-id-{{ j.get('id') }}-status"
-                                class="badge badge-{{ status_color[j.get('status')] }} badge-pill">
-                                {{ j.get('status') }}
-                            </span>
-
-                        </a>
-                        {# Job info when uncollapsed #}
-                        <div id="collapse-pinned-job-id-{{ j.get('id') }}"
-                            class="collapse border-left border-right {{ 'border-bottom rounded-bottom' if loop.last }}"
-                            data-parent="#pinned-jobs">
-                            <div class="card-body">
-                                <p class="m-0 p-0">fqid: {{ j.get('fqid') }}</p>
-                                <p class="m-0 p-0">subjobs: {{ j.get('subjobs') }}</p>
-                                <p class="m-0 p-0">
-                                    application: {{ (j.get('application')|string).split('(')[0] }}
-                                </p>
-                                <p class="m-0 p-0">backend: {{ (j.get('backend')|string).split('(')[0] }}</p>
-                                <p class="m-0 p-0">backend.actualCE: {{ j.get('backend.actualCE') }}</p>
-                                <p class="m-0 p-0">comment: {{ j.get('comment') }}</p>
-                                <p class="m-0 p-0" id="subjob-statuses-pinned-job-id-{{ j.get('id') }}">subjobs statuses: {{ j.get('subjob_statuses') }}</p>
-                                <a href="{{ url_for('job_page', job_id=j.get('id')) }}"
-                                    class="btn btn-sm btn-primary mt-3">
-                                    Job Info
-                                </a>
-                                {% if j.get('subjobs') != '0' %}
-                                    <a href="{{ url_for('subjobs_page', job_id=j.get('id')) }}"
-                                        class="btn btn-sm btn-primary mt-3">
-                                        Subjobs Info
-                                    </a>
-                                {% endif %} 
-
-                                <a href="#" data-id="{{ j.get('id') }}" class="btn btn-sm btn-primary mt-3 btn-copy">
-                                    Copy Job
-                                </a>
-                                <a href="#" data-id="{{ j.get('id') }}" class="btn btn-sm btn-primary mt-3 btn-unpin">Unpin Job</a>
-                            </div>
-                        </div>
-                    {% endfor %}
-                </div>
-            </div>
-        </div>
-    </div>
-    <div class="row mt-4">
-        <div class="col-lg"></div>
-    </div>
-    
-{% endblock content %}
-
-{% block footer %}
-    <script defer src="{{ url_for('static', filename='js/dashboard.js') }}"></script>
-
-{% endblock footer %}
diff --git a/ganga/GangaGUI/gui/templates/edit_job.html b/ganga/GangaGUI/gui/templates/edit_job.html
deleted file mode 100644
index b9c7f16c27..0000000000
--- a/ganga/GangaGUI/gui/templates/edit_job.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    <div class="container-fluid px-md-5">
-        <h3>Edit Job {{ job_id }}</h3>
-        <hr class="my-2">
-        <form method="post">
-            <div class="form-group">
-                <label for="job-edit">After submitting, a new modified job will be created.</label>
-                <textarea class="form-control" id="job-edit" name="edited-job-info" rows="20">{{ exported_data }}</textarea>
-            </div>
-            <div class="d-flex justify-content-center">
-                <button class="btn btn-primary" type="submit">Create New Job</button>
-            </div>
-        </form>
-    </div>
-{% endblock content %}
diff --git a/ganga/GangaGUI/gui/templates/job.html b/ganga/GangaGUI/gui/templates/job.html
deleted file mode 100644
index 775cac8a15..0000000000
--- a/ganga/GangaGUI/gui/templates/job.html
+++ /dev/null
@@ -1,236 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    <div class="container-fluid px-md-5">
-        <div class="row d-flex justify-content-center align-items-center">
-            <div class="col-md-6 mb-3 mb-md-0">
-                <div class="card" id="job-info" data-job_id="{{ job_info.get('id') }}">
-                    <div class="card-body">
-                        <div class="d-flex justify-content-between">
-                            <h5 class="d-flex align-items-center">
-                                {{ job_info.get('name') if (job_info.get('name')|string).strip() != '' else 'Unnamed Job' }}
-                                <small>
-                                    <span id="job-id-{{ job_info.get('id') }}-status"
-                                          class="badge badge-{{ status_color[job_info.get('status')] }} badge-pill ml-2">{{ job_info.get('status') }}</span>
-                                </small>
-                            </h5>
-                            <div>
-                                <a href="#" id="btn-copy" data-id="{{ job_info.get('id') }}" class="btn btn-sm btn-primary">Copy</a>
-                                <a href="#" id="btn-pin" data-id="{{ job_info.get('id') }}" class="btn btn-sm btn-primary">Pin Job</a>
-                            </div>
-                        </div>
-                        <hr class="my-2">
-                        <p class="m-0 p-0">fqid: {{ job_info.get('fqid') }}</p>
-                        <p class="m-0 p-0">subjobs: {{ job_info.get('subjobs') }}</p>
-                        <p class="m-0 p-0">application: {{ (job_info.get('application')|string).split('(')[0] }}</p>
-                        <p class="m-0 p-0">backend: {{ (job_info.get('backend')|string).split('(')[0] }}</p>
-                        <p class="m-0 p-0">backend.actualCE: {{ job_info.get('backend.actualCE') }}</p>
-                        <p class="m-0 p-0">comment: {{ job_info.get('comment') }}</p>
-                    </div>
-                </div>
-            </div>
-            <div class="col-md-6">
-                <div class="d-flex my-2">
-                    <a href="#" class="btn btn-info mr-1 w-100" data-toggle="modal" data-target="#stdout-modal">Peek
-                        (stdout)</a>
-                    <a href="#" class="btn btn-info ml-1 w-100" data-toggle="modal" data-target="#stderr-modal">Peek
-                        (stderr)</a>
-                </div>
-                <div class="d-flex my-2">
-                    <a href="#" id="btn-freeze" data-id="{{ job_info.get('id') }}" class="btn btn-primary w-100">Freeze
-                        Job</a>
-                    <a href="#" id="btn-unfreeze" data-id="{{ job_info.get('id') }}" class="btn btn-warning mx-2 w-100">UnFreeze
-                        Job</a>
-                </div>
-
-                <div class="d-flex my-2">
-                    <a href="#" id="btn-submit" data-id="{{ job_info.get('id') }}" class="btn btn-primary w-100">Submit
-                        Job</a>
-                    <a href="#" id="btn-kill" data-id="{{ job_info.get('id') }}" class="btn btn-warning mx-2 w-100">Kill
-                        Job</a>
-                    <a href="#" id="btn-remove" data-id="{{ job_info.get('id') }}" class="btn btn-danger w-100">Remove
-                        Job</a>
-                </div>
-                <div class="d-flex my-2">
-                    <a href="#" class="btn btn-dark w-100" data-toggle="modal" data-target="#job-info-modal">Job Info</a>
-                    <a href="{{ url_for('job_edit', job_id=job_info.get('id')) }}" class="btn btn-dark mx-2 w-100">Edit
-                        Job</a>
-                    <a href="{{ url_for('job_export', job_id=job_info.get('id')) }}" class="btn btn-dark w-100">Download</a>
-                </div>
-                <a href="{{ url_for('job_browse', job_id=job_info.get('id')) }}" class="btn btn-block btn-primary">Browse Files</a>
-            </div>
-            <div class="container-fluid mt-4">
-                <div class="row">
-                    <div class="col-md-6 mb-3 d-flex flex-column">
-                        <h3>Job Attributes</h3>
-                        <div class="card flex-grow-1" style="max-height: 500px; overflow: scroll">
-                            <div class="card-body pb-1">
-                                <form>
-                                    <div class="form-group">
-                                        <label for="attribute-select">Select Attribute</label>
-                                        <select data-id="{{ job_info.get('id') }}" class="custom-select"
-                                                id="attribute-select">
-                                            {% for attribute_action in attribute_actions %}
-                                                <option value="{{ attribute_action }}">{{ attribute_action }}</option>
-                                            {% endfor %}
-                                        </select>
-                                    </div>
-                                </form>
-                                <hr class="my-1">
-                                <pre id="attribute-info-box" class="pt-3"></pre>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="col-md-6 mb-3">
-                        <h3>Job Actions</h3>
-                        <div class="card">
-                            <div class="card-body">
-                                <div>
-                                    <div class="form-group">
-                                        <label for="action-select">Select Action</label>
-                                        <select class="custom-select" id="action-select">
-                                            <optgroup label="Methods">
-                                                {% for action in method_actions %}
-                                                    <option value="{{ action }}">{{ action }}</option>
-                                                {% endfor %}
-                                            </optgroup>
-                                            <optgroup label="Attributes">
-                                                {% for action in attribute_actions %}
-                                                    <option value="{{ action }}">{{ action }}</option>
-                                                {% endfor %}
-                                            </optgroup>
-                                        </select>
-                                    </div>
-                                    <div class="form-group">
-                                        <label for="action-argument">Arguments (if any)</label>
-                                        <input type="text" class="form-control" id="action-argument">
-                                    </div>
-                                    <button id="btn-execute" data-id="{{ job_info.get('id') }}"  class="btn btn-primary btn-block">Execute
-                                    </button>
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-            <div class="container-fluid">
-                <div class="row">
-                    <div class="col">
-                        <div class="mb-2 d-flex align-items-center justify-content-between">
-                            <h3 class="my-0 d-inline-block">Subjobs</h3><a href="{{ url_for("subjobs_page", job_id=job_info.get('id')) }}">Explore All Subjobs</a>
-                        </div>
-                        <div class="row">
-                            <div class="col-lg">
-                                {# Statistics Card - Running #}
-                                <div class="card mx-auto">
-                                    <div class="card-body">
-                                        <h5 class="card-title text-center">Running</h5>
-                                        <hr class="my-1">
-                                        <h2 class="text-center mb-n2" id="stat-running"></h2>
-                                    </div>
-                                </div>
-                            </div>
-                            <div class="col-lg">
-                                {# Statistics Card - Failed + Killed #}
-                                <div class="card mx-auto my-2 my-lg-0">
-                                    <div class="card-body">
-                                        <h5 class="card-title text-center">Failed + Killed</h5>
-                                        <hr class="my-1">
-                                        <h2 class="text-center mb-n2"
-                                            id="stat-failed-killed"></h2>
-                                    </div>
-                                </div>
-                            </div>
-                            <div class="col-lg">
-                                {# Statistics Card - Completing #}
-                                <div class="card mx-auto">
-                                    <div class="card-body">
-                                        <h5 class="card-title text-center">Completing</h5>
-                                        <hr class="my-1">
-                                        <h2 class="text-center mb-n2"
-                                            id="stat-completing"></h2>
-                                    </div>
-                                </div>
-                            </div>
-                            <div class="col-lg">
-                                {# Statistics Card - Failed #}
-                                <div class="card mx-auto my-2 my-lg-0">
-                                    <div class="card-body">
-                                        <h5 class="card-title text-center">Completed</h5>
-                                        <hr class="my-1">
-                                        <h2 class="text-center mb-n2"
-                                            id="stat-completed"></h2>
-                                    </div>
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!-- Job Info Modal -->
-    <div class="modal fade" id="job-info-modal" tabindex="-1" role="dialog" aria-labelledby="job-info-modal-label"
-         aria-hidden="true">
-        <div class="modal-dialog modal-lg">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title" id="job-info-modal-label">Job #{{ job_info.get('id') }} Info</h5>
-                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                        <span aria-hidden="true">&times;</span>
-                    </button>
-                </div>
-                <div class="modal-body">
-                    <pre>{{ full_print_info if full_print_info != None }}</pre>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!-- stdout Modal -->
-    <div class="modal fade" id="stdout-modal" tabindex="-1" role="dialog" aria-labelledby="stdout-modal-label"
-         aria-hidden="true">
-        <div class="modal-dialog modal-lg">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title" id="stdout-modal-label">Job #{{ job_info.get('id') }} stdout {{ " - File does not exist" if stdout == None }}</h5>
-                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                        <span aria-hidden="true">&times;</span>
-                    </button>
-                </div>
-                <div class="modal-body">
-                    {{ stdout if stdout != None }}
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!-- stderr Modal -->
-    <div class="modal fade" id="stderr-modal" tabindex="-1" role="dialog" aria-labelledby="stderr-modal-label"
-         aria-hidden="true">
-        <div class="modal-dialog modal-lg">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title" id="stderr-modal-label">Job #{{ job_info.id }} stderr {{ " - File does not exist" if stderr == None }}</h5>
-                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                        <span aria-hidden="true">&times;</span>
-                    </button>
-                </div>
-                <div class="modal-body">
-                    {{ stderr if stderr != None }}
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-                </div>
-            </div>
-        </div>
-    </div>
-{% endblock content %}
-
-{% block footer %}
-    <script defer src="{{ url_for('static', filename='js/job.js') }}"></script>
-{% endblock footer %}
diff --git a/ganga/GangaGUI/gui/templates/job_dir.html b/ganga/GangaGUI/gui/templates/job_dir.html
deleted file mode 100644
index 4213ca92e9..0000000000
--- a/ganga/GangaGUI/gui/templates/job_dir.html
+++ /dev/null
@@ -1,39 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    <div class="container">
-        <h3>Job {{ job_id }} Directory</h3>
-        <hr>
-        <div class="d-flex justify-content-between align-items-center mb-3">
-            <p class=" my-0 py-0 d-inline"><b>Current location:</b> {{ abs_path }}</p>
-            <div>
-                <a class="btn btn-primary btn-sm" href="{{ url_for('job_page', job_id=job_id) }}">Job page</a>
-                <a class="btn btn-primary btn-sm" href="{{ url_for('job_browse', job_id=job_id, path=back_path) }}">Go
-                back</a>
-            </div>
-        </div>
-        <div class="row">
-            <div class="col">
-                <table class="table table-striped table-bordered text-center table-responsive-sm">
-                    <thead>
-                    <tr>
-                        <th class="align-middle" scope="col">Type</th>
-                        <th class="align-middle" scope="col">Name</th>
-                    </tr>
-                    </thead>
-                    <tbody>
-                    {% for file_info in files_info %}
-                        <tr>
-                            <th class="align-middle px-3 font-weight-normal"
-                                style="width: 1%">{{ 'Directory' if file_info.get('directory') else 'File' }}</th>
-                            <td class="align-middle text-left"><a
-                                    href="{{ (request.path + '/' if request.path != '/' else '') + file_info.get('file') }}"
-                                    class="btn-link">{{ file_info.get('file') }}</a></td>
-                        </tr>
-                    {% endfor %}
-                    </tbody>
-                </table>
-            </div>
-        </div>
-    </div>
-{% endblock content %}
diff --git a/ganga/GangaGUI/gui/templates/jobs.html b/ganga/GangaGUI/gui/templates/jobs.html
deleted file mode 100644
index 3dcc3a338c..0000000000
--- a/ganga/GangaGUI/gui/templates/jobs.html
+++ /dev/null
@@ -1,144 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    
-    <div class="col">
-        <h3 class="text-gray-900">Jobs Repository</h3>
-        <hr>
-        <div class="row">
-            <div class="form-group col-md-9">
-                <label for="search" class="text-gray-900">Search Job</label>
-                <input type="text" id="SearchJob" class="form-control" placeholder="Search Job">
-            </div>
-            <div class="form-group col-md-3">
-                <label class="d-none d-md-block" for="filter-button">&nbsp;</label>
-                <button id="SearchButton" type="submit" class="btn btn-block btn-primary">Search</button>
-            </div>
-        </div>
-        <form class="mb-4 mb-md-0" action="{{ url_for('jobs_page', page=current_page) }}" method="post">
-            <div class="form-row">
-                <div class="col-md-2">
-                    <div class="form-group">
-                        <label for="jobs-per-page" class="text-gray-900">Jobs Per Page</label>
-                        <select name="jobs-per-page" class="form-control custom-select" id="jobs-per-page">
-                            {% for n in [10, 20, 40, 80] %}
-                                <option {{ 'selected' if session['jobs_per_page'] == n }} value="{{ n }}">{{ n }}</option>
-                            {% endfor %}
-                        </select>
-                    </div>
-                </div>
-                <div class="col-md-3">
-                    <div class="form-group">
-                        <label for="job-status" class="text-gray-900">Job Status</label>
-                        <select name="job-status" class="form-control custom-select" id="job-status">
-                            <option value="any">Any</option>
-                            {% for s in ['New', 'Running', 'Completed', 'Failed', 'Killed'] %}
-                                <option {{ 'selected' if session['jobs_filter']['status'] == s|lower }}  value="{{ s|lower }}">{{ s }}</option>
-                            {% endfor %}
-                        </select>
-                    </div>
-                </div>
-                <div class="col-md-3">
-                    <div class="form-group">
-                        <label for="job-application" class="text-gray-900">Job Application</label>
-                        <select name="job-application" class="form-control custom-select" id="job-application">
-                            <option value="any">Any</option>
-                            {% for a in applications %}
-                                <option {{ 'selected' if session['jobs_filter']['application'] == a }} value="{{ a }}">{{ a }}</option>
-                            {% endfor %}
-                        </select>
-                    </div>
-                </div>
-                <div class="col-md-3">
-                    <div class="form-group">
-                        <label for="job-backend" class="text-gray-900">Job Backend</label>
-                        <select name="job-backend" class="form-control custom-select" id="job-backend">
-                            <option value="any">Any</option>
-                            {% for b in backends %}
-                                <option {{ 'selected' if session['jobs_filter']['backend'] == b }} value="{{ b }}">{{ b }}</option>
-                            {% endfor %}
-                        </select>
-                    </div>
-                </div>
-                <div class="col-md-1">
-                    <label class="d-none d-md-block" for="filter-button">&nbsp;</label>
-                    <button type="submit" id="filter-button" class="btn btn-primary btn-block">Apply</button>
-                </div>
-            </div>
-        </form>
-        <div id="users">
-        <table id="dtBasicExample" class="table table-striped table-bordered text-center table-responsive-sm">
-            <thead>
-            <tr>
-                <th class="align-middle" scope="col">ID</th>
-                <th class="align-middle" scope="col">Status<i class="align middle material-icons right"></i></th>
-                <th class="align-middle" scope="col">Name</th>
-                <th class="align-middle" scope="col">Subjobs</th>
-                <th class="align-middle" scope="col">Application</th>
-                <th class="align-middle" scope="col">Backend</th>
-                <th class="align-middle" scope="col">Action</th>
-                <th class="align-middle" scope="col">Subjobs Info</th>
-            </tr>
-            </thead>
-            <tbody class="list">
-            {% for j in jobs_info %}
-                <tr class="job" id="job-{{ j.get('id') }}" data-id="{{ j.get('id') }}" data-status="{{ j.get('status') }}">
-                    <td class="align-middle" scope="row">{{ j.get('id') }}</td>
-                    <td class="align-middle"><span id="job-id-{{j.id}}-status"
-                        class="badge badge-{{ status_color[j.get('status')] }} badge-pill">{{ j.get('status') }}</span></td>
-                    <td class="align-middle">{{ j.get('name') if (j.get('name')|string).strip() != '' else 'Unnamed Job' }}</td>
-                    <td class="align-middle">{{ j.get('subjobs') }}</td>
-                    <td class="align-middle text-break">{{ (j.get('application')|string).split('(')[0] }}</td>
-                    <td class="align-middle text-break">{{ (j.get('backend')|string).split('(')[0] }}</td>
-                    <td class="align-middle"><a href="{{ url_for('job_page', job_id=j.get('id')) }}"
-                                                    class="btn btn-sm btn-primary">Job Info</a></td>
-                    {% if j.get('subjobs') != '0' %}
-                        <td class="align-middle"><a href="{{ url_for('subjobs_page', job_id=j.get('id')) }}"
-                                        class="btn btn-sm btn-primary">
-                                        Subjobs Info({{ j.get('subjobs') }})
-                                    </a></td>
-                    {% else %}
-
-                        <td class="align-middle text-break">No Subjobs</td>       
-                    {% endif %} 
-
-                </tr>
-            {% endfor %}
-            </tbody>
-        </table>
-    </div>
-        <nav class="d-flex justify-content-center" >
-            <ul class="pagination m-auto" style="overflow: scroll;">
-                <li class="page-item {{ 'disabled' if current_page <= 0 }}"><a class="page-link"
-                                                                                           href="{{ url_for('jobs_page', page=current_page - 1) }}">Previous</a>
-                </li>
-                {% for i in range(number_of_pages) %}
-                    <li class="page-item {{ 'active' if current_page == i }}"><a class="page-link"
-                                                 href="{{ url_for('jobs_page', page=i) }}">{{ i + 1 }}</a></li>
-                {% endfor %}
-                <li class="page-item {{ 'disabled' if current_page >= number_of_pages-1 }}"><a
-                            class="page-link" href="{{ url_for('jobs_page', page=current_page + 1) }}">Next</a></li>
-            </ul>
-        </nav>
-    </div>
-    
-{% endblock content %}
-
-{% block footer %}
-    <script type="text/javascript">
-        $(document).ready(function () {
-        var table= $('#dtBasicExample').DataTable({
-            "paging": false,
-            "dom": '<"top"i>rt<"bottom"><"clear">',
-            "info": false
-
-            });
-        $('#SearchButton').on( 'keyup click', function () {
-            table.search($('#SearchJob').val()).draw();
-        });
-        $('.dataTables_length').addClass('bs-select');
-        });
-        
-    </script>
-    <script defer src="{{ url_for('static', filename='js/jobs.js') }}"></script>
-{% endblock footer %}
diff --git a/ganga/GangaGUI/gui/templates/login.html b/ganga/GangaGUI/gui/templates/login.html
deleted file mode 100644
index a0c0ed2a99..0000000000
--- a/ganga/GangaGUI/gui/templates/login.html
+++ /dev/null
@@ -1,110 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <!-- Meta Tags -->
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
-    <!-- Bootstrap CSS -->
-    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
-    
-   
-
-    <!-- Title -->
-    <title>{{ title + ' - Ganga GUI' if title else 'Ganga GUI' }}</title>
-
-    
-</head>
-<body id="page-top">
-    <div id="wrapper">
-        
-
-        <div id="content-wrapper" class="d-flex flex-column">
-            <div id="content">
-                <nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
-                    <button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
-                        <i class="fa fa-bars"></i>
-                    </button>
-                    <ul class="navbar-nav ml-auto">
-                        <li class="nav-item dropdown no-arrow">
-                            <img width="150" height="42" src="{{ url_for('static', filename='img/logo.svg') }}">
-                        </li>
-                    </ul>
-                </nav>
-                {% with messages = get_flashed_messages(with_categories=true) %}
-                    {% if messages %}
-                        {% for category, message in messages %}
-                            <div class="alert alert-{{ category }} btn-block" style="border-radius: 0" role="alert">
-                                {{ message }}
-                            </div>
-                        {% endfor %}
-                    {% endif %}
-                {% endwith %}
-           
-                
-                
-            <div class="container-fluid">
-                <div class="row justify-content-center">
-                    <div class="col-11 col-md-6 justify-content-center">
-
-                            <div class="row pb-4 pt-3 pr-2 pl-2 justify-content-center border rounded">
-                                <h3 class="p-0 m-0"><b>LOGIN</b></h3>
-                                <!-- Login form -->
-                                <div class="col-12">
-                                    <p id="error" class="mb-2 text-center text-danger"></p>
-                                    <form id="login-form" method="post">
-                                        <div class="form-group">
-                                            <select name="username" id="username" class="custom-select" required>
-                                                <!-- Create options using the users available in the database -->
-                                                {% for user in users %}
-                                                <option value="{{ user.user }}">{{ user.user }} (Role={{ user.role }})</option>
-                                                {% endfor %}
-                                            </select>
-                                        </div>
-                                        <div class="form-group">
-                                            <input type="password" id="password" class="form-control" name="password"
-                                                   placeholder="Enter Password"
-                                                   required>
-                                        </div>
-                                        <button id="btn-submit" class="btn btn-block btn-primary">Submit</button>
-                                    </form>
-                                </div>
-                            </div>
-                    </div>
-                </div>
-                
-            </div>
-        </div>
-        </div>
-           
-
-      
-    </div> 
-
-    
-    <a class="scroll-to-top rounded" href="#page-top">
-        <i class="fas fa-angle-up"></i>
-    </a>
-   
-
-  
-
-<!-- Javascript files -->
-<script defer src="{{ url_for('static', filename='js/login.js') }}"></script>
-
-<!-- jQuery first, then Popper.js, then Bootstrap JS -->
-<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
-        integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
-        crossorigin="anonymous"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
-        integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
-        crossorigin="anonymous"></script>
-<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
-        integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
-        crossorigin="anonymous"></script>
-
-
-
-
-</body>
-</html>
diff --git a/ganga/GangaGUI/gui/templates/logs.html b/ganga/GangaGUI/gui/templates/logs.html
deleted file mode 100644
index 5d9b04bad7..0000000000
--- a/ganga/GangaGUI/gui/templates/logs.html
+++ /dev/null
@@ -1,31 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    
-    <h3 class="text-gray-900">Ganga Log</h3>
-    <hr>
-    <div class="row">
-        <div class="col">
-            <pre class="border rounded p-2 p-md-3" style="max-height: 80vh;">
-            {{ ganga_log_data }}</pre>
-        </div>
-    </div>
-    <h3 class="mt-3">GUI Access Log</h3>
-    <hr>
-    <div class="row">
-        <div class="col">
-            <pre class="border rounded p-2 p-md-3" style="max-height: 80vh;">
-            {{ gui_accesslog_data }}
-            </pre>
-            </div>
-        </div>
-        <h3 class="mt-3">GUI Error Log</h3>
-        <hr>
-        <div class="row">
-            <div class="col">
-                <pre class="border rounded p-2 p-md-3" style="max-height: 80vh;">
-                {{ gui_errorlog_data }}</pre>
-            </div>
-        </div>
-   
-{% endblock content %}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/templates/plugin.html b/ganga/GangaGUI/gui/templates/plugin.html
deleted file mode 100644
index f6a18bfac4..0000000000
--- a/ganga/GangaGUI/gui/templates/plugin.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    <div class="container-fluid px-md-5">
-        <h3>Docstring - {{ plugin_info.get('name') }}</h3>
-        <hr>
-        <div class="row">
-            <div class="col">
-                <pre class="border rounded p-2 p-md-3">
-                {{ plugin_info.get('docstring') }}
-            </pre>
-            </div>
-        </div>
-    </div>
-{% endblock content %}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/templates/plugins.html b/ganga/GangaGUI/gui/templates/plugins.html
deleted file mode 100644
index c1911225dc..0000000000
--- a/ganga/GangaGUI/gui/templates/plugins.html
+++ /dev/null
@@ -1,39 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    
-    <h3 class="text-gray-900">Plugins</h3>
-    <hr>
-    <div class="row justify-content-center">
-        <div class="col-12">
-            <div class="accordion" id="config">
-                <div class="list-group">
-                    {% for category in plugins_info %}
-                        
-                        <a href="#"
-                            class="list-group-item d-flex justify-content-between font-weight-medium align-items-center list-group-item-action {{ 'rounded-bottom' if loop.last }}"
-                            data-toggle="collapse"
-                            data-target="#collapse-plugin-{{ category }}" aria-expanded="true"
-                            aria-controls="collapse-plugin-{{ category }}">
-                            {{ category }}
-                        </a>
-                        <div id="collapse-plugin-{{ category }}"
-                            class="collapse border-left border-right {{ 'border-bottom rounded-bottom' if loop.last }}"
-                            data-parent="#config">
-                            <div class="card-body">
-                                <ul>
-                                    {% for plugin in plugins_info[category] %}
-                                        <li><a href="{{ url_for('plugin_page', plugin_name=plugin) }}">{{ plugin }}</a></li>
-                                    {% endfor %}
-                                </ul>
-                            </div>
-                        </div>
-                    {% endfor %}
-                </div>
-            </div>
-        </div>
-    </div>
-         
-    
-{% endblock content %}
-
diff --git a/ganga/GangaGUI/gui/templates/queue.html b/ganga/GangaGUI/gui/templates/queue.html
deleted file mode 100644
index a63730567f..0000000000
--- a/ganga/GangaGUI/gui/templates/queue.html
+++ /dev/null
@@ -1,154 +0,0 @@
-{% extends 'base.html' %}
-{% block content %}
-    <div class="d-sm-flex align-items-center justify-content-between mb-4">
-        <div class="h3 mb-0 text-gray-800">Queues</div>
-    </div>
-    <div class="row">
-        <div class="col-md-6">
-            <div class="card shadow mb-4">
-                <div class="card-header py-3">
-                    <h6 class="m-0 font-weight-bold text-primary">Ganga User Threads</h6>
-                </div>
-                <div class="card-body">
-                    <table class="table table-striped table-bordered text-center table-responsive-sm">
-                        <thead>
-                            <tr>
-                                <th class="align-middle" scope="col">Name</th>
-                                <th class="align-middle" scope="col">Command</th>
-                                <th class="align-middle" scope="col">Timeout</th>
-                            </tr>
-                        </thead>
-                        <tbody>
-                        {% for q in queue_info_list %}
-                            <tr>
-                                <td class="align-middle" scope="row">{{ q['name_user'] }}</td>
-                                <td class="align-middle">{{ q['user_condition'] }}</td>
-                                <td class="align-middle">{{ q['user_timeout'] }}</td>
-                            </tr>
-                        {% endfor %}
-                        </tbody>
-                    </table>
-                </div>
-            </div>
-        </div>
-        <div class="col-md-6">
-            <div class="card shadow mb-4">
-                <div class="card-header py-3">
-                    <h6 class="m-0 font-weight-bold text-primary">Ganga Monitoring Threads</h6>
-                </div>
-                <div class="card-body">
-                    <table class="table table-striped table-bordered text-center table-responsive-sm">
-                        <thead>
-                            <tr>
-                                <th class="align-middle" scope="col">Name</th>
-                                <th class="align-middle" scope="col">Command</th>
-                                <th class="align-middle" scope="col">Timeout</th>
-                            </tr>
-                        </thead>
-                        <tbody>
-                        {% for m in queue_info_list %}
-                            <tr>
-                                <td class="align-middle" scope="row">{{ m['name_monitor'] }}</td>
-                                <td class="align-middle">{{ m['monitor_condition'] }}</td>
-                                <td class="align-middle">{{ m['monitor_timeout'] }}</td>
-                            </tr>
-                        {% endfor %}
-                        </tbody>
-                    </table>
-                </div>
-            </div>
-        </div>
-    </div>
-    <div class="row">
-        <div class="col-md-6">
-            <div class="card shadow mb-4">
-                <div class="card-header py-3">
-                    <h6 class="m-0 font-weight-bold text-primary">Ganga User Queue</h6>
-                </div>
-                <div class="card-body">
-                    {% for uq in queue_info_list %}
-                        <p>{{ uq['user_threadpool'] }}</p>
-                    {% endfor %}
-                </div>
-            </div>
-        </div>
-        <div class="col-md-6">
-            <div class="card shadow mb-4">
-                <div class="card-header py-3">
-                    <h6 class="m-0 font-weight-bold text-primary">Ganga Monitoring Queue</h6>
-                </div>
-                <div class="card-body">
-                    {% for mq in queue_info_list %}
-                        <p>{{ mq['monitoring_threadpool'] }}</p>
-                    {% endfor %}
-                </div>
-            </div>
-        </div>
-    </div>
-    <div class="row">
-        <div class="container-fluid" id="data-container">
-
-        </div>
-    </div>
-    <div class="row mt-4">
-            <div class="col-lg"></div>
-    </div>
-   
-{% endblock content %}
-{% block footer %}
-    <script>
-        var chart;
-
-        function requestData()
-        {
-            // Ajax call to get the Data from Flask
-            var requests = $.get('/api/queue/chart');
-
-
-            var tm = requests.done(function (result)
-            {
-                var series = chart.series[0],
-                    shift = series.data.length > 20;
-
-                // add the point
-                chart.series[0].addPoint(result, true, shift);
-
-                // call it again after one second
-                setTimeout(requestData, 2000);
-            });
-        }
-
-        $(document).ready(function() {
-            chart = new Highcharts.Chart({
-                chart: {
-                    renderTo: 'data-container',
-                    defaultSeriesType: 'spline',
-                    events: {
-                        load: requestData
-                    }
-                },
-                title: {
-                    text: 'Queue'
-                },
-                xAxis: {
-                    type: 'datetime',
-                    tickPixelInterval: 150,
-                    maxZoom: 20 * 1000
-                },
-                yAxis: {
-                    minPadding: 0.2,
-                    maxPadding: 0.2,
-                    title: {
-                        text: 'Worker_Threads',
-                        margin: 80
-                    }
-                },
-                series: [{
-                    name: 'Time',
-                    data: []
-                }]
-            });
-
-        });
-    </script>
-{% endblock footer %}
diff --git a/ganga/GangaGUI/gui/templates/runfile.html b/ganga/GangaGUI/gui/templates/runfile.html
deleted file mode 100644
index c643094410..0000000000
--- a/ganga/GangaGUI/gui/templates/runfile.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    
-    <h3 class="text-gray-900">Runfile</h3>
-    <hr class="my-2">
-    <form method="post">
-        <div class="form-group">
-            <label for="runfile" class="text-gray-900">Write python script below which will be executed using the runfile function.</label>
-            <textarea class="form-control" id="runfile" name="runfile-data" rows="20"></textarea>
-        </div>
-        <div class="d-flex justify-content-center">
-            <button class="btn btn-primary" type="submit">Execute</button>
-        </div>
-    </form>
-    
-{% endblock content %}
diff --git a/ganga/GangaGUI/gui/templates/storage.html b/ganga/GangaGUI/gui/templates/storage.html
deleted file mode 100644
index 11c42b128f..0000000000
--- a/ganga/GangaGUI/gui/templates/storage.html
+++ /dev/null
@@ -1,77 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    
-    <h3 class="text-gray-900">Storage</h3>
-    <div class="row mt-3">
-        <div class="col">
-            <form method=post enctype=multipart/form-data>
-                <div class="input-group mb-3">
-                    <div class="custom-file">
-                        <input type="file" name="storagefile" class="custom-file-input" id="storagefile-input">
-                        <label class="custom-file-label" id="storagefile-input-label" for="storagefile-input"
-                                aria-describedby="storagefileInputAddon">Choose file</label>
-                    </div>
-                    <div class="input-group-append">
-                        <input class="input-group-text" id="storagefileInputAddon" type=submit value=Upload>
-                    </div>
-                </div>
-            </form>
-        </div>
-    </div>
-    <hr class="my-0 mb-2">
-    <div class="d-flex justify-content-between align-items-center mb-3">
-        <p class=" my-0 py-0 d-inline text-gray-900"><b>Current location:</b> {{ abs_path }}</p>
-        <div>
-            <a class="btn btn-primary btn-sm" href="{{ url_for('storage_page', path=back_path) }}">Go
-                    back</a>
-        </div>
-    </div>
-    <div class="row">
-        <div class="col">
-            <table class="table table-striped table-bordered text-center table-responsive-sm">
-                <thead>
-                <tr>
-                    <th class="align-middle" scope="col">Type</th>
-                    <th class="align-middle" scope="col">Name</th>
-                </tr>
-                </thead>
-                <tbody>
-                {% for file_info in files_info %}
-                    <tr>
-                        <th class="align-middle px-3 font-weight-normal"
-                            style="width: 1%">{{ 'Directory' if file_info.get('directory') else 'File' }}</th>
-                        <td class="align-middle text-left"><a
-                            href="{{ (request.path + '/' if request.path != '/' else '') + file_info.get('file') }}"
-                            class="btn-link">{{ file_info.get('file') }}</a></td>
-                    </tr>
-                {% endfor %}
-                </tbody>
-            </table>
-        </div>
-    </div>
-   
-{% endblock content %}
-
-{% block footer %}
-    <script>
-
-        // Add event listener to update the runfile label to the selected file
-        storagefileInput = document.querySelector('#storagefile-input');
-        storagefileInput.addEventListener('change', updateStorageFilename);
-
-        // For updating the storage upload input label to the filename of selected file
-        function updateStorageFilename(e) {
-
-            // Upload Input
-            const storagefileInput = e.target;
-
-            // Label to be update
-            const storagefileLabel = document.querySelector("#storagefile-input-label");
-
-            // Update label
-            storagefileLabel.innerHTML = storagefileInput.files[0].name;
-        }
-
-    </script>
-{% endblock footer %}
diff --git a/ganga/GangaGUI/gui/templates/subjob.html b/ganga/GangaGUI/gui/templates/subjob.html
deleted file mode 100644
index ee9f3156b3..0000000000
--- a/ganga/GangaGUI/gui/templates/subjob.html
+++ /dev/null
@@ -1,132 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    <div class="container-fluid px-md-5">
-        <div class="row d-flex justify-content-center align-items-center">
-            <div class="col-md-6 mb-3 mb-md-0">
-                <div class="card" id="subjob-info" data-job_id="{{ job_id }}" data-subjob_id="{{ subjob_info.get('id') }}">
-                    <div class="card-body">
-                        <div class="d-flex justify-content-between">
-                            <h5 class="d-flex align-items-center">
-                                {{ subjob_info.get('name') if (subjob_info.get('name')|string).strip() != '' else 'Unnamed Subjob' }}
-                                <small>
-                                    <span id="subjob-id-{{ subjob_info.get('id') }}-status"
-                                          class="badge badge-{{ status_color[subjob_info.get('status')] }} badge-pill ml-2">{{ subjob_info.get('status') }}</span>
-                                </small>
-                            </h5>
-                            <div>
-                                <a href="#" id="btn-copy" data-job_id="{{ job_id }}" data-subjob_id="{{ subjob_info.get('id') }}" class="btn btn-sm btn-primary">Copy</a>
-                            </div>
-                        </div>
-                        <hr class="my-2">
-                        <p class="m-0 p-0">fqid: {{ subjob_info.get('fqid') }}</p>
-                        <p class="m-0 p-0">application: {{ (subjob_info.get('application')|string).split('(')[0] }}</p>
-                        <p class="m-0 p-0">backend: {{ (subjob_info.get('backend')|string).split('(')[0] }}</p>
-                        <p class="m-0 p-0">backend.actualCE: {{ subjob_info.get('backend.actualCE') }}</p>
-                        <p class="m-0 p-0">comment: {{ subjob_info.get('comment') }}</p>
-                    </div>
-                </div>
-            </div>
-            <div class="col-md-6">
-                <div class="d-flex my-2">
-                    <a href="#" class="btn btn-info mr-1 w-100" data-toggle="modal" data-target="#stdout-modal">Peek
-                        (stdout)</a>
-                    <a href="#" class="btn btn-info ml-1 w-100" data-toggle="modal" data-target="#stderr-modal">Peek
-                        (stderr)</a>
-                </div>
-                <div class="d-flex my-2">
-                    <a href="#" class="btn btn-dark w-100" data-toggle="modal" data-target="#job-info-modal">Job Info</a>
-                </div>
-                <a href="{{ url_for('job_browse', job_id=job_id, path=browse_path) }}" class="btn btn-block btn-primary">Browse Files</a>
-            </div>
-            <div class="container-fluid mt-4">
-                <div class="row">
-                    <div class="col mb-3 d-flex flex-column">
-                        <h3>Subjob Attributes</h3>
-                        <div class="card flex-grow-1" style="max-height: 500px; overflow: scroll">
-                            <div class="card-body pb-1">
-                                <form>
-                                    <div class="form-group">
-                                        <label for="attribute-select">Select Attribute</label>
-                                        <select data-job_id="{{ job_id }}" data-subjob_id="{{ subjob_info.get('id') }}" class="custom-select"
-                                                id="attribute-select">
-                                            {% for attribute_action in attribute_actions %}
-                                                <option value="{{ attribute_action }}">{{ attribute_action }}</option>
-                                            {% endfor %}
-                                        </select>
-                                    </div>
-                                </form>
-                                <hr class="my-1">
-                                <pre id="attribute-info-box" class="pt-3"></pre>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!-- Subjob Info Modal -->
-    <div class="modal fade" id="job-info-modal" tabindex="-1" role="dialog" aria-labelledby="job-info-modal-label"
-         aria-hidden="true">
-        <div class="modal-dialog modal-lg">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title" id="job-info-modal-label">Subjob #{{ subjob_info.get('id') }} Info</h5>
-                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                        <span aria-hidden="true">&times;</span>
-                    </button>
-                </div>
-                <div class="modal-body">
-                    <pre>{{ full_print_info if full_print_info != None }}</pre>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!-- stdout Modal -->
-    <div class="modal fade" id="stdout-modal" tabindex="-1" role="dialog" aria-labelledby="stdout-modal-label"
-         aria-hidden="true">
-        <div class="modal-dialog modal-lg">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title" id="stdout-modal-label">Subjob #{{ subjob_info.get('id') }} stdout {{ " - File does not exist" if stdout == None }}</h5>
-                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                        <span aria-hidden="true">&times;</span>
-                    </button>
-                </div>
-                <div class="modal-body">
-                    {{ stdout if stdout != None }}
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-                </div>
-            </div>
-        </div>
-    </div>
-    <!-- stderr Modal -->
-    <div class="modal fade" id="stderr-modal" tabindex="-1" role="dialog" aria-labelledby="stderr-modal-label"
-         aria-hidden="true">
-        <div class="modal-dialog modal-lg">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title" id="stderr-modal-label">Subjob #{{ subjob_info.get('id') }} stderr {{ " - File does not exist" if stderr == None }}</h5>
-                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                        <span aria-hidden="true">&times;</span>
-                    </button>
-                </div>
-                <div class="modal-body">
-                    {{ stderr if stderr != None }}
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-                </div>
-            </div>
-        </div>
-    </div>
-{% endblock content %}
-
-{% block footer %}
-    <script defer src="{{ url_for('static', filename='js/subjob.js') }}"></script>
-{% endblock footer %}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/templates/subjob_dir.html b/ganga/GangaGUI/gui/templates/subjob_dir.html
deleted file mode 100644
index 588b37b554..0000000000
--- a/ganga/GangaGUI/gui/templates/subjob_dir.html
+++ /dev/null
@@ -1,37 +0,0 @@
-{% extends 'base.html' %}
-{% block content %}
-    <div class="container">
-        <h3>Subjob {{ subjob_id }} of Job {{ job_id }} Directory</h3>
-        <hr>
-        <div class="d-flex justify-content-between align-items-center mb-3">
-            <p class=" my-0 py-0 d-inline"><b>Current location:</b> {{ abs_path }}</p>
-            <a class="btn btn-primary btn-sm" href="{{ url_for('browse_job', job_id=job_id, path=back_path) }}">Go
-                back</a>
-        </div>
-        <div class="row">
-            <div class="col">
-                <table class="table table-striped table-bordered text-center table-responsive-sm">
-                    <thead>
-                    <tr>
-                        <th class="align-middle" scope="col">Type</th>
-                        <th class="align-middle" scope="col">Name</th>
-                    </tr>
-                    </thead>
-                    <tbody>
-                    {% for file in files_info %}
-                        <tr>
-                            <th class="align-middle px-3 font-weight-normal"
-                                style="width: 1%">{{ 'Directory' if file.directory else 'File' }}</th>
-                            <td class="align-middle text-left"><a
-                                    href="{{ (request.path + '/' if request.path != '/' else '') + file.file }}"
-                                    class="btn-link">{{ file.file }}</a></td>
-                        </tr>
-                    {% endfor %}
-                    </tbody>
-                </table>
-            </div>
-        </div>
-    </div>
-{% endblock content %}
-{% block footer %}
-{% endblock footer %}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/templates/subjobs.html b/ganga/GangaGUI/gui/templates/subjobs.html
deleted file mode 100644
index 751d4f872e..0000000000
--- a/ganga/GangaGUI/gui/templates/subjobs.html
+++ /dev/null
@@ -1,104 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    <div class="container-fluid">
-        <div class="col">
-            <h3>Subjobs Repository of Job {{ job_id }}</h3>
-            <hr>
-            <form class="mb-4 mb-md-0" action="{{ url_for('subjobs_page', page=current_page, job_id=job_id) }}" method="post">
-                <div class="form-row">
-                    <div class="col-md-2">
-                        <div class="form-group">
-                            <label for="subjobs-per-page">Subjobs Per Page</label>
-                            <select name="subjobs-per-page" class="form-control custom-select" id="subjobs-per-page">
-                                {% for n in [10, 20, 40, 80] %}
-                                    <option {{ 'selected' if session['subjobs_per_page'] == n }} value="{{ n }}">{{ n }}</option>
-                                {% endfor %}
-                            </select>
-                        </div>
-                    </div>
-                    <div class="col-md-3">
-                        <div class="form-group">
-                            <label for="subjob-status">Subjob Status</label>
-                            <select name="subjob-status" class="form-control custom-select" id="subjob-status">
-                                    <option value="any">Any</option>
-                                {% for s in ['New', 'Running', 'Completed', 'Failed', 'Killed'] %}
-                                    <option {{ 'selected' if session["subjobs_filter"]['status'] == s|lower }}  value="{{ s|lower }}">{{ s }}</option>
-                                {% endfor %}
-                            </select>
-                        </div>
-                    </div>
-                    <div class="col-md-3">
-                        <div class="form-group">
-                            <label for="subjob-application">Subjob Application</label>
-                            <select name="subjob-application" class="form-control custom-select" id="subjob-application">
-                                <option value="any">Any</option>
-                                {% for a in applications %}
-                                    <option {{ 'selected' if session["subjobs_filter"]['application'] == a }} value="{{ a }}">{{ a }}</option>
-                                {% endfor %}
-                            </select>
-                        </div>
-                    </div>
-                    <div class="col-md-3">
-                        <div class="form-group">
-                            <label for="subjob-backend">Subjob Backend</label>
-                            <select name="subjob-backend" class="form-control custom-select" id="subjob-backend">
-                                <option value="any">Any</option>
-                                {% for b in backends %}
-                                    <option {{ 'selected' if session["subjobs_filter"]['backend'] == b }} value="{{ b }}">{{ b }}</option>
-                                {% endfor %}
-                            </select>
-                        </div>
-                    </div>
-                    <div class="col-md-1">
-                        <label class="d-none d-md-block" for="filter-button">&nbsp;</label>
-                        <button type="submit" id="filter-button" class="btn btn-primary btn-block">Apply</button>
-                    </div>
-                </div>
-            </form>
-            <table class="table table-striped table-bordered text-center table-responsive-sm">
-                <thead>
-                <tr>
-                    <th class="align-middle" scope="col">fqid</th>
-                    <th class="align-middle" scope="col">Status</th>
-                    <th class="align-middle" scope="col">Name</th>
-                    <th class="align-middle" scope="col">Application</th>
-                    <th class="align-middle" scope="col">Backend</th>
-                    <th class="align-middle" scope="col">Action</th>
-                </tr>
-                </thead>
-                <tbody>
-                {% for sj in subjobs_info %}
-                    <tr class="subjob" id="subjob-{{ sj.get('id') }}" data-job_id="{{ job_id }}" data-id="{{ sj.get('id') }}" data-status="{{ sj.get('status') }}">
-                        <th class="align-middle" scope="row">{{ sj.get('fqid') }}</th>
-                        <td class="align-middle"><span id="subjob-id-{{ sj.get('id') }}-status"
-                                class="badge badge-{{ status_color[sj.get('status')] }} badge-pill">{{ sj.get('status') }}</span></td>
-                        <td class="align-middle">{{ sj.get('name') if (sj.get('name')|string).strip() != '' else 'Unnamed Subjob' }}</td>
-                        <td class="align-middle text-break">{{ (sj.get('application')|string).split('(')[0] }}</td>
-                        <td class="align-middle text-break">{{ (sj.get('backend')|string).split('(')[0] }}</td>
-                        <td class="align-middle"><a href="{{ url_for('subjob_page', job_id=job_id, subjob_id=sj.get('id')) }}"
-                                                    class="btn btn-sm btn-primary">Subjob Info</a></td>
-                    </tr>
-                {% endfor %}
-                </tbody>
-            </table>
-            <nav class="d-flex justify-content-center">
-                <ul class="pagination m-auto" style="overflow: scroll;">
-                    <li class="page-item {{ 'disabled' if current_page <= 0 }}"><a class="page-link"
-                                                                                           href="{{ url_for('subjobs_page', page=current_page - 1, job_id=job_id) }}">Previous</a>
-                    </li>
-                    {% for i in range(number_of_pages) %}
-                        <li class="page-item {{ 'active' if current_page == i }}"><a class="page-link"
-                                                 href="{{ url_for('subjobs_page', page=i, job_id=job_id) }}">{{ i + 1 }}</a></li>
-                    {% endfor %}
-                    <li class="page-item {{ 'disabled' if current_page >= number_of_pages-1 }}"><a
-                            class="page-link" href="{{ url_for('subjobs_page', page=current_page + 1, job_id=job_id) }}">Next</a></li>
-                </ul>
-            </nav>
-        </div>
-    </div>
-{% endblock content %}
-
-{% block footer %}
-    <script defer src="{{ url_for('static', filename='js/subjobs.js') }}"></script>
-{% endblock footer %}
\ No newline at end of file
diff --git a/ganga/GangaGUI/gui/templates/templates.html b/ganga/GangaGUI/gui/templates/templates.html
deleted file mode 100644
index 7b8dd5cfd6..0000000000
--- a/ganga/GangaGUI/gui/templates/templates.html
+++ /dev/null
@@ -1,130 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-    <div class="container-fluid">
-        <div class="col">
-            <h3>Templates Repository</h3>
-            <hr>
-            <form class="mb-4 mb-md-0" action="{{ url_for('templates_page', page=current_page) }}" method="post">
-                <div class="form-row">
-                    <div class="col-md-3">
-                        <div class="form-group">
-                            <label for="templates-per-page">Templates Per Page</label>
-                            <select name="templates-per-page" class="form-control custom-select"
-                                    id="templates-per-page">
-                                {% for n in [10, 20, 40, 80] %}
-                                    <option {{ 'selected' if session['templates_per_page'] == n }}
-                                            value="{{ n }}">{{ n }}</option>
-                                {% endfor %}
-                            </select>
-                        </div>
-                    </div>
-                    <div class="col-md-4">
-                        <div class="form-group">
-                            <label for="template-application">Template Application</label>
-                            <select name="template-application" class="form-control custom-select"
-                                    id="template-application">
-                                <option value="any">Any</option>
-                                {% for a in applications %}
-                                    <option {{ 'selected' if session["templates_filter"]['application'] == a }}
-                                            value="{{ a }}">{{ a }}</option>
-                                {% endfor %}
-                            </select>
-                        </div>
-                    </div>
-                    <div class="col-md-4">
-                        <div class="form-group">
-                            <label for="template-backend">Template Backend</label>
-                            <select name="template-backend" class="form-control custom-select" id="template-backend">
-                                <option value="any">Any</option>
-                                {% for b in backends %}
-                                    <option {{ 'selected' if session["templates_filter"]['backend'] == b }}
-                                            value="{{ b }}">{{ b }}</option>
-                                {% endfor %}
-                            </select>
-                        </div>
-                    </div>
-                    <div class="col-md-1">
-                        <label class="d-none d-md-block" for="filter-button">&nbsp;</label>
-                        <button type="submit" id="filter-button" class="btn btn-primary btn-block">Apply</button>
-                    </div>
-                </div>
-            </form>
-            <table class="table table-striped table-bordered text-center table-responsive-sm">
-                <thead>
-                <tr>
-                    <th class="align-middle" scope="col">ID</th>
-                    <th class="align-middle" scope="col">Name</th>
-                    <th class="align-middle" scope="col">Application</th>
-                    <th class="align-middle" scope="col">Backend</th>
-                    <th class="align-middle" scope="col">Action</th>
-                </tr>
-                </thead>
-                <tbody>
-                {% for t in templates_info %}
-                    <tr class="template" id="template-{{ t.get('id') }}">
-                        <th class="align-middle" scope="row">{{ t.get('id') }}</th>
-                        <td class="align-middle">{{ t.get('name') if (t.get('name')|string).strip() != '' else 'Unnamed Template' }}</td>
-                        <td class="align-middle text-break">{{ (t.get('application')|string).split('(')[0] }}</td>
-                        <td class="align-middle text-break">{{ (t.get('backend')|string).split('(')[0] }}</td>
-                        <td class="align-middle" style="min-width: 20%;">
-                            <div>
-                                <a href="#" data-id="{{ t.get('id') }}"
-                                   class="btn btn-sm btn-primary btn-create my-1 my-md-0">
-                                    Create Job
-                                </a>
-                                <a href="#" data-id="{{ t.get('id') }}" class="btn btn-sm btn-info btn-template-info my-1 my-md-0">
-                                    Info
-                                </a>
-                                <a href="#" data-id="{{ t.get('id') }}" class="btn btn-sm btn-danger btn-delete my-1 my-md-0">
-                                    Delete
-                                </a>
-                            </div>
-                        </td>
-                    </tr>
-                {% endfor %}
-                </tbody>
-            </table>
-            <nav class="d-flex justify-content-center">
-                <ul class="pagination m-auto" style="overflow: scroll;">
-                    <li class="page-item {{ 'disabled' if current_page <= 0 }}"><a class="page-link"
-                                                                                   href="{{ url_for('templates_page', page=current_page - 1) }}">Previous</a>
-                    </li>
-                    {% for i in range(number_of_pages) %}
-                        <li class="page-item {{ 'active' if current_page == i }}"><a class="page-link"
-                                                                                     href="{{ url_for('templates_page', page=i) }}">{{ i + 1 }}</a>
-                        </li>
-                    {% endfor %}
-                    <li class="page-item {{ 'disabled' if current_page >= number_of_pages-1 }}"><a
-                            class="page-link" href="{{ url_for('templates_page', page=current_page + 1) }}">Next</a>
-                    </li>
-                </ul>
-            </nav>
-        </div>
-    </div>
-    <!-- Template Info Modal -->
-    <div class="modal fade" id="template-info-modal" tabindex="-1" role="dialog"
-         aria-labelledby="template-info-modal-label"
-         aria-hidden="true">
-        <div class="modal-dialog modal-lg">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title" id="template-info-modal-label">Template Info: </h5>
-                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                        <span aria-hidden="true">&times;</span>
-                    </button>
-                </div>
-                <div class="modal-body">
-                    <pre id="template-info-box"></pre>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-                </div>
-            </div>
-        </div>
-    </div>
-{% endblock content %}
-
-{% block footer %}
-    <script defer src="{{ url_for('static', filename='js/templates.js') }}"></script>
-{% endblock footer %}
\ No newline at end of file
diff --git a/ganga/GangaGUI/guistate.py b/ganga/GangaGUI/guistate.py
deleted file mode 100644
index 4f8065d84d..0000000000
--- a/ganga/GangaGUI/guistate.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Global API Server, will run in Ganga thread pool
-api_server = None
-
-# Global GUI Server, will start gunicorn server using subprocess.popen
-gui_server = None
-
-def set_api_server(value):
-    global api_server
-    api_server = value
-
-def get_api_server():
-    return api_server
-
-def set_gui_server(value):
-    global gui_server
-    gui_server = value
-
-def get_gui_server():
-    return gui_server
diff --git a/ganga/GangaGUI/start.py b/ganga/GangaGUI/start.py
deleted file mode 100644
index dd484273ab..0000000000
--- a/ganga/GangaGUI/start.py
+++ /dev/null
@@ -1,232 +0,0 @@
-import os
-import string
-import uuid
-import random
-import requests
-import subprocess
-import socket
-from contextlib import closing
-from GangaCore.Core.GangaThread import GangaThread
-from GangaCore.Utility.logging import getLogger
-from GangaGUI.gui.routes import gui, db
-from GangaGUI import guistate
-from GangaGUI.api import internal
-from GangaGUI.gui.routes import User
-
-# Ganga logger
-logger = getLogger()
-
-# Directory just level up from GangaGUI
-ganga_package_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-# GangaThread for Internal API Flask server
-class APIServerThread(GangaThread):
-
-    def __init__(self, name: str, host: str, port: int):
-        super().__init__(name=name)
-        self.host = host
-        self.port = port
-
-    def run(self):
-        try:
-            internal.run(host=self.host, port=self.port)
-        except Exception as err:
-            logger.error(f"Failed to start API Server: {str(err)}")
-
-    def shutdown(self):
-        res = requests.post("http://localhost:{port}/shutdown".format(port=self.port))
-        logger.info(f"{res.status_code} - Success {res.json()['success']}, {res.json()['message']}")
-        if res.status_code == 200:
-            return True
-        return False
-    
-    
-def free_port():
-    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
-        s.bind(('', 0))
-        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        return s.getsockname()[1]
-
-
-def start_gui(*, gui_host: str = "127.0.0.1", gui_port: int = free_port(), internal_port: int = free_port(),
-              password: str = None, only_internal: bool = False):
-    """
-    Start GUI Flask App on a Gunicorn server and API Flask App on a GangaThread
-
-    :param only_internal: bool - will only start the internal API server
-    :param gui_host: str
-    :param gui_port: int
-    :param internal_port: int
-    :param password: str
-
-    Returns (host, port, user, password)
-    Accepts "gui_host", "gui_port", "internal_port" and "password" as arguments.
-
-    By default the "gui_host" is set to "127.0.0.1". It means GUI will be accessible over the network.
-    In order to make to accessible only inside the local machine, please set the host to "localhost" as in start_gui(gui_host="localhost").
-
-    "gui_port" can be set to any free port available (default is 5500)
-    If GUI is to be accessed over the network make sure the firewall allows the specified port.
-
-    "internal_port" can be set to any free port available (default is 5000)
-    "internal_port" is used by the API flask server which run on a Ganga Thread. This server has access to all of the
-    Ganga functions and information. The GUI Server communicates with the API Server over a RESTful interface for querying the data from Ganga.
-    The API server is not accessible from outside the machine, it is only meant to be accessed by the GUI Server.
-    The API server is a weak server and can not be use to deliver GUI over the internet.
-
-    Use the "user" and "password" to log into the GUI or generate token to access the APIs
-
-    The default "user" is "GangaGUIAdmin", and will be created during the first run of the GangaGUI.
-    "GangaGUIAdmin" has the admin rights with respect to GangaGUI ONLY.
-
-    If the "password" is not specified, a random 7 character AlphaNumeric password is auto generated.
-
-    Example Usage:
-    start_gui() -> will return ("127.0.0.1", 5500, "GangaGUIAdmin", "RNDPASS")
-    start_gui(password="mypassword") -> will return ("127.0.0.1", 5500, "GangaGUIAdmin", "mypassword")
-    start_gui(host="127.0.0.1", password="mypassword") -> will return ("127.0.0.1", 5500, "GangaGUIAdmin", "mypassword")
-    start_gui(host="127.0.0.1", port=1234, password="mypassword") -> ("127.0.0.1", 1234, "GangaGUIAdmin", "mypassword")
-    """
-
-    # For when it is called by ganga-gui binary for starting the integrated terminal
-    if os.environ.get('WEB_CLI') is not None or only_internal is not False:
-
-        # Get the internal port to start the API server on
-        if os.environ.get("INTERNAL_PORT") is not None:
-            internal_port = int(os.environ.get("INTERNAL_PORT"))
-
-        # Start internal API server, it is always be meant for internal use by the GUI server
-        api_server = APIServerThread("GangaGUIAPI", "localhost", internal_port)
-        guistate.set_api_server(api_server)
-        api_server.start()
-
-        return True
-
-    # Create default user
-    gui_user, gui_password = create_default_user(password=password)
-
-    # Start internal API server, it is always be meant for internal use by the GUI server
-    api_server = APIServerThread("GangaGUIAPI", "localhost", internal_port)
-    guistate.set_api_server(api_server)
-    api_server.start()
-
-    # Start GUI server
-    gui_server = start_gui_server(gui_host=gui_host, gui_port=gui_port, internal_port=internal_port,
-                                  package_dir=ganga_package_dir)
-    guistate.set_gui_server(gui_server)
-
-    # Display necessary information to the user
-    logger.info(f"GUI Login Details: user='{gui_user.user}', password='{gui_password}'")
-    logger.info(f"You can now access the GUI at http://{gui_host}:{gui_port}")
-    logger.info(f"The internal port for flask server using ganga thread is http://{gui_host}:{internal_port}")
-    logger.info(
-        f"If on a remote system you may need to set up port forwarding to reach the web server. This can be done with 'ssh -D {gui_port} <remote-ip>' from a terminal.")
-
-    return gui_host, gui_port, gui_user.user, gui_password
-
-
-def stop_gui():
-    """Stop API Flask server on a GangaThread and the GUI Flask server running on a Gunicorn server"""
-
-    if guistate.get_api_server() is not None:
-        if guistate.get_api_server().shutdown():
-            guistate.set_api_server(None)
-        else:
-            raise Exception("Error in shutting down the API server.")
-
-    if guistate.get_gui_server() is not None:
-        guistate.get_gui_server().terminate()
-
-
-# ******************** Helper Functions ******************** #
-
-
-def create_default_user(password=None):
-    """
-    Creates default user called GangaGUIAdmin.
-    :param password: str
-    :return: tuple
-    """
-
-    # Database path
-    db_path = gui.config["SQLALCHEMY_DATABASE_URI"].replace("sqlite:///", "")
-
-    if not os.path.exists(db_path):
-        # Create database if does not exist
-        db.create_all()
-        gui_user = User()
-        gui_user.public_id = str(uuid.uuid4())
-        gui_user.user = "GangaGUIAdmin"
-        gui_user.role = "Admin"
-        if password is None:
-            password = ''.join(random.choices(string.ascii_uppercase + string.digits, k=7))
-        gui_user.store_password_hash(password)
-        db.session.add(gui_user)
-        db.session.commit()
-    else:
-        # Store password for GangaGUIAdmin in database
-        gui_user = User.query.filter_by(user="GangaGUIAdmin").first()
-        if gui_user is None:
-            gui_user = User()
-            gui_user.user = "GangaGUIAdmin"
-            gui_user.role = "Admin"
-        if password is None:
-            password = ''.join(random.choices(string.ascii_uppercase + string.digits, k=7))
-        gui_user.store_password_hash(password)
-        gui_user.public_id = str(uuid.uuid4())
-        db.session.add(gui_user)
-        db.session.commit()
-
-    return gui_user, password
-
-
-def start_gui_server(gui_host, gui_port, internal_port, package_dir=ganga_package_dir, web_cli_mode=False,
-                     web_cli_port=None):
-    """
-    Start the GUI server on a Gunicorn server - this is started as a separate process and communicated with the Internal API server running on a GangaThread which has access to Ganga resources.
-
-    :param gui_host: str
-    :param gui_port: str
-    :param internal_port: int or str
-    :param package_dir: str
-    :return: Popen
-    """
-
-    # Start the GUI on a Gunicorn (production ready) server.
-
-    # Set the env for the GUI server
-    gui_env = os.environ.copy()
-    gui_env["INTERNAL_PORT"] = str(internal_port)
-    # If started by ganga-gui binary to start the web cli
-    if web_cli_mode:
-        if web_cli_port is None:
-            raise Exception("Please provide Web CLI Port.")
-        gui_env["WEB_CLI"] = str(True)
-        gui_env["WEB_CLI_PORT"] = str(int(web_cli_port))
-
-    # Log location
-    gui_accesslog_file = gui.config["ACCESS_LOG"]
-    gui_errorlog_file = gui.config["ERROR_LOG"]
-
-    # Start the server
-    gui_server = subprocess.Popen(
-        f"gunicorn --chdir {package_dir} --log-level warning --access-logfile {gui_accesslog_file} --error-logfile {gui_errorlog_file} --bind {gui_host}:{gui_port} wsgi:gui",
-        shell=True, cwd=os.path.dirname(os.path.abspath(__file__)), env=gui_env)
-
-    return gui_server
-
-
-# ******************** EOF ******************** #
-
-# TODO Remove
-# Use this for starting the server for development purposes
-# Development user="GangaGUIAdmin" password="GangaGUIAdmin"
-if __name__ == "__main__":
-    # TODO fix password
-    db.create_all()
-    user = User(public_id=str(uuid.uuid4()), user="GangaGUIAdmin", role="Admin")
-    user.store_password_hash("GangaGUIAdmin")
-    db.session.add(user)
-    db.session.commit()
-    gui.logger.warning("Development server running with debugger active. user='GangaGUIAdmin' password='GangaGUIAdmin'")
-    gui.run(port=5500, debug=True)
diff --git a/ganga/GangaGUI/wsgi.py b/ganga/GangaGUI/wsgi.py
deleted file mode 100644
index 15c520a678..0000000000
--- a/ganga/GangaGUI/wsgi.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""Entry point for the gunicorn server"""
-
-from GangaGUI.gui.routes import gui
diff --git a/setup.py b/setup.py
index a65bcce0cc..f475ce7c18 100644
--- a/setup.py
+++ b/setup.py
@@ -73,26 +73,15 @@ def run(self):
 
 pythonPackages = find_packages('./')
 pythonPackages.append('ganga/GangaRelease')
-pythonPackages.append('ganga/GangaGUI')
 
 
 install_requires = [
     'ipython>=5.0.0',
-    'jedi>=0.17.2',
-    'httplib2>=0.8',
     'absl-py>=0.1.2',
     'google-api-python-client',
     'google-auth-httplib2',
     'google-auth-oauthlib',
     'requests>=2.23.0',
-    'Flask>=1.1.2',
-    'PyJWT~=2.4.0',
-    'Flask-SQLAlchemy>=2.4.3',
-    'gunicorn>=20.0.4',
-    'Flask-Login>=0.5.0',
-    'Flask-SocketIO==4.3.1',
-    'Werkzeug==2.0.3',
-    'SQLAlchemy==1.3.19',
     "docker",
     "pymongo",
     "gdown",
@@ -111,12 +100,10 @@ def run(self):
     author_email='project-ganga-developers@cern.ch',
     license='GPL v2',
     scripts=[
-        'bin/ganga',
-        'bin/ganga-gui'],
+        'bin/ganga'],
     package_dir={
         'ganga': 'ganga',
-        'GangaRelease': 'ganga/GangaRelease',
-        'GangaGUI': 'ganga/GangaGUI'},
+        'GangaRelease': 'ganga/GangaRelease'},
     packages=pythonPackages,
     install_requires=install_requires,
     extras_require={
@@ -141,12 +128,8 @@ def run(self):
             'ReleaseNotes-*',
             'tools/check-new-ganga.py',
             'tools/ganga-cvmfs-install.sh',
-            'tools/ganga-cvmfs-install-dev.sh'],
-        'GangaGUI': [
-            'gui/templates/*.html',
-            'gui/static/css/main.css',
-            'gui/static/js/*.js']},
+            'tools/ganga-cvmfs-install-dev.sh']},
     cmdclass={
         'tests': RunTestsCommand,
     },
-)
\ No newline at end of file
+)


Test patch:
diff --git a/ganga/GangaGUI/test/test_gui_dashboard.py b/ganga/GangaGUI/test/test_gui_dashboard.py
deleted file mode 100644
index 7d881ffe38..0000000000
--- a/ganga/GangaGUI/test/test_gui_dashboard.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from GangaCore.testlib.GangaUnitTest import GangaUnitTest
-from GangaGUI.gui.routes import gui
-from GangaCore.Runtime.GPIexport import exportToGPI
-from GangaGUI.start import start_gui
-
-# Export start_gui function to GPI
-exportToGPI("start_gui", start_gui, "Functions")
-
-
-# ******************** Test Class ******************** #
-
-# Test dashboard view of the GUI
-class TestGangaGUIDashboard(GangaUnitTest):
-
-    def setUp(self, extra_opts=[]):
-        super(TestGangaGUIDashboard, self).setUp(extra_opts=[])
-        gui.config["TESTING"] = True
-        gui.config["LOGIN_DISABLED"] = True
-        gui.config["INTERNAL_PORT"] = 5000
-        self.app = gui.test_client()
-
-        from GangaCore.GPI import start_gui
-        start_gui(only_internal=True, internal_port=5000)
-
-    def test_dashboard(self):
-        res = self.app.get("/")
-        assert res.status_code == 200
-
-# ******************** EOF ******************** #
diff --git a/ganga/GangaGUI/test/test_gui_database.py b/ganga/GangaGUI/test/test_gui_database.py
deleted file mode 100644
index 266f1413f2..0000000000
--- a/ganga/GangaGUI/test/test_gui_database.py
+++ /dev/null
@@ -1,60 +0,0 @@
-import os
-import uuid
-from GangaCore.testlib.GangaUnitTest import GangaUnitTest
-from GangaGUI.gui.routes import gui, db, User
-from GangaCore.Runtime.GPIexport import exportToGPI
-from GangaGUI.start import start_gui
-
-# Export start_gui function to GPI
-exportToGPI("start_gui", start_gui, "Functions")
-
-# Path of current directory
-currentdir = os.path.dirname(os.path.abspath(__file__))
-
-
-# ******************** Test Class ******************** #
-
-
-class TestGangaGUIDatabase(GangaUnitTest):
-
-    def setUp(self, extra_opts=[]):
-        super(TestGangaGUIDatabase, self).setUp(extra_opts=[])
-        gui.config["TESTING"] = True
-        gui.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.join(currentdir, "gui_test.sqlite")
-        gui.config["LOGIN_DISABLED"] = True
-        gui.config["INTERNAL_PORT"] = 5000
-
-        # Flask testing client
-        self.app = gui.test_client()
-
-        # Start internal API server
-        from GangaCore.GPI import start_gui
-        start_gui(only_internal=True, internal_port=5000)
-
-    # Test creation of database file
-    def test_database_creation(self):
-        db.create_all()
-        self.assertTrue(os.path.exists(os.path.join(currentdir, "gui_test.sqlite")))
-
-        tempuser = User(public_id=str(uuid.uuid4()), user="GangaGUITestUser", role="Admin")
-        tempuser.store_password_hash("testpassword")
-        db.session.add(tempuser)
-        db.session.commit()
-
-        db_users = User.query.all()
-
-        self.assertTrue(len(db_users) == 1)
-        self.assertTrue(db_users[0].public_id == tempuser.public_id)
-        self.assertTrue(db_users[0].user == tempuser.user)
-        self.assertTrue(db_users[0].role == tempuser.role)
-        self.assertTrue(db_users[0].password_hash == tempuser.password_hash)
-        self.assertTrue(db_users[0].verify_password("testpassword"))
-
-    # Teardown, remove dummy database file
-    def tearDown(self):
-        super(TestGangaGUIDatabase, self).tearDown()
-        db.session.remove()
-        db.drop_all()
-        os.remove(os.path.join(currentdir, "gui_test.sqlite"))
-
-# ******************** EOF ******************** #
\ No newline at end of file
diff --git a/ganga/GangaGUI/test/test_gui_token_authentication.py b/ganga/GangaGUI/test/test_gui_token_authentication.py
deleted file mode 100644
index 31fd35d99c..0000000000
--- a/ganga/GangaGUI/test/test_gui_token_authentication.py
+++ /dev/null
@@ -1,86 +0,0 @@
-import os
-import uuid
-import jwt
-from GangaCore.testlib.GangaUnitTest import GangaUnitTest
-from GangaGUI.gui.routes import gui, db, User
-from GangaCore.Runtime.GPIexport import exportToGPI
-from GangaGUI.start import start_gui
-
-
-# Export start_gui function to GPI
-exportToGPI("start_gui", start_gui, "Functions")
-
-# Path of current directory
-currentdir = os.path.dirname(os.path.abspath(__file__))
-
-
-# ******************** Test Class ******************** #
-
-
-class TestGangaGUITokenAuthentication(GangaUnitTest):
-
-    def setUp(self, extra_opts=[]):
-        super(TestGangaGUITokenAuthentication, self).setUp(extra_opts=[])
-        gui.config["TESTING"] = True
-        gui.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.join(currentdir, "gui_test.sqlite")
-        gui.config["LOGIN_DISABLED"] = True
-        gui.config["INTERNAL_PORT"] = 5000
-
-        # Create database and add a temp user to the database
-        db.create_all()
-        tempuser = User(public_id=str(uuid.uuid4()), user="GangaGUITestUser", role="Admin")
-        tempuser.store_password_hash("testpassword")
-        db.session.add(tempuser)
-        db.session.commit()
-
-        # Flask testing client
-        self.app = gui.test_client()
-
-        # Start internal API server
-        from GangaCore.GPI import start_gui
-        start_gui(only_internal=True, internal_port=5000)
-
-    # Test existence of the database file
-    def test_database_existence(self):
-        self.assertTrue(os.path.exists(os.path.join(currentdir, "gui_test.sqlite")))
-
-    # Test response of GUI server when no credential information is provided in the request body
-    def test_no_credential(self):
-        res = self.app.post("/token")
-        self.assertTrue(res.status_code == 401)
-        self.assertFalse(res.json["success"])
-        self.assertFalse("token" in res.json.keys())
-
-    # Test provision on invalid credentials in the request body
-    def test_wrong_credential(self):
-        res = self.app.post("/token", json={"user": "wronguser", "password": "wrongpassword"})
-        self.assertTrue(res.status_code == 401)
-        self.assertFalse(res.json["success"])
-        self.assertFalse("token" in res.json.keys())
-
-    # Test provision of valid credentails in the request body
-    def test_right_credential(self):
-        res = self.app.post("/token", json={"username": "GangaGUITestUser", "password": "testpassword"})
-        print(res.json)
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue("token" in res.json.keys())
-        self.assertFalse(res.json["token"] is None)
-
-        token = res.json["token"]
-
-        data = jwt.decode(token, gui.config["SECRET_KEY"], algorithms=["HS256"])
-        current_user = User.query.filter_by(public_id=data["public_id"]).first()
-
-        self.assertIsNotNone(current_user)
-        self.assertTrue(current_user.user == "GangaGUITestUser")
-        self.assertTrue(current_user.role == "Admin")
-        self.assertTrue(current_user.verify_password("testpassword"))
-
-    # Tear down, remove temp database file
-    def tearDown(self):
-        super(TestGangaGUITokenAuthentication, self).tearDown()
-        db.session.remove()
-        db.drop_all()
-        os.remove(os.path.join(currentdir, "gui_test.sqlite"))
-
-# ******************** EOF ******************** #
diff --git a/ganga/GangaGUI/test/test_internal_config_api.py b/ganga/GangaGUI/test/test_internal_config_api.py
deleted file mode 100644
index 93d099dbc9..0000000000
--- a/ganga/GangaGUI/test/test_internal_config_api.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from GangaCore.testlib.GangaUnitTest import GangaUnitTest
-from GangaGUI.api import internal
-
-
-# ******************** Test Class ******************** #
-
-
-# Config API Tests
-class TestGangaGUIInternalConfigAPI(GangaUnitTest):
-
-    # Setup
-    def setUp(self, extra_opts=[]):
-        super(TestGangaGUIInternalConfigAPI, self).setUp(extra_opts=[])
-
-        # App config and database creation
-        internal.config["TESTING"] = True
-
-        # Flask test client
-        self.app = internal.test_client()
-
-    # Config API - GET Method
-    def test_GET_method_config_list(self):
-        from GangaCore.GPI import config
-        from GangaCore.Utility.Config import getConfig
-
-        # To store sections of config
-        list_of_sections = []
-
-        # Get each section information and append to the list
-        for section in config:
-
-            config_section = getConfig(section)
-            options_list = []
-
-            # Get options information for the particular config section
-            for o in config_section.options.keys():
-                options_list.append({
-                    "name": str(config_section.options[o].name),
-                    "value": str(config_section.options[o].value),
-                    "docstring": str(config_section.options[o].docstring),
-                })
-
-            # Append config section data to the list
-            list_of_sections.append({
-                "name": str(config_section.name),
-                "docstring": str(config_section.docstring),
-                "options": options_list,
-            })
-
-        res = self.app.get(f"/internal/config")
-        # print(res.json) # to check the res body
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(len(res.json) == len(list_of_sections))
-
-    # Tear down
-    def tearDown(self):
-        super(TestGangaGUIInternalConfigAPI, self).tearDown()
-
-# ******************** EOF ******************** #
diff --git a/ganga/GangaGUI/test/test_internal_credentials_api.py b/ganga/GangaGUI/test/test_internal_credentials_api.py
deleted file mode 100644
index 2e0014638b..0000000000
--- a/ganga/GangaGUI/test/test_internal_credentials_api.py
+++ /dev/null
@@ -1,131 +0,0 @@
-from GangaCore.testlib.GangaUnitTest import GangaUnitTest
-from GangaGUI.api import internal
-from GangaCore.GPIDev.Schema import SimpleItem
-from GangaCore.GPIDev.Adapters.ICredentialInfo import ICredentialInfo
-from GangaCore.GPIDev.Adapters.ICredentialRequirement import ICredentialRequirement
-from datetime import datetime, timedelta
-
-
-# ******************** Classes to Mock Credentials ******************** #
-
-
-class FakeCredInfo(ICredentialInfo):
-    def __init__(self, requirements, check_file=False, create=False):
-
-        self.does_exist = False
-
-        super(FakeCredInfo, self).__init__(requirements, check_file, create)
-
-    def create(self):
-        self.does_exist = True
-
-    def destroy(self):
-        self.does_exist = False
-
-    @property
-    def vo(self):
-        if self.does_exist:
-            return self.initial_requirements.vo
-        return None
-
-    @property
-    def role(self):
-        if self.does_exist:
-            return self.initial_requirements.role
-        return None
-
-    def expiry_time(self):
-        if self.does_exist:
-            return datetime.now() + timedelta(days=1)
-
-        datetime.now()
-
-    def default_location(self):
-        return '/tmp/some_fake_file'
-
-    def check_requirements(self, query):
-        return True
-
-    def exists(self):
-        return self.does_exist
-
-
-class FakeCred(ICredentialRequirement):
-    """
-    An object specifying the requirements of a VOMS proxy file for testing
-    """
-    _schema = ICredentialRequirement._schema.inherit_copy()
-    _schema.datadict['vo'] = SimpleItem(defvalue=None, typelist=[str, None])
-    _schema.datadict['role'] = SimpleItem(defvalue=None, typelist=[str, None])
-
-    _category = 'CredentialRequirement'
-    _name = 'TestCred'
-
-    info_class = FakeCredInfo
-
-    def __init__(self, **kwargs):
-        super(FakeCred, self).__init__(**kwargs)
-
-    def encoded(self):
-        return ':'.join(requirement for requirement in [self.vo, self.role] if requirement)
-
-    def is_empty(self):
-        return not (self.vo or self.role)
-
-
-# ******************** Test Class ******************** #
-
-
-# Credential Store API Tests
-class TestGangaGUIInternalCredentialStoreAPI(GangaUnitTest):
-
-    # Setup
-    def setUp(self, extra_opts=[]):
-        super(TestGangaGUIInternalCredentialStoreAPI, self).setUp(extra_opts=[])
-
-        # App config and database creation
-        internal.config["TESTING"] = True
-
-        # Flask test client
-        self.app = internal.test_client()
-
-    # Credential Store API - GET Method - Get list of all the credentials and their info
-    def test_GET_method(self):
-        from GangaCore.GPI import credential_store
-
-        # Create mock credentials
-        credential_store.create(FakeCred())
-        assert len(credential_store) == 1
-
-        # Create mock credentials
-        credential_store.create(FakeCred(vo='some_other_vo'))
-        assert len(credential_store) == 2
-
-        # GET request
-        res = self.app.get(f"/internal/credentials")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(len(res.json) == len(credential_store))
-
-    # Credential Store API - PUT Method - Renew all the credentials in the credential sotre
-    def test_PUT_method(self):
-        from GangaCore.GPI import credential_store
-
-        # Create mock credentials
-        credential_store.create(FakeCred())
-        assert len(credential_store) == 1
-
-        # Create mock credentials
-        credential_store.create(FakeCred(vo='some_other_vo'))
-        assert len(credential_store) == 2
-
-        # PUT request
-        res = self.app.put(f"/internal/credentials/renew")
-        self.assertTrue(res.status_code == 200)
-
-    # Tear down
-    def tearDown(self):
-        super(TestGangaGUIInternalCredentialStoreAPI, self).tearDown()
-
-
-# ******************** EOF ******************** #
-
diff --git a/ganga/GangaGUI/test/test_internal_job_api.py b/ganga/GangaGUI/test/test_internal_job_api.py
deleted file mode 100644
index 0960982517..0000000000
--- a/ganga/GangaGUI/test/test_internal_job_api.py
+++ /dev/null
@@ -1,772 +0,0 @@
-from GangaCore.testlib.GangaUnitTest import GangaUnitTest
-from GangaGUI.api import internal
-
-
-# ******************** Test Class ******************** #
-
-
-# Job API Tests
-class TestGangaGUIInternalJobAPI(GangaUnitTest):
-
-    # Setup
-    def setUp(self, extra_opts=[]):
-        super(TestGangaGUIInternalJobAPI, self).setUp(extra_opts=[])
-
-        # App config and database creation
-        internal.config["TESTING"] = True
-
-        # Flask test client
-        self.app = internal.test_client()
-
-    # Job API Test - GET Method, Single Job Info - Job ID out of index
-    def test_GET_method_id_out_of_range(self):
-        res = self.app.get(f"/internal/jobs/1")
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - GET Method, Single Job Info - Job ID negative
-    def test_GET_method_id_negative(self):
-        res = self.app.get(f"/internal/jobs/-1")
-        self.assertTrue(res.status_code == 404)
-
-    # Job API Test - GET Method, Single Job Info - Job ID string
-    def test_GET_method_id_string(self):
-        res = self.app.get(f"/internal/jobs/test")
-        self.assertTrue(res.status_code == 404)
-
-    # Job API Test - GET Method, Single Job Info - Everything correct
-    def test_GET_method(self):
-        from GangaCore.GPI import Job
-
-        # Create test job
-        j = Job()
-        j.name = "API Test Job"
-        j.comment = "Test comment"
-
-        # Make the GET request
-        res = self.app.get(f"/internal/jobs/{j.id}")
-
-        # Response assertions
-        self.assertTrue(res.status_code == 200)
-
-        # Response data assertions
-        self.assertTrue("application" in res.json.keys())
-        self.assertTrue("backend" in res.json.keys())
-        self.assertTrue("backend.actualCE" in res.json.keys())
-        self.assertTrue("comment" in res.json.keys())
-        self.assertTrue("fqid" in res.json.keys())
-        self.assertTrue("id" in res.json.keys())
-        self.assertTrue("name" in res.json.keys())
-        self.assertTrue("subjob_statuses" in res.json.keys())
-        self.assertTrue("subjobs" in res.json.keys())
-        self.assertTrue(res.json["name"] == "API Test Job")
-        self.assertTrue(int(res.json["id"]) == int(j.id))
-        self.assertTrue(str(res.json["comment"]) == str(j.comment))
-
-    # Job API Test - GET Method, Single Job Attribute Info - Job ID out of index
-    def test_job_attribute_GET_method_id_out_of_index(self):
-        res = self.app.get(f"/internal/jobs/1/id")
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - GET Method, Single Job Attribute Info - Job ID negative
-    def test_job_attribute_GET_method_id_negative(self):
-        res = self.app.get(f"/internal/jobs/-1/id")
-        self.assertTrue(res.status_code == 404)
-
-    # Job API Test - GET Method, Single Job Attribute Info - Job ID string
-    def test_job_attribute_GET_method_id_string(self):
-        res = self.app.get(f"/internal/jobs/test/id")
-        self.assertTrue(res.status_code == 404)
-
-    # Job API Test - GET Method, Single Job Attribute Info - Job ID corrent but unsupported attribute
-    def test_job_attribute_GET_method_unsupported_attribute(self):
-        from GangaCore.GPI import Job
-
-        # Create test job
-        j = Job()
-        j.name = "API Test Job"
-        j.comment = "Test comment"
-
-        # GET request
-        res = self.app.get(f"/internal/jobs/{j.id}/test")
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - GET Method, Single Job Attribute Info - Job ID correct and supported attribute
-    def test_job_attribute_GET_method_supported_attribute(self):
-        from GangaCore.GPI import Job
-
-        # Create test job
-        j = Job()
-        j.name = "API Test Job"
-        j.comment = "Test comment"
-
-        # Supported attributes list
-        supported_attributes = ["application", "backend", "do_auto_resubmit", "fqid", "id", "info", "inputdir",
-                                "inputdata",
-                                "inputfiles",
-                                "master", "name", "outputdir", "outputdata",
-                                "outputfiles", "parallel_submit", "splitter", "status", "time"]
-
-        # For each attribute make a GET request and assert the response data
-        for attribute in supported_attributes:
-            res = self.app.get(f"/internal/jobs/{j.id}/{attribute}")
-            self.assertTrue(res.status_code == 200)
-            self.assertTrue(attribute in res.json.keys())
-
-    # Job API Test - POST Method, Create Job from Template - Template ID not provide in the request body
-    def test_POST_method_template_id_not_given(self):
-        res = self.app.post(f"/internal/jobs/create")
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - POST Method, Create Job from Template - Template ID is not an int
-    def test_POST_method_template_id_not_int(self):
-        res = self.app.post(f"/internal/jobs/create", json={"template_id": "test"})
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - POST Method, Create Job from Template - Template ID incorrect
-    def test_POST_method_incorrect_template_id(self):
-        res = self.app.post(f"/internal/jobs/create", json={"template_id": 2})
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - POST Method, Create Job from Template - Template ID correct and job name not give
-    def test_POST_method_correct_template_id_job_name_given(self):
-        from GangaCore.GPI import JobTemplate, jobs
-
-        # Create test template
-        t = JobTemplate()
-        t.name = "Test Template Name"
-
-        # POST request
-        res = self.app.post(f"/internal/jobs/create",
-                            json={"template_id": t.id, "job_name": "Custom Test Name"})
-        self.assertTrue(res.status_code == 200)
-
-        job_created = False
-        for j in jobs:
-            print(j.name)
-            if j.name == "Custom Test Name":
-                job_created = True
-
-        # Assert if job was created
-        self.assertTrue(job_created)
-
-    # Job API Test - POST Method, Create Job from Template - Template ID correct and job name also provided
-    def test_POST_method_correct_template_id_job_name_not_given(self):
-        from GangaCore.GPI import JobTemplate, jobs
-
-        # Create test template
-        t = JobTemplate()
-        t.name = "Test Template Name"
-
-        # POST request
-        res = self.app.post(f"/internal/jobs/create", json={"template_id": t.id})
-        self.assertTrue(res.status_code == 200)
-
-        job_created = False
-        for j in jobs:
-            print(j.name)
-            if j.name == "Test Template Name":
-                job_created = True
-
-        # Assert job creation and job name
-        self.assertTrue(job_created)
-
-    # Job API Test - PUT Method, Action on Single Job - Job ID out of index
-    def test_PUT_method_id_out_of_index(self):
-        res = self.app.put(f"/internal/jobs/1/name", json={"name": "New Test Name"})
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - PUT Method, Action on Single Job - Job ID negative
-    def test_PUT_method_id_negative(self):
-        res = self.app.put(f"/internal/jobs/-1/id", json={"name": "New Test Name"})
-        self.assertTrue(res.status_code == 404)
-
-    # Job API Test - PUT Method, Action on Single Job - Job ID string
-    def test_PUT_method_id_string(self):
-        res = self.app.put(f"/internal/jobs/test/id", json={"name": "New Test Name"})
-        self.assertTrue(res.status_code == 404)
-
-    # Job API Test - PUT Method, Action on Single Job - Job ID correct but unsupported action
-    def test_PUT_method_unsupported_action(self):
-        from GangaCore.GPI import Job
-
-        # Create test job
-        j = Job()
-        j.name = "API Test Job"
-        j.comment = "Test comment"
-
-        # PUT request
-        res = self.app.put(f"/internal/jobs/{j.id}/test")
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - PUT Method, Action on Single Job - do_auto_resubmit action - no or bad form data
-    def test_PUT_method_do_auto_resubmit_action_no_or_bad_value(self):
-        from GangaCore.GPI import Job
-
-        # Create test job and set do_auto_submit to false
-        j = Job()
-        j.name = "Do Auto Resubmit Test"
-        j.do_auto_resubmit = False
-
-        # PUT request without form data
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit")
-        self.assertTrue(res.status_code == 400)
-
-        # PUT request with bad form data
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit",
-                           json={"do_auto_resubmit": '"Bad Value"'})
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - PUT Method, Action on Single Job - do_auto_resubmit action - correct form data
-    def test_PUT_method_do_auto_resubmit_action(self):
-        from GangaCore.GPI import Job, Local
-        from GangaTest.Framework.utils import sleep_until_state
-
-        # Create test job and set do_auto_submit to false
-        j = Job()
-        j.name = "Do Auto Resubmit Test"
-        j.do_auto_resubmit = False
-        j.comment = "Do Auto Resubmit Test Comment"
-        j.application.exe = "sleep"
-        j.application.args = ["60"]
-        j.backend = Local()
-
-        # PUT request with correct form data
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit",
-                           json={"do_auto_resubmit": True})
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.do_auto_resubmit == True)
-
-        # PUT request with correct form data
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit",
-                           json={"do_auto_resubmit": False})
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.do_auto_resubmit == False)
-
-        # PUT request with correct form data
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit",
-                           json={"do_auto_resubmit": True})
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.do_auto_resubmit == True)
-
-        # PUT request with correct form data
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit",
-                           json={"do_auto_resubmit": False})
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.do_auto_resubmit == False)
-
-        # Submit the job and wait for status to be running
-        j.submit()
-        sleep_until_state(j, state="running")
-        self.assertTrue(j.status == "running")
-
-        # Cannot change value in running state
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit",
-                           json={"do_auto_resubmit": True})
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.do_auto_resubmit == False)
-        self.assertTrue(j.status == "running")
-
-        # Kill the job
-        j.kill()
-        self.assertTrue(j.status == "killed")
-
-        # Cannot change value in killed state
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit",
-                           json={"do_auto_resubmit": True})
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.do_auto_resubmit == False)
-        self.assertTrue(j.status == "killed")
-
-        # Change job status to failed
-        j.force_status("failed")
-        self.assertTrue(j.status == "failed")
-
-        # Cannot change value in failed state
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit",
-                           json={"do_auto_resubmit": True})
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.do_auto_resubmit == False)
-        self.assertTrue(j.status == "failed")
-
-        # Change job status to completed
-        j.force_status("completed")
-        self.assertTrue(j.status == "completed")
-
-        # Cannot change value in completed state
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit",
-                           json={"do_auto_resubmit": True})
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.do_auto_resubmit == False)
-        self.assertTrue(j.status == "completed")
-
-    # Job API Test - PUT Method, Action on Single Job - name action - no form data
-    def test_PUT_method_name_action_no_value(self):
-        from GangaCore.GPI import Job
-
-        # Create test job
-        j = Job()
-        j.name = "Name 1"
-
-        # PUT request without form data
-        res = self.app.put(f"/internal/jobs/{j.id}/name")
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - PUT Method, Action on Single Job - name action - correct form data
-    def test_PUT_method_name_action(self):
-        from GangaCore.GPI import Job, Local
-        from GangaTest.Framework.utils import sleep_until_state
-
-        # Create test job
-        j = Job()
-        j.name = "Name 1"
-        j.application.exe = "sleep"
-        j.application.args = ["60"]
-        j.backend = Local()
-
-        # PUT request with correct form data
-        res = self.app.put(f"/internal/jobs/{j.id}/name", json={"name": "Name 2"})
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.name == "Name 2")
-
-        # Submit the job
-        j.submit()
-        sleep_until_state(j, state="running")
-        self.assertTrue(j.status == "running")
-
-        # Cannot change name in running state
-        res = self.app.put(f"/internal/jobs/{j.id}/name",
-                           json={"name": '"Name 3"'})
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.name == "Name 2")
-        self.assertTrue(j.status == "running")
-
-    # Job API Test - PUT Method, Action on Single Job - parallel_submit action - no or bad form data
-    def test_PUT_parallel_submit_action_no_or_bad_value(self):
-        from GangaCore.GPI import Job
-
-        # Create test job
-        j = Job()
-        j.name = "Paralle Submit Test"
-        j.parallel_submit = True
-
-        # PUT request with no data
-        res = self.app.put(f"/internal/jobs/{j.id}/parallel_submit")
-        self.assertTrue(res.status_code == 400)
-
-        # PUT reqeust with bad data
-        res = self.app.put(f"/internal/jobs/{j.id}/do_auto_resubmit",
-                           json={"parallel_submit": "Bad value"})
-        self.assertTrue(res.status_code == 400)
-
-    # Job API Test - PUT Method, Action on Single Job - parallel_submit action - good form data
-    def test_PUT_method_parallel_submit_action(self):
-        from GangaCore.GPI import Job, Local
-        from GangaTest.Framework.utils import sleep_until_state
-
-        # Create test job
-        j = Job()
-        j.name = "Parallel Submit Test"
-        j.parallel_submit = True
-        j.application.exe = "sleep"
-        j.application.args = ["60"]
-        j.backend = Local()
-
-        self.assertTrue(j.status == "new")
-
-        # PUT request with correct form data
-        res = self.app.put(f"/internal/jobs/{j.id}/parallel_submit",
-                           json={"parallel_submit": False})
-        print(res.json)
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.do_auto_resubmit == False)
-
-        # PUT request with correct form data
-        res = self.app.put(f"/internal/jobs/{j.id}/parallel_submit",
-                           json={"parallel_submit": True})
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.parallel_submit == True)
-
-        # PUT request with correct form data
-        res = self.app.put(f"/internal/jobs/{j.id}/parallel_submit",
-                           json={"parallel_submit": False})
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.parallel_submit == False)
-
-        # PUT request with correct form data
-        res = self.app.put(f"/internal/jobs/{j.id}/parallel_submit",
-                           json={"parallel_submit": True})
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.parallel_submit == True)
-
-        self.assertTrue(j.status == "new")
-
-        # Submit the job
-        j.submit()
-        sleep_until_state(j, state="running")
-        self.assertTrue(j.status == "running")
-
-        # Cannot change value in running state
-        res = self.app.put(f"/internal/jobs/{j.id}/parallel_submit",
-                           json={"parallel_submit": False})
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.parallel_submit == True)
-        self.assertTrue(j.status == "running")
-
-    # Job API - PUT Method, Kill action
-    def test_PUT_kill_action(self):
-        from GangaCore.GPI import Job, jobs, Local
-        from GangaTest.Framework.utils import sleep_until_state
-
-        # Empty job repository
-        self.assertTrue(len(jobs) == 0)
-
-        # Test sleep job
-        j = Job()
-        j.name = "Kill Job Name"
-        j.application.exe = "sleep"
-        j.application.args = ["60"]
-        j.backend = Local()
-
-        self.assertTrue(len(jobs) == 1)
-
-        # Cannot kill job in new state
-        res = self.app.put(f"/internal/jobs/{j.id}/kill")
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.status == "new")
-
-        # Submit the job
-        j.submit()
-        sleep_until_state(j, state="running")
-        self.assertTrue(j.status == "running")
-
-        # Kill the job in running state
-        res = self.app.put(f"/internal/jobs/{j.id}/kill")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status == "killed")
-
-        # Cannot kill job in killed state
-        res = self.app.put(f"/internal/jobs/{j.id}/kill")
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.status == "killed")
-
-        # Change job state to failed
-        j.force_status("failed")
-        self.assertTrue(j.status == "failed")
-
-        # Cannot kill job in failed state but it will return 200 OK HTTP code
-        res = self.app.put(f"/internal/jobs/{j.id}/kill")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status == "failed")
-
-        # Change job state to completed
-        j.force_status("completed")
-        self.assertTrue(j.status == "completed")
-
-        # Cannot kill job in completed state but it will return 200 OK HTTP code
-        res = self.app.put(f"/internal/jobs/{j.id}/kill")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status == "completed")
-
-    # Job API - PUT Method, force_status action - no or bad value in request body
-    def test_PUT_force_status_action_no_or_bad_value(self):
-        from GangaCore.GPI import Job, jobs
-
-        # Empty repository
-        self.assertTrue(len(jobs) == 0)
-
-        # Test job
-        j = Job()
-        j.name = "Force Status Test"
-
-        self.assertTrue(j.status == "new")
-
-        # Request without a body
-        res = self.app.put(f"/internal/jobs/{j.id}/force_status")
-        self.assertTrue(res.status_code == 400)
-
-        # Reuqest with a bad value in the body - Bad values are other than (completed, failed)
-        res = self.app.put(f"/internal/jobs/{j.id}/force_status",
-                           json={"force_status": '"BadValue"'})
-        self.assertTrue(res.status_code == 400)
-
-    # Job API - PUT Method, force_status action - good request body
-    def test_PUT_force_status_action(self):
-        from GangaCore.GPI import Job, jobs, Local
-        from GangaTest.Framework.utils import sleep_until_state
-
-        # Empty repository
-        self.assertTrue(len(jobs) == 0)
-
-        # Test job
-        j = Job()
-        j.name = "Force Status Test"
-        j.application.exe = "sleep"
-        j.application.args = ["60"]
-        j.backend = Local()
-
-        self.assertTrue(j.status == "new")
-
-        # Cannot change job status from new to completed
-        res = self.app.put(f"/internal/jobs/{j.id}/force_status",
-                           json={"force_status": "completed"})
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.status == "new")
-
-        # Submit the job
-        j.submit()
-        sleep_until_state(j, state="running")
-        self.assertTrue(j.status == "running")
-
-        # Change job status from running to failed
-        res = self.app.put(f"/internal/jobs/{j.id}/force_status",
-                           json={"force_status": "failed"})
-        print(res.json)
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status == "failed")
-
-        # Change job status from failed to completed
-        res = self.app.put(f"/internal/jobs/{j.id}/force_status",
-                           json={"force_status": "completed"})
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status == "completed")
-
-    # Job API - PUT Method, resubmit action
-    def test_PUT_resubmit_action(self):
-        from GangaCore.GPI import Job, jobs, Local
-        from GangaTest.Framework.utils import sleep_until_state
-
-        # Empty repository
-        self.assertTrue(len(jobs) == 0)
-
-        # Test job
-        j = Job()
-        j.name = "Resubmit Test"
-        j.application.exe = "sleep"
-        j.application.args = ["5"]
-        j.backend = Local()
-
-        self.assertTrue(j.status == "new")
-
-        # Cannot resubmit job with status new
-        res = self.app.put(f"/internal/jobs/{j.id}/resubmit")
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.status == "new")
-
-        # Submit the job
-        j.submit()
-        sleep_until_state(j)
-        self.assertTrue(j.status == "completed")
-
-        # Cannot resubmit job with status running
-        res = self.app.put(f"/internal/jobs/{j.id}/resubmit")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status != "completed")
-
-    # Job API - PUT Method, submit action
-    def test_PUT_submit_action(self):
-        from GangaCore.GPI import Job, jobs, Local
-        from GangaTest.Framework.utils import sleep_until_state
-
-        # Empty repository
-        self.assertTrue(len(jobs) == 0)
-
-        # Test job
-        j = Job()
-        j.name = "Submit Test"
-        j.application.exe = "sleep"
-        j.application.args = ["60"]
-        j.backend = Local()
-
-        self.assertTrue(j.status == "new")
-
-        # Submit a job with status new
-        res = self.app.put(f"/internal/jobs/{j.id}/submit")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status != "new")
-
-        sleep_until_state(j, state="running")
-        self.assertTrue(j.status == "running")
-
-        # Cannot submit job with status running
-        res = self.app.put(f"/internal/jobs/{j.id}/submit")
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.status == "running")
-
-        # Kill the job
-        j.kill()
-        self.assertTrue(j.status == "killed")
-
-        # Cannot submit job with status killed
-        res = self.app.put(f"/internal/jobs/{j.id}/submit")
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.status == "killed")
-
-        # Force job status to failed
-        j.force_status("failed")
-        self.assertTrue(j.status == "failed")
-
-        # Cannot submit job with status failed
-        res = self.app.put(f"/internal/jobs/{j.id}/submit")
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.status == "failed")
-
-        # Force job status to completed
-        j.force_status("completed")
-        self.assertTrue(j.status == "completed")
-
-        # Cannot submit job with status failed
-        res = self.app.put(f"/internal/jobs/{j.id}/submit")
-        self.assertTrue(res.status_code == 400)
-        self.assertTrue(j.status == "completed")
-
-    # Job API - PUT Method, runPostProcessors action
-    def test_PUT_runPostProcessors_action(self):
-        from GangaCore.GPI import Job, jobs, Local
-        from GangaTest.Framework.utils import sleep_until_state
-
-        # Empty repository
-        self.assertTrue(len(jobs) == 0)
-
-        # Test job
-        j = Job()
-        j.name = "runPostProcessors Test"
-        j.application.exe = "sleep"
-        j.application.args = ["60"]
-        j.backend = Local()
-
-        self.assertTrue(j.status == "new")
-
-        # Run runPostProcessors of job with status new
-        res = self.app.put(f"/internal/jobs/{j.id}/runPostProcessors")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status == "new")
-
-        # Submit the job
-        j.submit()
-        sleep_until_state(j, state="running")
-        self.assertTrue(j.status == "running")
-
-        # Run runPostProcessors of job with status running
-        res = self.app.put(f"/internal/jobs/{j.id}/runPostProcessors")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status == "running")
-
-        # Kill the job
-        j.kill()
-        self.assertTrue(j.status == "killed")
-
-        # Run runPostProcessors of job with status killed
-        res = self.app.put(f"/internal/jobs/{j.id}/runPostProcessors")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status == "killed")
-
-        # Force job status to failed
-        j.force_status("failed")
-        self.assertTrue(j.status == "failed")
-
-        # Run runPostProcessors of job with status failed
-        res = self.app.put(f"/internal/jobs/{j.id}/runPostProcessors")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status == "failed")
-
-        # Force job status to completed
-        j.force_status("completed")
-        self.assertTrue(j.status == "completed")
-
-        # Run runPostProcessors of job with status running
-        res = self.app.put(f"/internal/jobs/{j.id}/runPostProcessors")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(j.status == "completed")
-
-    # Job API - DELETE Method, ID Out of Index
-    def test_DELETE_method_id_out_of_range(self):
-        res = self.app.delete(f"/internal/jobs/1")
-        self.assertTrue(res.status_code == 400)
-
-    # Job API - DELETE Method, ID is Negative
-    def test_DELETE_method_id_negative(self):
-        res = self.app.delete(f"/internal/jobs/-1")
-        self.assertTrue(res.status_code == 404)
-
-    # Job API - DELETE Method, ID is String
-    def test_DELETE_method_id_string(self):
-        res = self.app.delete(f"/internal/jobs/test")
-        self.assertTrue(res.status_code == 404)
-
-    # Job API - DELETE Method - Job in new state
-    def test_DELETE_method_new_state(self):
-        from GangaCore.GPI import Job, jobs, Local
-
-        # Empty repository
-        self.assertTrue(len(jobs) == 0)
-
-        # Test job
-        j = Job()
-        j.name = "Delete Test"
-        j.application.exe = "sleep"
-        j.application.args = ["60"]
-        j.backend = Local()
-
-        self.assertTrue(j.status == "new")
-        self.assertTrue(len(jobs) == 1)
-
-        # Delete the job with status new
-        res = self.app.delete(f"/internal/jobs/{j.id}")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(len(jobs) == 0)
-        self.assertTrue(j.id not in jobs.ids())
-
-    # Job API - DELETE Method - Job in completed state
-    def test_DELETE_method_completed_state(self):
-        from GangaCore.GPI import Job, jobs, Local
-        from GangaTest.Framework.utils import sleep_until_state
-
-        # Empty repository
-        self.assertTrue(len(jobs) == 0)
-
-        # Test job
-        j = Job()
-        j.name = "Delete Test"
-
-        self.assertTrue(j.status == "new")
-        self.assertTrue(len(jobs) == 1)
-
-        j.submit()
-        sleep_until_state(j)
-
-        # Delete the job with status completed
-        res = self.app.delete(f"/internal/jobs/{j.id}")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(len(jobs) == 0)
-        self.assertTrue(j.id not in jobs.ids())
-
-    # Job API - DELETE Method - Job in failed state
-    def test_DELETE_method_failed_state(self):
-        from GangaCore.GPI import Job, jobs, Local
-        from GangaTest.Framework.utils import sleep_until_state
-
-        # Empty repository
-        self.assertTrue(len(jobs) == 0)
-
-        # Test job
-        j = Job()
-        j.name = "Delete Test"
-
-        self.assertTrue(j.status == "new")
-        self.assertTrue(len(jobs) == 1)
-
-        j.submit()
-        sleep_until_state(j)
-        j.force_status("failed")
-
-        # Delete the job with status completed
-        res = self.app.delete(f"/internal/jobs/{j.id}")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(len(jobs) == 0)
-        self.assertTrue(j.id not in jobs.ids())
-
-    # Tear down
-    def tearDown(self):
-        super(TestGangaGUIInternalJobAPI, self).tearDown()
-
-# ******************** EOF ******************** #
diff --git a/ganga/GangaGUI/test/test_internal_jobs_api.py b/ganga/GangaGUI/test/test_internal_jobs_api.py
deleted file mode 100644
index 47f734d6b5..0000000000
--- a/ganga/GangaGUI/test/test_internal_jobs_api.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from GangaCore.testlib.GangaUnitTest import GangaUnitTest
-from GangaGUI.api import internal
-
-
-# ******************** Test Class ******************** #
-
-# Job API Tests
-class TestGangaGUIInternalJobsAPI(GangaUnitTest):
-
-    # Setup
-    def setUp(self, extra_opts=[]):
-        super(TestGangaGUIInternalJobsAPI, self).setUp(extra_opts=[])
-
-        # App config and database creation
-        internal.config["TESTING"] = True
-
-        # Flask test client
-        self.app = internal.test_client()
-
-    # Jobs API - GET Method
-    def test_GET_method_jobs_list(self):
-        from GangaCore.GPI import Job, GenericSplitter, Local
-
-        # Create 20 test jobs with subjobs
-        for i in range(0, 20):
-            j = Job()
-            j.name = f"Job Test {i}"
-            j.application.exe = "sleep"
-            j.splitter = GenericSplitter()
-            j.splitter.attribute = 'application.args'
-            j.splitter.values = [['3'] for _ in range(0, 3)]
-            j.backend = Local()
-            j.submit()
-
-        # GET reqeust
-        res = self.app.get(f"/internal/jobs")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(len(res.json) == 20)
-
-        # Assert response
-        supported_attributes = ["id", "fqid", "status", "name", "subjobs", "application", "backend", "backend.actualCE",
-                                "comment", "subjob_statuses"]
-        for i in range(0, 20):
-            for attribute in supported_attributes:
-                self.assertTrue(attribute in res.json[i])
-            self.assertTrue(res.json[i]["name"] == f"Job Test {i}")
-
-    # Jobs API - GET Method, Incomplete IDs list
-    def test_GET_method_jobs_incomplete_ids_list(self):
-        res = self.app.get(f"/internal/jobs/incomplete-ids")
-        self.assertTrue(res.status_code == 200)
-
-    # Tear down
-    def tearDown(self):
-        super(TestGangaGUIInternalJobsAPI, self).tearDown()
-
-# ******************** EOF ******************** #
diff --git a/ganga/GangaGUI/test/test_internal_jobtree_api.py b/ganga/GangaGUI/test/test_internal_jobtree_api.py
deleted file mode 100644
index 3f97176eaf..0000000000
--- a/ganga/GangaGUI/test/test_internal_jobtree_api.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from GangaCore.testlib.GangaUnitTest import GangaUnitTest
-from GangaGUI.api import internal
-
-
-# ******************** Test Class ******************** #
-
-# JobTree API Tests
-class TestGangaGUIInternalJobTreeAPI(GangaUnitTest):
-
-    # Setup
-    def setUp(self, extra_opts=[]):
-        super(TestGangaGUIInternalJobTreeAPI, self).setUp(extra_opts=[])
-
-        # App config and database creation
-        internal.config["TESTING"] = True
-
-        # Flask test client
-        self.app = internal.test_client()
-
-    # Job Tree API - GET Method
-    def test_GET_method_jobtree_list(self):
-        from GangaCore.GPI import Job, jobtree
-
-        # Create 10 dir in jobtree and add 10 jobs to each
-        for i in range(0, 10):
-            jobtree.mkdir(f"Jobdir{i}")
-            jobtree.cd(f"Jobdir{i}")
-            for j in range(0, 10):
-                jobtree.add(Job(name=f"Job{i}-{j}"))
-            jobtree.cd()
-
-        # GET reqeust
-        res = self.app.get(f"/internal/jobtree")
-        self.assertTrue(res.status_code == 200)
-
-        # Assert presence of the created dirs in the response
-        for i in range(0, 10):
-            self.assertTrue(f"Jobdir{i}" in res.json["/"].keys())
-
-    # Tear down
-    def tearDown(self):
-        super(TestGangaGUIInternalJobTreeAPI, self).tearDown()
-
-# ******************** EOF ******************** #
diff --git a/ganga/GangaGUI/test/test_internal_subjobs_api.py b/ganga/GangaGUI/test/test_internal_subjobs_api.py
deleted file mode 100644
index e40a91c41f..0000000000
--- a/ganga/GangaGUI/test/test_internal_subjobs_api.py
+++ /dev/null
@@ -1,217 +0,0 @@
-from GangaCore.testlib.GangaUnitTest import GangaUnitTest
-from GangaGUI.api import internal
-
-
-# ******************** Test Class ******************** #
-
-
-# Subjobs API Tests
-class TestGangaInternalGUISubjobsAPI(GangaUnitTest):
-
-    # Setup
-    def setUp(self, extra_opts=[]):
-        super(TestGangaInternalGUISubjobsAPI, self).setUp(extra_opts=[])
-
-        # App config setup and test database creation
-        internal.config["TESTING"] = True
-
-        # Flask test client
-        self.app = internal.test_client()
-
-    # Subjobs API - GET Method, Subjobs List - Job ID out of range
-    def test_GET_method_job_id_out_of_range(self):
-        res = self.app.get(f"/internal/jobs/1/subjobs")
-        self.assertTrue(res.status_code == 400)
-
-    # Subjobs API - GET Method, Subjobs List - Job ID negative
-    def test_GET_method_job_id_negative(self):
-        res = self.app.get(f"/internal/jobs/-1/subjobs")
-        self.assertTrue(res.status_code == 404)
-
-    # Subjobs API - GET Method, Subjobs List - Job ID string
-    def test_GET_method_job_id_string(self):
-        res = self.app.get(f"/internal/jobs/test/subjobs")
-        self.assertTrue(res.status_code == 404)
-
-    # Subjobs API - GET Method, Subjobs List - No subjob case
-    def test_GET_method_job_id_no_subjob(self):
-        from GangaCore.GPI import Job
-
-        # Create test job
-        j = Job()
-        j.name = "Test Name"
-
-        # GET request
-        res = self.app.get(f"/internal/jobs/{j.id}/subjobs")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(len(res.json) == 0)
-
-    # Subjob API - GET Method, Subjobs List
-    def test_GET_method_job_id(self):
-        from GangaCore.GPI import Job, GenericSplitter, Local
-
-        # Create test job
-        j = Job()
-        j.name = "Subjob test"
-        j.application.exe = "sleep"
-        j.splitter = GenericSplitter()
-        j.splitter.attribute = 'application.args'
-        j.splitter.values = [['5'] for _ in range(0, 20)]
-        j.backend = Local()
-        j.submit()
-
-        # GET request
-        res = self.app.get(f"/internal/jobs/{j.id}/subjobs")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(len(res.json) == 20)
-
-        # Supported attributes list and assertions
-        supported_attributes = ["id", "fqid", "status", "name", "application", "backend", "backend.actualCE", "comment"]
-        for i in range(0, 20):
-            for attribute in supported_attributes:
-                self.assertTrue(attribute in res.json[i].keys())
-
-    # Subjobs API - GET Method, Single Subjob info - Job ID out of range
-    def test_GET_method_single_subjob_info_job_id_out_of_range(self):
-        res = self.app.get(f"/internal/jobs/1/subjobs/2")
-        self.assertTrue(res.status_code == 400)
-
-    # Subjobs API - GET Method, Single Subjob info - Job ID negative
-    def test_GET_method_single_subjob_info_job_id_negative(self):
-        res = self.app.get(f"/internal/jobs/-1/subjobs/2")
-        self.assertTrue(res.status_code == 404)
-
-    # Subjobs API - GET Method, Single Subjob info - Job ID string
-    def test_GET_method_single_subjob_info_job_id_string(self):
-        res = self.app.get(f"/internal/jobs/test/subjobs/2")
-        self.assertTrue(res.status_code == 404)
-
-    # Subjobs API - GET Method, Single Subjob info - No subjob case
-    def test_GET_method_single_subjob_info_no_subjob(self):
-        from GangaCore.GPI import Job
-
-        # Create test job
-        j = Job()
-        j.name = "Test Name"
-
-        # GET request
-        res = self.app.get(f"/internal/jobs/{j.id}/subjobs/2")
-        self.assertTrue(res.status_code == 400)
-
-    # Subjobs API - GET Method, Single Subjob info - subjob id out of index
-    def test_GET_method_single_subjob_info_subjob_id_out_of_index(self):
-        from GangaCore.GPI import Job, GenericSplitter, Local
-
-        # Create test job with subjobs
-        j = Job()
-        j.name = "Subjob test"
-        j.application.exe = "sleep"
-        j.splitter = GenericSplitter()
-        j.splitter.attribute = 'application.args'
-        j.splitter.values = [['5'] for _ in range(0, 10)]
-        j.backend = Local()
-        j.submit()
-
-        # GET request
-        res = self.app.get(f"/internal/jobs/{j.id}/subjobs/21")
-        self.assertTrue(res.status_code == 400)
-
-    # Subjobs API - GET Method, Single Subjob Info
-    def test_GET_method_single_subjob_info(self):
-        from GangaCore.GPI import Job, GenericSplitter, Local
-
-        # Create test job with subjobs
-        j = Job()
-        j.name = "Subjob test"
-        j.application.exe = "sleep"
-        j.splitter = GenericSplitter()
-        j.splitter.attribute = 'application.args'
-        j.splitter.values = [['5'] for _ in range(0, 20)]
-        j.backend = Local()
-        j.submit()
-
-        # GET request
-        res = self.app.get(f"/internal/jobs/{j.id}/subjobs/{j.subjobs[2].id}")
-        print(res.json)
-        self.assertTrue(res.status_code == 200)
-
-        # Attributes in the API response body
-        supported_attributes = ["id", "fqid", "status", "name", "application", "backend", "backend.actualCE", "comment"]
-        for attribute in supported_attributes:
-            self.assertTrue(attribute in res.json.keys())
-
-    # Subjobs API - GET Method, Single Subjob Attribute info - Job ID out of range
-    def test_GET_method_single_subjob_attr_info_job_id_out_of_range(self):
-        res = self.app.get(f"/internal/jobs/1/subjobs/2/fqid")
-        self.assertTrue(res.status_code == 400)
-
-    # Subjobs API - GET Method, Single Subjob Attribute info - Job ID negative
-    def test_GET_method_single_subjob_attr_info_job_id_negative(self):
-        res = self.app.get(f"/internal/jobs/-1/subjobs/2/fqid")
-        self.assertTrue(res.status_code == 404)
-
-    # Subjobs API - GET Method, Single Subjob Attribute info - Job ID string
-    def test_GET_method_single_subjob_attr_info_job_id_string(self):
-        res = self.app.get(f"/internal/jobs/test/subjobs/2/fqid")
-        self.assertTrue(res.status_code == 404)
-
-    # Subjobs API - GET Method, Single Subjob Attribute info - No subjob case
-    def test_GET_method_single_subjob_attr_info_no_subjob(self):
-        from GangaCore.GPI import Job
-
-        # Create test job
-        j = Job()
-        j.name = "Test Name"
-
-        # GET request
-        res = self.app.get(f"/internal/jobs/{j.id}/subjobs/2/fqid")
-        self.assertTrue(res.status_code == 400)
-
-    # Subjobs API - GET Method, Single Subjob Attribute info - subjob id out of index
-    def test_GET_method_single_subjob_attr_info_subjob_id_out_of_index(self):
-        from GangaCore.GPI import Job, GenericSplitter, Local
-
-        # Create job with subjobs
-        j = Job()
-        j.name = "Subjob test"
-        j.application.exe = "sleep"
-        j.splitter = GenericSplitter()
-        j.splitter.attribute = 'application.args'
-        j.splitter.values = [['5'] for _ in range(0, 10)]
-        j.backend = Local()
-        j.submit()
-
-        # GET request
-        res = self.app.get(f"/internal/jobs/{j.id}/subjobs/21/fqid")
-        self.assertTrue(res.status_code == 400)
-
-    # Subjobs API - GET Method, Single Subjob Attribute Info
-    def test_GET_method_single_subjob_attr_info(self):
-        from GangaCore.GPI import Job, GenericSplitter, Local
-
-        # Create test job with subjobs
-        j = Job()
-        j.name = "Subjob test"
-        j.application.exe = "sleep"
-        j.splitter = GenericSplitter()
-        j.splitter.attribute = 'application.args'
-        j.splitter.values = [['5'] for _ in range(0, 5)]
-        j.backend = Local()
-        j.submit()
-
-        supported_attributes = ["application", "backend", "do_auto_resubmit", "fqid", "id", "info", "inputdir",
-                                "inputfiles",
-                                "master", "name", "outputdir",
-                                "outputfiles", "parallel_submit", "status", "time"]
-
-        for i in range(0, 5):
-            for attribute in supported_attributes:
-                res = self.app.get(f"/internal/jobs/{j.id}/subjobs/{j.subjobs[i].id}/{attribute}")
-                self.assertTrue(res.status_code == 200)
-                self.assertTrue(attribute in res.json.keys())
-
-    # Tear down
-    def tearDown(self):
-        super(TestGangaInternalGUISubjobsAPI, self).tearDown()
-
-# ******************** EOF ******************** #
diff --git a/ganga/GangaGUI/test/test_internal_templates_api.py b/ganga/GangaGUI/test/test_internal_templates_api.py
deleted file mode 100644
index 942c2bf75c..0000000000
--- a/ganga/GangaGUI/test/test_internal_templates_api.py
+++ /dev/null
@@ -1,91 +0,0 @@
-from GangaCore.testlib.GangaUnitTest import GangaUnitTest
-from GangaGUI.api import internal
-
-
-# ******************** Test Class ******************** #
-
-
-# Templates API Tests
-class TestGangaGUIInternalTemplatesAPI(GangaUnitTest):
-
-    # Setup
-    def setUp(self, extra_opts=[]):
-        super(TestGangaGUIInternalTemplatesAPI, self).setUp(extra_opts=[])
-
-        # App config and database creation
-        internal.config["TESTING"] = True
-
-        # Flask test client
-        self.app = internal.test_client()
-
-    # Templates API - GET Method
-    def test_GET_method_templates_list(self):
-        from GangaCore.GPI import templates, JobTemplate, GenericSplitter, Local
-
-        # Create 20 test templates
-        for i in range(0, 20):
-            t = JobTemplate()
-            t.name = f"Template Test {i}"
-            t.application.exe = "sleep"
-            t.splitter = GenericSplitter()
-            t.splitter.attribute = 'application.args'
-            t.splitter.values = [['3'] for _ in range(0, 3)]
-            t.backend = Local()
-
-        # GET request
-        res = self.app.get(f"/internal/templates")
-        self.assertTrue(res.status_code == 200)
-        self.assertTrue(len(res.json) == 20)
-
-        # Response data assertions
-        supported_attributes = ["id", "fqid", "name", "application", "backend", "comment", "backend.actualCE"]
-        for i in range(0, 20):
-            for attribute in supported_attributes:
-                self.assertTrue(attribute in res.json[i])
-            self.assertTrue(res.json[i]["name"] == f"Template Test {i}")
-
-    # Templates API - DELETE Method, ID Out of Index
-    def test_DELETE_method_id_out_of_range(self):
-        res = self.app.delete(f"/internal/templates/1")
-        self.assertTrue(res.status_code == 400)
-
-    # Templates API - DELETE Method, ID is Negative
-    def test_DELETE_method_id_negative(self):
-        res = self.app.delete(f"/internal/templates/-1")
-        self.assertTrue(res.status_code == 404)
-
-    # Templates API - DELETE Method, ID is String
-    def test_DELETE_method_id_string(self):
-        res = self.app.delete(f"/internal/templates/test")
-        self.assertTrue(res.status_code == 404)
-
-    # Templates API - DELETE Method
-    def test_DELETE_method_templates_list(self):
-        from GangaCore.GPI import templates, JobTemplate, GenericSplitter, Local
-
-        # Clean template repository check
-        self.assertTrue(len(templates) == 0)
-
-        # Create 20 test templates
-        created_template_ids = []
-        for i in range(0, 20):
-            t = JobTemplate()
-            t.name = f"Template Test {i}"
-            created_template_ids.append(t.id)
-
-        self.assertTrue(len(templates) == 20)
-        self.assertTrue(len(created_template_ids) == 20)
-
-        # Delete one template every request and assert the deletion
-        for i in range(0,20):
-            self.assertTrue(created_template_ids[i] in templates.ids())
-            res = self.app.delete(f"/internal/templates/{created_template_ids[i]}")
-            self.assertTrue(res.status_code == 200)
-            self.assertTrue(len(templates) == (20-(i+1)))
-            self.assertTrue(created_template_ids[i] not in templates.ids())
-
-    # Tear down
-    def tearDown(self):
-        super(TestGangaGUIInternalTemplatesAPI, self).tearDown()
-
-# ******************** EOF ******************** #