diff --git a/0.1.11 b/0.1.11
deleted file mode 100644
index b5f99d0ce8e8c3b214d0a7d4e7a694490eeffed9..0000000000000000000000000000000000000000
--- a/0.1.11
+++ /dev/null
@@ -1,10 +0,0 @@
-Requirement already satisfied: codesnipper in c:\users\tuhe\appdata\local\programs\python\python310\lib\site-packages (0.1.11)
-Requirement already satisfied: wexpect in c:\users\tuhe\appdata\local\programs\python\python310\lib\site-packages (from codesnipper) (4.0.0)
-Requirement already satisfied: pybtex in c:\users\tuhe\appdata\local\programs\python\python310\lib\site-packages (from codesnipper) (0.24.0)
-Requirement already satisfied: pexpect in c:\users\tuhe\appdata\local\programs\python\python310\lib\site-packages (from codesnipper) (4.8.0)
-Requirement already satisfied: ptyprocess>=0.5 in c:\users\tuhe\appdata\local\programs\python\python310\lib\site-packages (from pexpect->codesnipper) (0.7.0)
-Requirement already satisfied: six in c:\users\tuhe\appdata\local\programs\python\python310\lib\site-packages (from pybtex->codesnipper) (1.16.0)
-Requirement already satisfied: latexcodec>=1.0.4 in c:\users\tuhe\appdata\local\programs\python\python310\lib\site-packages (from pybtex->codesnipper) (2.0.1)
-Requirement already satisfied: PyYAML>=3.01 in c:\users\tuhe\appdata\local\programs\python\python310\lib\site-packages (from pybtex->codesnipper) (6.0)
-Requirement already satisfied: pywin32>=220 in c:\users\tuhe\appdata\local\programs\python\python310\lib\site-packages (from wexpect->codesnipper) (304)
-Requirement already satisfied: psutil>=5.0.0 in c:\users\tuhe\appdata\local\programs\python\python310\lib\site-packages (from wexpect->codesnipper) (5.9.1)
diff --git a/setup.py b/setup.py
index 7309a30b4a993fa6129733762e50c0cf22ef7791..8f1847547645ab503defc73c09ff2eb7f2d369a0 100644
--- a/setup.py
+++ b/setup.py
@@ -2,6 +2,8 @@
 # Use:  pipreqs.exe slider --no-pin --force for requirements_pip.txt
 # https://packaging.python.org/tutorials/packaging-projects/
 # py -m build && twine upload dist/*
+# Linux> python -m build && twine upload dist/*
+# Local install: sudo pip install -e ./
 
 import setuptools
 import pkg_resources
diff --git a/src/codesnipper.egg-info/PKG-INFO b/src/codesnipper.egg-info/PKG-INFO
index 1415e4f4a4163f11e0dfb7633e48481046a139e1..055fae08a3ba7de7f27371026f392ee3c4273a02 100644
--- a/src/codesnipper.egg-info/PKG-INFO
+++ b/src/codesnipper.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: codesnipper
-Version: 0.1.11
+Version: 0.1.14
 Summary: A lightweight framework for censoring student solutions files and extracting code + output
 Home-page: https://lab.compute.dtu.dk/tuhe/snipper
 Author: Tue Herlau
diff --git a/src/codesnipper.egg-info/requires.txt b/src/codesnipper.egg-info/requires.txt
index 4ba7d8fcd57f03899543a71a0d303d13cb5072a3..cdc5a5a821191c5ff35eb9ae362a55f75f8cc512 100644
--- a/src/codesnipper.egg-info/requires.txt
+++ b/src/codesnipper.egg-info/requires.txt
@@ -1,3 +1,4 @@
 pexpect
 wexpect
 pybtex
+numpy
diff --git a/src/snipper/block_parsing.py b/src/snipper/block_parsing.py
index d8996d86bf7c37ad76f343f29a77faea42cba068..ebca172b8154c4aa4b23fdb1d94da18417930ed8 100644
--- a/src/snipper/block_parsing.py
+++ b/src/snipper/block_parsing.py
@@ -37,7 +37,12 @@ def block_split(lines, tag):
     def get_tag_args(line):
         # line = line.strip()
         k = line.find(" ")
+        if 'nodoc' in line:
+            print("Nodoc!!")
         tag_args = ((line[:k + 1] if k >= 0 else line)[len(tag):] ).strip().split(";")
+        if 'nodoc' in tag_args:
+            print("nodoc.")
+
         tag_args = [t.strip() for t in tag_args]
         # if len(tag_args) == 0:
         #     return {'': ''}  # No name.
@@ -46,7 +51,8 @@ def block_split(lines, tag):
 
         if '' not in tag_args:
             tag_args[''] = ''
