diff --git a/dist/coursebox-0.0.1-py3-none-any.whl b/dist/coursebox-0.0.1-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..df9e2089096cf6ca1f2aad32e45273460a2bb899
Binary files /dev/null and b/dist/coursebox-0.0.1-py3-none-any.whl differ
diff --git a/dist/coursebox-0.0.1.tar.gz b/dist/coursebox-0.0.1.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..2c018231141ae11aac06c6a010e6ef364541a0f1
Binary files /dev/null and b/dist/coursebox-0.0.1.tar.gz differ
diff --git a/dist/coursebox-0.0.2-py3-none-any.whl b/dist/coursebox-0.0.2-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..73492399eb7b283cb88d5d5c1c8781d0607f2e65
Binary files /dev/null and b/dist/coursebox-0.0.2-py3-none-any.whl differ
diff --git a/dist/coursebox-0.0.2.tar.gz b/dist/coursebox-0.0.2.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..8dbe79a08ee6b4ce82d6c9a21cfbd5b36bcb0f43
Binary files /dev/null and b/dist/coursebox-0.0.2.tar.gz differ
diff --git a/dist/coursebox-0.1.0-py3-none-any.whl b/dist/coursebox-0.1.0-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..c7d235d2d3f861f5e3d65d255e7334c6862a2443
Binary files /dev/null and b/dist/coursebox-0.1.0-py3-none-any.whl differ
diff --git a/dist/coursebox-0.1.0.tar.gz b/dist/coursebox-0.1.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..7466bf0b7a234245dca79cec66204d7936caf2b7
Binary files /dev/null and b/dist/coursebox-0.1.0.tar.gz differ
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..74ad859cdbbfd93ffd7073066e0eb99a63b5eb0a
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,13 @@
+openpyxl
+tika
+xlwings
+pybtex
+langdetect
+wexpect
+pexpect
+matplotlib
+numpy
+pycode_similar
+jinjafy
+slider
+tinydb
diff --git a/setup.py b/setup.py
index 9954fcc28ddefa6b7228e32b5000324c77ffa880..6395f79941d10e1847d82220b494c4339ad4e206 100644
--- a/setup.py
+++ b/setup.py
@@ -1,14 +1,17 @@
 # Use this guide:
 # https://packaging.python.org/tutorials/packaging-projects/
+# Use pipreqs.exe to get requirements list.
+# py -m build && twine upload dist/*
 
 import setuptools
+import pkg_resources
 
 with open("README.md", "r", encoding="utf-8") as fh:
     long_description = fh.read()