-
+        if "dse" in tag_args:
+            print("DSE!!!")
         return tag_args
 
     if i is None:
diff --git a/src/snipper/fix_cite.py b/src/snipper/fix_cite.py
index a76120a635acc9b2791f50c33e4b57a01906274c..b27dc91d73113ae4b8cd2ca6cac62a637aaf4eec 100644
--- a/src/snipper/fix_cite.py
+++ b/src/snipper/fix_cite.py
@@ -11,7 +11,8 @@ def fix_citations(lines, references, strict=True, file=None):
     """
     if str(file).endswith(".rst"):
         print(file)
-    lines = fix_aux(lines, aux=references.get('aux', {}) )
+    # lines = fix_aux(lines, )
+    lines = fix_single_reference(lines, aux=references.get('aux', {}), cmd="\\ref", strict=True)
     for cm in references.get('commands', []):
         # Probably just go with this one.
         lines = fix_aux_special(lines, aux=cm['aux'], command=cm['command'], output=cm['output'])
@@ -29,11 +30,10 @@ def fix_aux_special(lines, aux, command='\\nref', output='\cite[%s]{my_bibtex_en
     l2 = fix_single_reference(lines, aux=daux, cmd=command, strict=True)
     return l2
 
-def fix_aux(lines, aux, strict=True):
-    print("fix_cite.py/fix_aux() deprecated...")
-    l2 = fix_single_reference(lines, aux=aux, cmd="\\ref", strict=True)
-    # print("\n".join(l2))
-    return l2
+# def fix_aux(lines, aux, strict=True):
+#     print("fix_cite.py/fix_aux() deprecated...")
+# print("\n".join(l2))
+# return l2
 
 
 def fix_bibtex(lines, bibtex, rst_mode=False):
@@ -64,7 +64,7 @@ def fix_bibtex(lines, bibtex, rst_mode=False):
         s = s[:i] + rtxt + s[j+1:]
         i = i + len(rtxt)
 
-    if len(all_refs) > 0:
+    if len(all_refs) > 0 and not rst_mode: # Don't add the license head in RST mode. The user is responsible for including references in sphinx conf.py.
         if not s.startswith(COMMENT):
             s = f"{COMMENT}\n{COMMENT}\n" + s
         i = s.find(COMMENT, s.find(COMMENT)+1)
diff --git a/src/snipper/fix_i.py b/src/snipper/fix_i.py
index 28b5bfbe733929b4083e490cdae58d86d511caf9..296dc0ccb1842780a315aa7fe0e73c47a064bdb3 100644
--- a/src/snipper/fix_i.py
+++ b/src/snipper/fix_i.py
@@ -9,65 +9,125 @@ else:
     import pexpect as we
 
 
+def rsession(analyzer, lines, extra):
+    l2 = []
+    dbug = False
+    # analyzer = we.spawn("python", encoding="utf-8", timeout=20)
+    # analyzer.expect([">>>"])
+    if "BetterBasicDog" in "\n".join(lines) and False:
+        print("\n".join(lines))
+        print("-"*50)
+        for k in extra['session_results']:
+            print(k['input'])
+            print(k['output'])
+
+        import time
+        an = we.spawn("python", encoding="utf-8", timeout=20)
+        an.expect([">>>"])
+        l3 = """
+import numpy as np 
+from scipy.linalg import norm
+x = np.asarray([3, 4])
+x  # What is x?
+norm(x)"""
+        lines2 = l3.strip().splitlines()
+
+        for l in lines2:
+            an.sendline(l)
+            an.expect_exact([">>>", "..."])
+            print("INPUT", l)
+            print(">>>", an.before.strip())
+            if len(an.after.strip()) > 4:
+                print(">>>>>>>>>>>>> That was a long after?")
+            # analyzer.be
+
+        print('*' * 50)
+        # analyzer = an
+        dbug = True
+    lines = "\n".join(lines).replace("\r", "").splitlines()
+
+    for i, l in enumerate(lines):
+        l2.append(l)
+        if l.startswith(" ") and i < len(lines)-1 and not lines[i+1].startswith(" "):
+            if not lines[i+1].strip().startswith("else:") and not lines[i+1].strip().startswith("elif") :
+                l2.append("") # Empty line instead?
+
+    lines = l2
+    alines = []
+    in_dot_mode = False
+    if len(lines[-1]) > 0 and (lines[-1].startswith(" ") or lines[-1].startswith("\t")):
+        lines += [""]
+
+
+    for i, word in enumerate(lines):
+        if dbug:
+            print("> Sending...", word)
+        analyzer.sendline(word.rstrip())
+        import time
+        before = ""
+        while True:
+            time.sleep(0.05)
+            analyzer.expect_exact([">>>", "..."])
+            if dbug and "total_cost" in word:
+                aaa = 23234
+            before += analyzer.before
+            # if dbug:
+            print(">  analyzer.before...", analyzer.before.strip(), "...AFTER...", analyzer.after.strip())
+            # AFTER =
+            if analyzer.before.endswith("\n"):
+                print("> BREAKING LOOP")
+                break
+                pass
+            else:
+                before += analyzer.after
+            break
+
+
+        # print("Before is", before)
+        abefore = analyzer.before.rstrip()
+        # Sanitize by removing garbage binary stuff the terminal puts in
+        abefore = "\n".join([l for l in abefore.splitlines() if not l.startswith('\x1b')] )
+
+
+        dotmode = analyzer.after == "..."
+        if 'dir(s)' in word:
+            pass
+        if 'help(s.find)' in word:
+            pass
+        if dotmode:
+            alines.append(">>>" +abefore.rstrip() if not in_dot_mode else "..." + abefore.rstrip())
+            in_dot_mode = True
+        else:
+            alines.append( ("..." if in_dot_mode else ">>>") + abefore.rstrip())
+            in_dot_mode = False
+    if dbug:
+        print("-"*50)
+        print("\n".join(alines))
+    extra['session_results'].append({'input': '\n'.join(lines), 'output': '\n'.join(alines)})
+    return alines
+
+
 def run_i(lines, file, output):
-    extra = dict(python=None, output=output, evaluated_lines=0)
+    extra = dict(python=None, output=output, evaluated_lines=0, session_results=[])
     def block_fun(lines, start_extra, end_extra, art, head="", tail="", output=None, extra=None):
         outf = output + ("_" + art if art is not None and len(art) > 0 else "") + ".shell"
         lines = full_strip(lines)
         s = "\n".join(lines)
         s.replace("...", "..") # passive-aggressively truncate ... because of #issues.
         lines = textwrap.dedent(s).strip().splitlines()
+        # an.setecho(True) # TH January 2023: Seems to fix an issue on linux with truncated lines. May cause problems on windows?
 
         if extra['python'] is None:
             an = we.spawn("python", encoding="utf-8", timeout=20)
             an.expect([">>>"])
             extra['python'] = an
 
-        analyzer = extra['python']
-        def rsession(analyzer, lines):
-            l2 = []
-            for i, l in enumerate(lines):
-                l2.append(l)
-                if l.startswith(" ") and i < len(lines)-1 and not lines[i+1].startswith(" "):
-                    if not lines[i+1].strip().startswith("else:") and not lines[i+1].strip().startswith("elif") :
-                        l2.append("\n")
-
-            lines = l2
-            alines = []
-            in_dot_mode = False
-            if len(lines[-1]) > 0 and (lines[-1].startswith(" ") or lines[-1].startswith("\t")):
-                lines += [""]
-
-            for i, word in enumerate(lines):
-                analyzer.sendline(word)
-                before = ""
-                while True:
-                    analyzer.expect_exact([">>>", "..."])
-                    before += analyzer.before
-                    if analyzer.before.endswith("\n"):
-                        break
-                    else:
-                        before += analyzer.after
-
-                dotmode = analyzer.after == "..."
-                if 'dir(s)' in word:
-                    pass
-                if 'help(s.find)' in word:
-                    pass
-                if dotmode:
-                    alines.append(">>>" + analyzer.before.rstrip() if not in_dot_mode else "..." + analyzer.before.rstrip())
-                    in_dot_mode = True
-                else:
-                    alines.append( ("..." if in_dot_mode else ">>>") + analyzer.before.rstrip())
-                    in_dot_mode = False
-            return alines
-
-        for l in (head[extra['evaluated_lines']:] + ["\n"]):
-            analyzer.sendline(l)
-            analyzer.expect_exact([">>>", "..."])
-
-
-        alines = rsession(analyzer, lines)
+        # analyzer = extra['python']
+        # What does this do?
+        # for l in (head[extra['evaluated_lines']:] + ["\n"]):
+        #     analyzer.sendline(l)
+        #     analyzer.expect_exact([">>>", "..."])
+        alines = rsession(extra['python'], lines, extra) # give it the analyzer
         extra['evaluated_lines'] += len(head) + len(lines)
         lines = alines
         return lines, [outf, lines]
@@ -81,6 +141,8 @@ def run_i(lines, file, output):
             for outf in kvs:
                 out = "\n".join( ["\n".join(v[1]) for v in c if v[0] == outf] )
                 out = out.replace("\r", "")
+                if outf.endswith("python0B_e4.shell"):
+                    print(outf)
 
                 with open(outf, 'w') as f:
                     f.write(out)
diff --git a/src/snipper/fix_s.py b/src/snipper/fix_s.py
index 5a97096a6321ddab15efa6cd46f900777476b92a..a6eff7e8024db8eb6011f39db9b9f4eff1d7aa27 100644
--- a/src/snipper/fix_s.py
+++ b/src/snipper/fix_s.py
@@ -2,6 +2,8 @@ from collections import defaultdict
 import os
 from snipper.block_parsing import block_iterate
 from snipper.snipper_main import full_strip
+from snipper.block_parsing import indent
+
 
 def get_s(lines):
     """ Return snips from 'lines' """
@@ -13,7 +15,11 @@ def get_s(lines):
         else:
             # In this case the #! tags are kept in.
             pass
-            # print("keepting tags.")
+        if 'dse' in c['start_tag_args']:
+            print("asdfasdfs")
+        print(c['start_tag_args'])
+        if 'nodoc' in c['start_tag_args'] and c['start_tag_args']['nodoc']:
+            print("No documentation!")
         blocks[c['name']].append(c)
 
     output = {}
@@ -23,9 +29,54 @@ def get_s(lines):
         # c['block']['args']
         # slines = slines[ 23]
         # co.
+
+
+
+        # if slines[f.lineno].strip().startswith('"' * 3):
+        #     print("got a docstrnig")
+        #     for k in range(f.lineno, f.end_lineno + 1):
+        #         l = slines[k] if k != f.lineno else slines[k].strip()[3:]
+        #         if l.find('"' * 3) >= 0:
+        #             break
+        # else:
+        #     k = -1
+        # if k > 0:
+        #     print("Docstring detected")
+        #     for i in range(f.lineno, k + 1):
+        #         ll2[i] = None
         output[name] = slines
     return output
 
+def rm_docstring(lines):
+    source = "\n".join(slines)
+    import ast
+    node = ast.parse(source)
+    classes = [n for n in node.body if isinstance(n, ast.ClassDef)]
+    functions = [n for n in node.body if isinstance(n, ast.FunctionDef)]
+    ll2 = slines.copy()
+
+    def rm_ds(f, ll2):
+        if slines[f.lineno].strip().startswith('"' * 3):
+            # print("got a docstrnig")
+            for k in range(f.lineno, f.end_lineno + 1):
+                l = slines[k] if k != f.lineno else slines[k].strip()[3:]
+                if l.find('"' * 3) >= 0:
+                    break
+        else:
+            k = -1
+        if k > 0:
+            # print("Docstring detected")
+            for i in range(f.lineno, k + 1):
+                ll2[i] = None
+
+    for f in functions:
+        rm_ds(f, ll2)
+    for c in classes:
+        for f in c.body:
+            rm_ds(f, ll2)
+    return [l for l in ll2 if l is not None]
+
+
 # def _s_block_process():
 #
 #     pass
@@ -39,12 +90,23 @@ def save_s(lines, output_dir, file_path): # save file snips to disk
     for name, ll in content.items():
         if file_path is not None:
             file_path = file_path.replace("\\", "/")
-            ll = [f"# {file_path}"] + ll
+            ll = [f"{indent(ll[0])}# {file_path}"] + ll
+
         out = "\n".join(ll)
 
-        with open(output_dir + "/" + os.path.basename(file_path)[:-3] + ("_" + name if len(name) > 0 else name) + ".py", 'w') as f:
+        fname = output_dir + "/" + os.path.basename(file_path)[:-3] + ("_" + name if len(name) > 0 else name) + ".py"
+        with open(fname, 'w') as f:
             f.write(out)
 
+        # Dedent it for better plotting.
+        fname_stripped = fname[:-3] + "_stripped.py"
+        id = [indent(l) for l in ll if len(l.strip()) > 0]
+        id_len = [len(i) for i in id]
+        mindex = id_len[id_len.index(min(id_len))]
+        out2 = "\n".join([l[mindex:] for l in ll])
+
+        with open(fname_stripped, 'w') as f:
+            f.write(out2)
 
 s1 = """
 L1
diff --git a/src/snipper/version.py b/src/snipper/version.py
index 6dbb672ffb8889efcd413672815cdfb59af8a81a..f3b45743bddc02aadc17cb38557a5867e733caf7 100644
--- a/src/snipper/version.py
+++ b/src/snipper/version.py
@@ -1,4 +1 @@
-__version__ = "0.1.12"
-
-# /builds/02465material/02465public
-# /builds/02465material/02465public
\ No newline at end of file
+__version__ = "0.1.15"