-beamer-slider
+# beamer-slider
 setuptools.setup(
     name="coursebox",
-    version="0.0.1",
+    version="0.1.0",
     author="Tue Herlau",
     author_email="tuhe@dtu.dk",
     description="A course management system currently used at DTU",
@@ -27,5 +30,5 @@ setuptools.setup(
     package_dir={"": "src"},
     packages=setuptools.find_packages(where="src"),
     python_requires=">=3.8",
-    install_requires=['jinja2',],
+    install_requires=[str(r) for r in pkg_resources.parse_requirements('requirements.txt')],
 )
diff --git a/src/coursebox.egg-info/PKG-INFO b/src/coursebox.egg-info/PKG-INFO
new file mode 100644
index 0000000000000000000000000000000000000000..e3cfb0ff0f97c63baaed2e3d9661e7667a7c685f
--- /dev/null
+++ b/src/coursebox.egg-info/PKG-INFO
@@ -0,0 +1,21 @@
+Metadata-Version: 2.1
+Name: coursebox
+Version: 0.1.0
+Summary: A course management system currently used at DTU
+Home-page: https://lab.compute.dtu.dk/tuhe/coursebox
+Author: Tue Herlau
+Author-email: tuhe@dtu.dk
+License: MIT
+Project-URL: Bug Tracker, https://lab.compute.dtu.dk/tuhe/coursebox/issues
+Platform: UNKNOWN
+Classifier: Programming Language :: Python :: 3
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Requires-Python: >=3.8
+Description-Content-Type: text/markdown
+License-File: LICENSE
+
+# coursebox
+
+DTU course management
+
diff --git a/src/coursebox.egg-info/SOURCES.txt b/src/coursebox.egg-info/SOURCES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a3fc7c7d05742b5d062b249657a7ea33edf3cd1d
--- /dev/null
+++ b/src/coursebox.egg-info/SOURCES.txt
@@ -0,0 +1,25 @@
+LICENSE
+README.md
+pyproject.toml
+setup.py
+src/coursebox/__init__.py
+src/coursebox/setup_coursebox.py
+src/coursebox/thtools_base.py
+src/coursebox.egg-info/PKG-INFO
+src/coursebox.egg-info/SOURCES.txt
+src/coursebox.egg-info/dependency_links.txt
+src/coursebox.egg-info/requires.txt
+src/coursebox.egg-info/top_level.txt
+src/coursebox/book/__init__.py
+src/coursebox/book/exam_includer.py
+src/coursebox/core/__init__.py
+src/coursebox/core/citations.py
+src/coursebox/core/info.py
+src/coursebox/core/info_paths.py
+src/coursebox/core/projects.py
+src/coursebox/core/projects_info.py
+src/coursebox/core/projects_plagiarism.py
+src/coursebox/material/__init__.py
+src/coursebox/material/homepage_lectures_exercises.py
+src/coursebox/material/lecture_questions.py
+src/coursebox/material/snipper.py
\ No newline at end of file
diff --git a/src/coursebox.egg-info/dependency_links.txt b/src/coursebox.egg-info/dependency_links.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/src/coursebox.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/src/coursebox.egg-info/requires.txt b/src/coursebox.egg-info/requires.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4414fc1e28fae46b363ba747b7a921479d85ab62
--- /dev/null
+++ b/src/coursebox.egg-info/requires.txt
@@ -0,0 +1 @@
+requirements.txt
diff --git a/src/coursebox.egg-info/top_level.txt b/src/coursebox.egg-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d11e16ff39bd313e7895aed45c0aba5c183516fd
--- /dev/null
+++ b/src/coursebox.egg-info/top_level.txt
@@ -0,0 +1 @@
+coursebox
diff --git a/src/coursebox/__pycache__/__init__.cpython-38.pyc b/src/coursebox/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..03009bd43ac88fb412c376ecd7db5db69331bc5e
Binary files /dev/null and b/src/coursebox/__pycache__/__init__.cpython-38.pyc differ
diff --git a/src/coursebox/__pycache__/setup_coursebox.cpython-38.pyc b/src/coursebox/__pycache__/setup_coursebox.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f96ff60f229e8bbc3fe61501332eb3ae3d352e26
Binary files /dev/null and b/src/coursebox/__pycache__/setup_coursebox.cpython-38.pyc differ
diff --git a/src/coursebox/__pycache__/thtools_base.cpython-38.pyc b/src/coursebox/__pycache__/thtools_base.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..615f2f239e0aef33c387543bdc2bf499b1461fe5
Binary files /dev/null and b/src/coursebox/__pycache__/thtools_base.cpython-38.pyc differ
diff --git a/src/coursebox/book/__pycache__/__init__.cpython-38.pyc b/src/coursebox/book/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1b43374657666dd2b6a283b5bbddba4185aee8f2
Binary files /dev/null and b/src/coursebox/book/__pycache__/__init__.cpython-38.pyc differ
diff --git a/src/coursebox/book/__pycache__/exam_includer.cpython-38.pyc b/src/coursebox/book/__pycache__/exam_includer.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..54a9b2cc65f24cc6e00c2596de0e03b71e4e72b4
Binary files /dev/null and b/src/coursebox/book/__pycache__/exam_includer.cpython-38.pyc differ
diff --git a/src/coursebox/core/__pycache__/__init__.cpython-38.pyc b/src/coursebox/core/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..be50bdc268403b43f0a5f93c504fab5f9bcab49f
Binary files /dev/null and b/src/coursebox/core/__pycache__/__init__.cpython-38.pyc differ
diff --git a/src/coursebox/core/__pycache__/citations.cpython-38.pyc b/src/coursebox/core/__pycache__/citations.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8956e2985ebe5bced649649c27a3d2352d355dc6
Binary files /dev/null and b/src/coursebox/core/__pycache__/citations.cpython-38.pyc differ
diff --git a/src/coursebox/core/__pycache__/info.cpython-38.pyc b/src/coursebox/core/__pycache__/info.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3f839d495d781a86b5672f0951019147942b043c
Binary files /dev/null and b/src/coursebox/core/__pycache__/info.cpython-38.pyc differ
diff --git a/src/coursebox/core/__pycache__/info_paths.cpython-38.pyc b/src/coursebox/core/__pycache__/info_paths.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..44878fc248c9c6c8946de9bb7017acaaed9339c5
Binary files /dev/null and b/src/coursebox/core/__pycache__/info_paths.cpython-38.pyc differ
diff --git a/src/coursebox/core/__pycache__/projects_info.cpython-38.pyc b/src/coursebox/core/__pycache__/projects_info.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4924025fb95a5691dc63e256c55f5a0b44df0bbd
Binary files /dev/null and b/src/coursebox/core/__pycache__/projects_info.cpython-38.pyc differ
diff --git a/src/coursebox/core/citations.py b/src/coursebox/core/citations.py
index 57d3a5d55788f7ac78c107b6b20ebb46ced86822..7a39334a784bce7a6be8b86a23365c380bb44a67 100644
--- a/src/coursebox/core/citations.py
+++ b/src/coursebox/core/citations.py
@@ -1,8 +1,10 @@
 import os
 import pybtex
 import io
-import six
-from thtools.coursebox.core.info_paths import get_paths
+# import six
+from coursebox.core.info_paths import get_paths
+from pybtex import plugin
+from pybtex.database.input import bibtex
 
 def get_references(bibfile, gi):
 
@@ -14,17 +16,23 @@ def get_references(bibfile, gi):
     if not os.path.exists(bibf):
         return None
 
-    pybtex_style = pybtex.plugin.find_plugin('pybtex.style.formatting', 'alpha')()
-    pybtex_html_backend = pybtex.plugin.find_plugin('pybtex.backends', 'html')()
-    pybtex_plain_backend = pybtex.plugin.find_plugin('pybtex.backends', 'plaintext')()
+     # pybtex.plugin
 
-    pybtex_parser = pybtex.database.input.bibtex.Parser()
+
+    pybtex_style = plugin.find_plugin('pybtex.style.formatting', 'alpha')()
+    pybtex_html_backend = plugin.find_plugin('pybtex.backends', 'html')()
+    pybtex_plain_backend = plugin.find_plugin('pybtex.backends', 'plaintext')()
+
+    pybtex_parser = bibtex.Parser()
 
     with open(bibf, 'r', encoding='utf8') as f:
         data = pybtex_parser.parse_stream(f)
 
-    itv = six.itervalues(data.entries)
-    data_formatted = pybtex_style.format_entries(itv)
+    # Tue: This used to be:
+    # import six
+    # itv = six.itervalues(data.entries)
+    # itv = iter(data.entries)
+    data_formatted = pybtex_style.format_entries(data.entries.values())
     refs = {}
 
     if 'auxfile' in gi:
diff --git a/src/coursebox/core/info.py b/src/coursebox/core/info.py
index 935c9d66c3a3b2ef804b5d8d3d72f146348d81eb..31693eee1acc1377ddda1d876be7fa5ddad25449 100644
--- a/src/coursebox/core/info.py
+++ b/src/coursebox/core/info.py
@@ -1,18 +1,19 @@
 from datetime import timedelta
 from datetime import datetime
-import thtools
+import coursebox
+# import thtools
 import os
 import shutil
-from thtools.thtools_base import list_dict2dict_list
-import thtools.jinjafy
+from coursebox.thtools_base import list_dict2dict_list
+# import jinjafy
 import openpyxl
-from thtools.coursebox.core.projects_info import populate_student_report_results
-from thtools.coursebox.core.info_paths import get_paths, semester_id, semester, year, today
-from thtools.coursebox.core.info_paths import core_conf
-import six
-import pybtex.database.input.bibtex
-import pybtex.plugin
-import io
+from coursebox.core.projects_info import populate_student_report_results
+from coursebox.core.info_paths import get_paths, semester_id, semester, year, today
+from coursebox.core.info_paths import core_conf
+# import six
+# import pybtex.database.input.bibtex
+# import pybtex.plugin
+# import io
 
 
 def xlsx_to_dicts(xlsx_file,sheet=None, as_dict_list=False):
@@ -77,12 +78,12 @@ def get_enrolled_students():
         students2[id] = s2
     return students2
 
-
-def get_file_dir_or_template(filepath, templatepath):
-    thtools.ensure_dir_exists( os.path.dirname(filepath) )
-    if not os.path.exists(os.path.dirname):
-        shutil.copyfile(templatepath, filepath)
-
+# def get_file_dir_or_template(filepath, templatepath):
+#     dn =  os.path.dirname(filepath)
+#
+#     thtools.ensure_dir_exists(  )
+#     if not os.path.exists(os.path.dirname):
+#         shutil.copyfile(templatepath, filepath)
 
 def get_instructors():
     paths = get_paths()
@@ -90,7 +91,7 @@ def get_instructors():
     return instructors
 
 def continuing_education():
-    return thtools.coursebox.core.info_paths.core_conf['continuing_education_mode']
+    return coursebox.core.info_paths.core_conf['continuing_education_mode']
 
 def first_day_of_class(info):
     if continuing_education():
@@ -266,7 +267,7 @@ def class_information():
     del gi['key']
     del gi['value']
 
-    from thtools.coursebox.core.citations import get_references
+    from coursebox.core.citations import get_references
     if "pensum_bib" in gi:
         refs, nrefs = get_references(paths['02450public'] + "/" + gi['pensum_bib'], gi)
         d['references'], d['new_references'] = refs, nrefs
diff --git a/src/coursebox/core/info_paths.py b/src/coursebox/core/info_paths.py
index 313e3254cb043d3d478880c282b2ff08098e24cc..6bfbcc7b5f94fa597c8f78079568d2aabb7b9f12 100644
--- a/src/coursebox/core/info_paths.py
+++ b/src/coursebox/core/info_paths.py
@@ -1,4 +1,4 @@
-import thtools
+# import thtools
 import os
 import shutil
 from datetime import datetime
@@ -31,7 +31,9 @@ def get_paths():
         semester_path = root_02450private +"/resources/mock_semesters/" + semester_id()
     else:
         semester_path = root_02450private + "/semesters/" + semester_id()
-    thtools.ensure_dir_exists(semester_path)
+
+    if not os.path.isdir(semester_path):
+        os.makedirs(semester_path)
 
     main_conf = semester_path + "/" + semester_id() + ".xlsx"
     if not os.path.exists(main_conf):
@@ -70,7 +72,8 @@ def get_paths():
     else:
         pass
     for (key, loc, template) in _files:
-        thtools.ensure_dir_exists(os.path.dirname(loc))
+        if not os.path.exists(os.path.dirname(loc)):
+            os.makedirs(os.path.dirname(loc))
         if not os.path.exists(loc):
             shutil.copyfile(template, loc)
         paths[key] = loc
diff --git a/src/coursebox/core/projects.py b/src/coursebox/core/projects.py
index 307e8cb47f75e744a472abe436a01cfbd3d33fe6..f8a37d0430d803023713c921dd2dec739a9f480f 100644
--- a/src/coursebox/core/projects.py
+++ b/src/coursebox/core/projects.py
@@ -5,7 +5,7 @@ import numpy as np
 import itertools
 import math
 import glob
-import zipfile
+# import zipfile
 from tika import parser
 from openpyxl.worksheet.datavalidation import DataValidation
 from openpyxl.utils import get_column_letter
@@ -13,18 +13,19 @@ import matplotlib.pyplot as plt
 import langdetect
 import xlwings as xw
 
-from thtools.coursebox.core.projects_info import get_output_file, INSTRUCTOR_ROW, STUDENT_ID_ROW, parse_column
-from thtools.coursebox.core.projects_info import EVALUATION_ROW_END, EVALUATION_ROW_START, WEIGHT_ROW_START, RANGE_MIN_COL, DELTA_ALLOWED_ROW
-from thtools.coursebox.core.info import get_paths, class_information, semester_id
-from thtools.coursebox.core import projects_info
-from thtools.coursebox.core.projects_plagiarism import plagiarism_checker
+from coursebox.core.projects_info import get_output_file, INSTRUCTOR_ROW, STUDENT_ID_ROW, parse_column
+from coursebox.core.projects_info import EVALUATION_ROW_END, EVALUATION_ROW_START, WEIGHT_ROW_START, RANGE_MIN_COL, DELTA_ALLOWED_ROW
+from coursebox.core.info import get_paths, class_information, semester_id
+from coursebox.core import projects_info
+from coursebox.core.projects_plagiarism import plagiarism_checker
 
-from thtools.cache import cache_contains_dir, cache_update_dir
-from thtools.plot.plot_helpers import get_colors
+from jinjafy.cache import cache_contains_dir, cache_update_dir
+from jinjafy.plot.plot_helpers import get_colors
 import time
-
 from collections import defaultdict
 import zipfile
+
+
 def get_dirs(zf):
     zip = zipfile.ZipFile(zf)
     fls = list(set([os.path.dirname(x) for x in zip.namelist()]))
@@ -35,7 +36,7 @@ def fix_handins_fuckup(project_id=2):
     """ Handle the problem with multiple hand-ins in DTU learn. """
     import zipfile
     paths = get_paths()
-    from thtools.coursebox.core.info import class_information
+    from coursebox.core.info import class_information
     info = class_information()
     zf = paths['instructor_project_evaluations'] + f"/zip{project_id}.zip"
 
diff --git a/src/coursebox/core/projects_info.py b/src/coursebox/core/projects_info.py
index 3da60f3f2b11dd6f915193a94c9c2b18c84ef9c6..0b2433184cc76668023684c0ae55218ff333eb7a 100644
--- a/src/coursebox/core/projects_info.py
+++ b/src/coursebox/core/projects_info.py
@@ -1,4 +1,4 @@
-from thtools.coursebox.core.info_paths import get_paths
+from coursebox.core.info_paths import get_paths
 import os
 import re
 import openpyxl
diff --git a/src/coursebox/material/__pycache__/__init__.cpython-38.pyc b/src/coursebox/material/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b18a9bc8d10c6a18a2f0a18ea89fcc6049754efc
Binary files /dev/null and b/src/coursebox/material/__pycache__/__init__.cpython-38.pyc differ
diff --git a/src/coursebox/material/__pycache__/homepage_lectures_exercises.cpython-38.pyc b/src/coursebox/material/__pycache__/homepage_lectures_exercises.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7fbf6d0fa20cc775ab5f264daaea2e53dae055f9
Binary files /dev/null and b/src/coursebox/material/__pycache__/homepage_lectures_exercises.cpython-38.pyc differ
diff --git a/src/coursebox/material/__pycache__/lecture_questions.cpython-38.pyc b/src/coursebox/material/__pycache__/lecture_questions.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e66197689c863bc31c59715e6582b5a2372276f2
Binary files /dev/null and b/src/coursebox/material/__pycache__/lecture_questions.cpython-38.pyc differ
diff --git a/src/coursebox/material/__pycache__/snipper.cpython-38.pyc b/src/coursebox/material/__pycache__/snipper.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..01866b2826347606df13268f4052d9d722791851
Binary files /dev/null and b/src/coursebox/material/__pycache__/snipper.cpython-38.pyc differ
diff --git a/src/coursebox/material/homepage_lectures_exercises.py b/src/coursebox/material/homepage_lectures_exercises.py
index d172128c9046e9e840eb222e7980fbac2802b90a..b225ab87b393c5be9808e71c5161213a78aadde0 100644
--- a/src/coursebox/material/homepage_lectures_exercises.py
+++ b/src/coursebox/material/homepage_lectures_exercises.py
@@ -3,6 +3,8 @@ import shutil, os, glob
 from datetime import datetime, timedelta
 import calendar
 import pickle
+
+import slider
 from jinjafy import jinjafy_comment
 from jinjafy import jinjafy_template
 from coursebox.core.info_paths import get_paths
@@ -12,7 +14,8 @@ from slider.slider import set_svg_background_images
 from coursebox.book.exam_includer import HOMEWORK_PROBLEMS
 from coursebox.core.info import class_information
 from coursebox.material.lecture_questions import lecture_question_compiler
-from thtools import latexmk
+from slider import latexmk
+import coursebox
 
 def get_feedback_groups():
     paths = get_paths()
@@ -44,7 +47,7 @@ def get_feedback_groups():
     reduced_groups = [rg for rg in reduced_groups if len(rg)>0]
     # groups are now partitioned.
     if len(remaining_lectures) > 0:
-        fbgs = thtools.thtools_base.partition_list(reduced_groups, len(remaining_lectures))
+        fbgs = coursebox.thtools_base.partition_list(reduced_groups, len(remaining_lectures))
         for gg in fbgs:
             for g in gg:
                 already_used = already_used + g
@@ -154,7 +157,7 @@ def make_lectures(week=None, mode=0, gather_pdf_out=True, gather_sixup=True, mak
         if make_quizzes:
             lecture_question_compiler(paths, info, lecture_texfile)
 
-        pdf_out = thtools.latexmk(lecture_texfile, Linux=Linux)
+        pdf_out = slider.latexmk(lecture_texfile, Linux=Linux)
         all_pdfs.append( (w,pdf_out))
 
     handle_pdf_collection(paths, all_pdfs, gather_pdf_out=gather_pdf_out, gather_sixup=gather_sixup, odir=odex)
@@ -180,7 +183,7 @@ def handle_pdf_collection(paths, all_pdfs, gather_pdf_out, gather_sixup, odir):
                 tv['sixup'] = sixup
                 tex_out_sixup = tmp_dir + "/Lecture_%i%s.tex" % (week, sixup_str)
                 jinjafy_comment(data=tv, file_in=collect_template, file_out=tex_out_sixup, jinja_tag=None)
-                dpdf = tmp_dir + "/" + thtools.latexmk(tex_out_sixup, shell=False, cleanup=True)
+                dpdf = tmp_dir + "/" + slider.latexmk(tex_out_sixup, shell=False, cleanup=True)
             else:
                 dpdf = tv['pdffiles'][0]
 
@@ -212,16 +215,16 @@ def compile_simple_files(paths, info, template_file_list, verbose=False):
             file = file.replace("_template.tex", ".tex")
         tex_out = paths['shared_latex_compilation_dir'] + "/" + file
         jinjafy_template(data=d2, file_in=fname, file_out=tex_out, filters=get_filters(), template_searchpath=paths['instructor'])
-        thtools.latexmk(tex_out, pdf_out= paths['pdf_out'] + "/" + os.path.basename(tex_out)[:-4]+".pdf")
+        latexmk(tex_out, pdf_out= paths['pdf_out'] + "/" + os.path.basename(tex_out)[:-4]+".pdf")
 
 def fix_shared(paths, output_dir, pdf2png=False,dosvg=True,verbose=False, compile_templates=True):
     '''
     Copy shared files into lecture directories
     '''
     cache_base = output_dir
-    from thtools.cache import cache_contains_file, cache_update_file
-    from thtools.slider.convert import svg2pdf, pdfcrop
-    from thtools.slider import convert
+    from jinjafy.cache import cache_contains_file, cache_update_file
+    from slider.convert import svg2pdf, pdfcrop
+    from slider import convert
 
     def rec_fix_shared(shared_base, output_dir):
         if dosvg:
diff --git a/src/coursebox/material/lecture_questions.py b/src/coursebox/material/lecture_questions.py
index cac5f9fa1490fccd4042952ef7fc1fad3395c80f..5991e4f76a28995db83d09c4fbd90385e7dbfd84 100644
--- a/src/coursebox/material/lecture_questions.py
+++ b/src/coursebox/material/lecture_questions.py
@@ -2,11 +2,11 @@ import os
 import shutil
 import glob
 
-from thtools.jinjafy import jinjafy_template
-from thtools import latexmk
-from thtools import execute_command
-from thtools.slider.slider import slide_no_by_text, recursive_tex_apply
-from thtools.slider.legacy_importer import slide_to_image
+from jinjafy import jinjafy_template
+from slider import latexmk
+from coursebox.thtools_base import execute_command
+from slider.slider import slide_no_by_text, recursive_tex_apply
+from slider.legacy_importer import slide_to_image
 
 
 def lecture_question_compiler(paths, info, lecture_texfile):
diff --git a/src/coursebox/material/snipper.py b/src/coursebox/material/snipper.py
index 77f330f055662520674bf3c6c41eda43bcbc7aab..b0bee23a70410914dca22c4856fbb19900d3b0d9 100644
--- a/src/coursebox/material/snipper.py
+++ b/src/coursebox/material/snipper.py
@@ -1,7 +1,7 @@
-from thtools.coursebox.core.info import find_tex_cite
+from coursebox.core.info import find_tex_cite
 import os
 import functools
-from thtools import execute_command
+from jinjafy import execute_command
 import textwrap
 import re
 
@@ -118,8 +118,9 @@ def run_i(lines, file, output):
         lines = textwrap.dedent(s).strip().splitlines()
 
         if extra['python'] is None:
-            import thtools
-            if thtools.is_win():
+            # import thtools
+
+            if os.name == 'nt':
                 import wexpect as we
             else:
                 import pexpect as we
diff --git a/src/coursebox/thtools_base.py b/src/coursebox/thtools_base.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b42df839167c393b00b998feb3d3bb84c579250
--- /dev/null
+++ b/src/coursebox/thtools_base.py
@@ -0,0 +1,155 @@
+import os
+import platform
+import subprocess
+import inspect
+
+
+def is_win():
+    # if sys.platform()
+    return platform.uname()[0].startswith("Windows")
+
+
+def is_compute():
+    return platform.uname()[1] == "linuxterm1"
+
+
+def is_gbar():
+    return False
+
+def is_cogsys_cluster():
+    return platform.uname()[0] == "Linux" and os.path.exists("/dtu-compute") and not is_compute()
+
+def is_cluster():
+    return is_compute() or is_gbar() or is_cogsys_cluster()
+
+def get_system_name():
+    if is_win():
+        return "Win"
+    if is_compute():
+        return "thinlinc.compute.dtu.dk"
+    if is_cogsys_cluster():
+        return "cogys cluster"
+
+def execute_command(command, shell=True):
+    if not isinstance(command, list):
+        command = [command]
+    if not is_compute():
+        result = subprocess.run(command, stdout=subprocess.PIPE, shell=shell)
+        out = result.stdout
+    else:
+        out = subprocess.check_output(command, shell=shell)
+    s = out.decode("utf-8")
+    OK = True
+    return s, OK
+
+# def git_pull(repo_dir=None):
+#     import pbs # should switch to sh when it gets windows support.
+#     gitty = pbs.Command('git')
+#     # args = {}
+#     # if repo_dir is not None:
+#     #     kwargs = {'_cwd': repo_dir}
+#     # if repo_dir is not None:
+#     r = gitty("pull", _cwd=repo_dir)
+#     # else:
+#     #     r = gitty("pull")
+#     err = r.stderr
+#     if err is not None and err is not "":
+#         print("thtools_base.git_pull(), encountered error", err)
+
+
+# def git_commit_push(repo_dir=None, commit="default commit message from thtools farm"):
+#     import pbs
+#     gitty = pbs.Command('git')
+#     # probably it is a good idea to check the status
+#
+#     # repo_dir
+#
+#     r1 = gitty("add", ".", _cwd=repo_dir)
+#     try:
+#         r2 = gitty("commit", "-m'%s'"%commit, _cwd=repo_dir)
+#     except pbs.ErrorReturnCode_1:
+#         print("Error in git push!")
+#         # print(r2.stderr)
+#
+#     r3 = gitty("push",  _cwd=repo_dir)
+
+
+# Returns the base root of thtools
+# def thtools_root_dir():
+#     frame = inspect.stack()[0]
+#     module = inspect.getmodule(frame[0])
+#     file_in = os.path.dirname(module.__file__)
+#     return file_in
+
+
+def get_callstack(nback=2):
+    x = inspect.currentframe()
+    for j in range(nback):
+        x = x.f_back
+    ff = os.path.abspath(inspect.getfile(x))
+    return ff, x.f_lineno, x
+
+
+def caller_script_path():
+    frame = inspect.stack()[1]
+    module = inspect.getmodule(frame[0])
+    file_in = module.__file__
+    return file_in
+
+
+def pprint(d, indent=0):
+   for key, value in d.items():
+      print('\t' * indent + str(key))
+      if isinstance(value, dict):
+         pprint(value, indent+1)
+      else:
+         print('\t' * (indent+1) + str(value))
+
+def list_dict2dict_list(lst, along_new_axis=True):
+    import numpy as np
+    if not lst:
+        return dict()
+    dc = dict()
+    for key in lst[0].keys():
+        dc[key] = np.stack([l[key] for l in lst if key in l], axis=0)
+    if not along_new_axis:
+        raise Exception("Should probably implement new axis = false")
+    return dc
+
+
+def partition_list(I,K,randomize=False):
+    import numpy as np
+    J = np.arange(len(I))
+    if randomize:
+        J = np.random.permutation(J)
+
+    spl = np.array_split(J, K)
+    di = []
+    for chunk in spl:
+        x = []
+        for j in chunk:
+            x.append(I[j])
+        di.append(x)
+    return di
+
+
+def watermark_string(nback=2):
+
+    from datetime import datetime
+
+    tm =  datetime.now().strftime('%b-%d-%I:%M%p')
+    # for line in traceback.format_stack():
+    #     #     print(line.strip())
+    v = inspect.stack()
+    ss = []
+    j = 0
+    for i in range(len(v)):
+        if "plot_helpers.py" in v[i].filename: continue
+        ss.append( os.path.basename( v[i].filename) )
+        j = j + 1
+        if j > nback: break
+    # from thtools import execute_command
+    v, _ = execute_command("git rev-parse --short HEAD".split())
+
+    ss.append(tm)
+    return ('/'.join(ss) + f" @{v}").strip()