From a6734a9a62c7c74b550cc0097de25a9c87a67270 Mon Sep 17 00:00:00 2001
From: Tue Herlau <tuhe@dtu.dk>
Date: Mon, 13 Sep 2021 15:31:15 +0200
Subject: [PATCH] Updates to readme.md

---
 .gitignore                                    | 138 ++++++++++++++++++
 .../__pycache__/__init__.cpython-36.pyc       | Bin 149 -> 0 bytes
 .../cs101report1_grade.cpython-36.pyc         | Bin 2656 -> 0 bytes
 .../__pycache__/__init__.cpython-36.pyc       | Bin 152 -> 0 bytes
 .../__pycache__/__init__.cpython-38.pyc       | Bin 160 -> 0 bytes
 .../__pycache__/cs101report1.cpython-36.pyc   | Bin 2741 -> 0 bytes
 .../cs101report1_grade.cpython-36.pyc         | Bin 2703 -> 0 bytes
 .../__pycache__/homework1.cpython-36.pyc      | Bin 1189 -> 0 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 1208 -> 0 bytes
 docs/README.jinja.md                          |  97 ++++++------
 .../cs101courseware}/cs101report1_grade.py    |   0
 .../Report0_handin_18_of_18.token             | Bin
 .../Report0_resources_do_not_hand_in.dat      | Bin
 .../cs101courseware_example}/Report1.xlsx     | Bin
 .../Report1_handin_18_of_18.token             | Bin
 .../Report1_resources_do_not_hand_in.dat      | Bin
 .../Report2_resources_do_not_hand_in.dat      | Bin
 .../cs101courseware_example}/__init__.py      |   0
 .../cs101courseware_example}/cs101report1.py  |   0
 .../cs101report1_grade.py                     |   0
 .../cs101courseware_example}/cs101report2.py  |   0
 .../cs101report2_grade.py                     |   0
 .../cs101courseware_example}/homework1.py     |   0
 .../cs101courseware_example}/instructions.py  |   0
 docs/mkdocs.py                                |   1 -
 setup.py                                      |   7 +-
 src/unitgrade.egg-info/PKG-INFO               |  20 ++-
 src/unitgrade.egg-info/SOURCES.txt            |   5 +
 src/unitgrade.egg-info/requires.txt           |   4 +-
 src/unitgrade.egg-info/top_level.txt          |   1 +
 {unitgrade => src/unitgrade}/__init__.py      |   0
 {unitgrade => src/unitgrade}/unitgrade.py     |   0
 .../unitgrade}/unitgrade_grade.py             |   0
 .../unitgrade}/unitgrade_helpers.py           |   0
 {unitgrade => src/unitgrade}/version.py       |   0
 src/unitgrade2/__init__.py                    |  70 +++++----
 .../__pycache__/__init__.cpython-38.pyc       | Bin 1306 -> 494 bytes
 .../__pycache__/unitgrade2.cpython-38.pyc     | Bin 22740 -> 22788 bytes
 .../unitgrade_helpers2.cpython-38.pyc         | Bin 7000 -> 6853 bytes
 .../__pycache__/version.cpython-38.pyc        | Bin 171 -> 171 bytes
 src/unitgrade2/unitgrade2.py                  |  53 ++-----
 src/unitgrade2/unitgrade_helpers2.py          |  32 ++--
 src/unitgrade2/version.py                     |   2 +-
 unitgrade/__pycache__/__init__.cpython-36.pyc | Bin 998 -> 0 bytes
 unitgrade/__pycache__/__init__.cpython-38.pyc | Bin 1316 -> 0 bytes
 .../__pycache__/unitgrade.cpython-36.pyc      | Bin 11636 -> 0 bytes
 .../__pycache__/unitgrade.cpython-38.pyc      | Bin 14886 -> 0 bytes
 .../unitgrade_helpers.cpython-36.pyc          | Bin 5594 -> 0 bytes
 .../unitgrade_helpers.cpython-38.pyc          | Bin 8338 -> 0 bytes
 unitgrade/__pycache__/version.cpython-38.pyc  | Bin 166 -> 0 bytes
 50 files changed, 290 insertions(+), 140 deletions(-)
 create mode 100644 .gitignore
 delete mode 100644 cs101courseware/__pycache__/__init__.cpython-36.pyc
 delete mode 100644 cs101courseware/__pycache__/cs101report1_grade.cpython-36.pyc
 delete mode 100644 cs101courseware_example/__pycache__/__init__.cpython-36.pyc
 delete mode 100644 cs101courseware_example/__pycache__/__init__.cpython-38.pyc
 delete mode 100644 cs101courseware_example/__pycache__/cs101report1.cpython-36.pyc
 delete mode 100644 cs101courseware_example/__pycache__/cs101report1_grade.cpython-36.pyc
 delete mode 100644 cs101courseware_example/__pycache__/homework1.cpython-36.pyc
 delete mode 100644 cs101courseware_example/__pycache__/homework1.cpython-38.pyc
 rename {cs101courseware => docs/legacy/cs101courseware}/cs101report1_grade.py (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/Report0_handin_18_of_18.token (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/Report0_resources_do_not_hand_in.dat (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/Report1.xlsx (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/Report1_handin_18_of_18.token (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/Report1_resources_do_not_hand_in.dat (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/Report2_resources_do_not_hand_in.dat (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/__init__.py (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/cs101report1.py (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/cs101report1_grade.py (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/cs101report2.py (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/cs101report2_grade.py (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/homework1.py (100%)
 rename {cs101courseware_example => docs/legacy/cs101courseware_example}/instructions.py (100%)
 rename {unitgrade => src/unitgrade}/__init__.py (100%)
 rename {unitgrade => src/unitgrade}/unitgrade.py (100%)
 rename {unitgrade => src/unitgrade}/unitgrade_grade.py (100%)
 rename {unitgrade => src/unitgrade}/unitgrade_helpers.py (100%)
 rename {unitgrade => src/unitgrade}/version.py (100%)
 delete mode 100644 unitgrade/__pycache__/__init__.cpython-36.pyc
 delete mode 100644 unitgrade/__pycache__/__init__.cpython-38.pyc
 delete mode 100644 unitgrade/__pycache__/unitgrade.cpython-36.pyc
 delete mode 100644 unitgrade/__pycache__/unitgrade.cpython-38.pyc
 delete mode 100644 unitgrade/__pycache__/unitgrade_helpers.cpython-36.pyc
 delete mode 100644 unitgrade/__pycache__/unitgrade_helpers.cpython-38.pyc
 delete mode 100644 unitgrade/__pycache__/version.cpython-38.pyc

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5391d87
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,138 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+#   For a library or package, you might want to ignore these files since the code is
+#   intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
\ No newline at end of file
diff --git a/cs101courseware/__pycache__/__init__.cpython-36.pyc b/cs101courseware/__pycache__/__init__.cpython-36.pyc
deleted file mode 100644
index d33bfab045b3ca7b901756260b46811e19f99be0..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 149
zcmXr!<>gv6<9Iv+0|Ucj5COxC3=9ko3=9m#EDQ_`DGb33nv8xc8Hzx{2;!HMvsFxJ
zacWU<Oi5`*YK%*Ma%paAUP*C`k%5sxOle+bNqSLYN@`4Uv7v!sa(-!1acX&DQEE(l
dd}dx|NqoFsLFFwDo80`A(wtN~klDo``vG3xCJz7r

diff --git a/cs101courseware/__pycache__/cs101report1_grade.cpython-36.pyc b/cs101courseware/__pycache__/cs101report1_grade.cpython-36.pyc
deleted file mode 100644
index 8de424470b4aaa51585fb35660bf3c8d4221dcf7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2656
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

diff --git a/cs101courseware_example/__pycache__/__init__.cpython-36.pyc b/cs101courseware_example/__pycache__/__init__.cpython-36.pyc
deleted file mode 100644
index 98d393f34d0bda15a5bea3d0235370d3a1f2b301..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 152
zcmXr!<>g8_bR(XDfq~&Mh=5^61_lNP1_p*=76t}}6oz01O-8?!3`HPe1o6w&*(xTq
zIJKxarld3@HO3`BximL5ucSDpG%vFxy(lpyH72>((7-S`zqF`0wLGyXH9oZ>F}ENm
gH6}hjGcU6wK3=b&@)n0pZhlH>PO2Tq_+pR~01(h9G5`Po

diff --git a/cs101courseware_example/__pycache__/__init__.cpython-38.pyc b/cs101courseware_example/__pycache__/__init__.cpython-38.pyc
deleted file mode 100644
index b4b9f0b3284b408c2767cd2e0f124b2b7a70cb86..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 160
zcmWIL<>g{vU|>)aIhFvTAA<;F%*epN;K0DZP|U)>z>vZa%%I8Wx00a<B#a<_xjI|L
zgche36~~m6W~9cr<R_QrrskCt$CTz}mZTRYrliIs7aJNFCg+zH6{nUb7Ny3gRwU*Y
i<fO*L$7kkcmc+;F6;$5hu*uC&Da}c>0~!Ar<O~3!*eBNj

diff --git a/cs101courseware_example/__pycache__/cs101report1.cpython-36.pyc b/cs101courseware_example/__pycache__/cs101report1.cpython-36.pyc
deleted file mode 100644
index b66271bfa506d026fd4bbe74cdca575612225b1f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2741
zcmXr!<>lHl@kYEk8w0~*1|-13z`)?Zz`#&k#K6Fi!jQt4!;s4u#hA+!#gxk&#mop2
zW6EL4WsPD5vzc?)a@nKU85!IeQdm-0TNqMUQyH6?qd43dQrJ@1TNqN<!F*14h7^tz
z&K8Cg&Qzvm<|wXI?i8+UrlP!5)>N)$hGs@ah7|5#22GxqAjfDj-{K7{O)W0T%+GT#
z$}cUr#TJxWkY7}Ciz_goC^N6bvm`ZFlkt{#YFT1VX<|ugd=XeWzPO|`B{i=^lkpa3
zMt*K;d45s0VKT@>7>4`LfPsM_l_82Tg&~S5g)xfRogsxOg}H?xg*la_nK_CT$v>>k
z%u#G9Y{3kg?6*XGGK))sQp-|{iW75SPOK7ui74c!Ddc1pm!R0m3JX&u6gxror7)(j
zq_ajbr?955wJ=1nq_77wXmV7kVzWgLSr8NeFBusa7+x}i2#^(-NlXk3$sjS1XPFon
z7(mz=6q$0M$Ye}m0!3ymBO^lzQwlRE$ZHsD7_yj~8G{)#S^SDXS~VGO@f3l*ml_Z9
zNEMe$X|6&_qC!eyrY6fR#pGf`1H<I}(xT$j^2DOl_|%HT+=84`J$PsraWgP5++r;N
z#nLUt98IQMEXAogX<*@%3`GJA3=F?KovmU*i&Kk=V@gUhQe#~5lS^|`^Gb?iO7k*H
z(u)#PQe$w~0}+QrwxM1@<t>rq{M>@llGOObyyEiIqIj^qTp&NQfkJ_ihmnJ^$_hE;
zV3CFqoO;-d^3!C!#StH$mzbLxAAgH0K0Y@;r8Eb`=82ClEKSUT$Q1E0FfbGefe4Tf
z!QO-rf}r3KKz0Bq>Nr3y1f@j|Mn1+OF$M+(loSJ!0p~&q%oM|t&H_p=!3>&gRa(gA
zV)a;feo;y>$i^tvjMSW*{3zD){GyzcD7NC#+}zZnDCU&>bU#g&B4LozML>iohyZ&B
zn@>cMZG;=n5AqHuwQ(>Oi8C-T_-V4EnRtt}B(o$ZwFu-huz$hoAVGw%2NYOE><kPH
zp!8e}ia`!W7A669uo(6bA~PRL_+;j#CKd&yrWd6a7iZ?@!9uS}1tOzR1ea1s%u7*l
z$}cX-&r?WAEJ-X*Ma|zJkAq`N4Jo!#nX_1;SW_6I*g*Nbg&~R^Qa(m;KuVG-O^7|1
zF3@w%Pfbh9OwI&l2~gCf?~rSK9k^qjJ@(8EN<Aq^nY)IunE_Nb2Qz3g!!tE+64?Fm
zIbd&VG8OTFqFIW8fkBh02o!xqAU0BbfTIGGpg~En7!+*`j6950c0{`xYj#Qo8^plC
z0HQ%97r1x=xuu3Vg&~Ehl}VBT;%-n5dHMhU|Nme&X|jMFd5gIywfGiuNkz#m_Po;E
zq|~Bfur!1KIr$b}K~a8kYH@LVerZWTX^9LhWil{USrG4bR73nUInk0cI2}iEBo-H^
z7M1uIMX{Hp7MG-z=0!1=<mW)j0eMgWBa$|l1$LnTdi;X2T`|bN9E@y?EKD3MMGEKz
z0z8R<)FP^_6s8u2DCQJqQ2AY@h|_yPzQL}bgoG0MAS1z{53;$2IRz!;i=<($hlYF+
zC?JbuL873_1QOtIKNW#I3vzTZ$W#W#Dg%OU(L)bnj4}vhCXzjH%WiSN`~y+}wvmIe
zND*tXQv^!A;K%}pDOeRYGm9h{7#KjQ9aiWt3UGtPPzoJTg2l+_pvFTgOA1pOQz~l;
za~e}RQxsb&dpctjM+!?YgC^@Oc1Y93po-r)Si#W1PyxbMFf0PqQ!jbJ4#!AfV26W>
zLa;NUI18c8q2eM?u^7cukeHkupP3746d~sUcqkQt8XGF0)DKe6!N|fWzz7xtRcE=0
znR)T?ewsW{!tg3r56&tAMPd=iv*3`6l7`D5)Wm0`<`jUkAE=~`630<pgWU=)yurQz
p+YiY}V0R)2aK_-UfmE(`poT~>s0tEc<YDAt65tgO5@6+E1^`6Xc~t-a

diff --git a/cs101courseware_example/__pycache__/cs101report1_grade.cpython-36.pyc b/cs101courseware_example/__pycache__/cs101report1_grade.cpython-36.pyc
deleted file mode 100644
index 6f0848e6a8e76af9b5877f00a49b72f484752463..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2703
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

diff --git a/cs101courseware_example/__pycache__/homework1.cpython-36.pyc b/cs101courseware_example/__pycache__/homework1.cpython-36.pyc
deleted file mode 100644
index afa293b6628d6b283bb49fb86c7b3055fb97400b..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1189
zcmXr!<>gv6<9K{4D+9x01|-15z`)?Zz`#(Pz`($e!jQt4!w|)o!jQt0!<5S$#mop2
zW6oj8WsPD5vsrT3a@nKUb2*|o7#UJnQ`lM<qBv97Q#e`}qPS8xQ@C0fqPSCeQn<63
ziegf^ni&`wQn^873S%&XCeKTd)qa|cx43ii6I0@o@{3FI^E4T63HW5@r6v{yrKT69
z78hsc=V>zC63R_Y%!@BBEKMv*O^Ht}D#|aq#ZhDwU!0s@l$y*4GKqnKff<UOL7q@x
zU|>jRsAa4Wt6^|qh~=wgs$oiJtYH*qsAVkV3TLPRIfBt|C4(k&6kBd(PG)h*Ew-Z6
z;?kUwTa4L7YzzzxVB(jvvsFxJacWU<Oi5`*YK%*Ma%paAUP*C`k%5sxOle+bNqSLY
zN@`4Uv7v!sa(-!1acX&DQEE&^er{@ceo?leUP0w8o}$#U)S}|lc#u6@Aop>A9L>bS
z$i>LVSOgMD1_^*L$U7kG!QRkfU|=X=NMUSdWMoKTN?}f6NnuTAsRfC#)i9*6moU~a
zG&44{fMO(=L6gI;N+%>ERRL<90?0arw9>rflFa-(h2+FMxJ)8g?j^{wm!Oz`2@1WJ
zEDQ_`Rh&MV#U%>miN#h`0#Jie6hO|0L<Va?QD$BV*v*=Zw-|H4!2}^V85kIDi4<q%
z7UV#@8edqNS`4yV5aef&uNW9P7<m|rKzz85Ss54@KsJMYoCWo93R5p*3{x#bEn^L1
z31b#h7IO__7E3c@3bP1<IYTXD32QS0C{nZ7Y8Yx5o0%9HO4w6aYM8P(K<pZ(EKX3!
z)H0VaW^t8p*D%&FH#0Re*0Pkar?A$rfYhWg1T$!|`GsgQMsXFTmXsFd#Ye<frdNxs
zbAMRXVqYcToS&MOmYJLhif)C(qSPw(Am3nDh0J12o+40~-D1isxW!hKn3s~Ddy5rB
z=iOo{&a6r;0tMzR=CsU`B7O!2hA7tL{M5AgDE5M))RfHRl3Ogrg+(PrATMjO-eQcn
z#aJ1|nUk3ppPQeOniIuY84pz$#Zr`8oLU45HwXa^U|vXGiO&IN6e&>13V;(1AEOu(
z8zT=R4-*%o0AmqI<`zeMd~RZ9UVOYJ?=9B6(%gc|A|a5I1d6kBQWJ~v^imQ_5{pwy
ziorgL5`hUr42QS~?42lnm{e|RNl|8UG1&b@ptu941#pzY?aWKeO^uI-I2z6Q95%W6
gDWy57cA&IZ3~~%8Mer~RuyL?+aB}c)FtRZM0CZy}L;wH)

diff --git a/cs101courseware_example/__pycache__/homework1.cpython-38.pyc b/cs101courseware_example/__pycache__/homework1.cpython-38.pyc
deleted file mode 100644
index 0d3386b94e926f441ec02b6e5452a23dc1d8f02d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1208
zcmWIL<>g{vU|{&hrk2>w%E0g##6iYP3=9ko3=9m#2@DJjDGVu$ISf&ZDGVu0IZV0C
zQOt}WG3FeWT-GR7Fq<WZEtfrtJ(nYjgOMSHHHEE(A&N7FJ%yu%A&M)7Gli>#A&NVd
zCxttksVF9utC@k3A(b0MrZ5IGX!5)S+3lyvc#AtHKQSdfDZjWRKTnhKmVi%YUTR`d
zP-=QnYH@L9ex4@NEuq}h#Ju?8!qUW|)Rg$tqN4nwTO373@x{scMXAY*Ad{e&nSp@;
zgq=Yikzrt9NN1>JtYL6rh~=wgs$oiJtYH*qsAVkVr~x^G(QhS#Ci5+}+{&EH;*wiz
zMXAN5IVHCkvy0dm7#P6BFE?kan9$<XqT-m6(u~v?m;B_?+|<01;+WFB%#!q?#FW&S
z<YGeu!{q$ZqT<x@#G=&r)QZI1f}GTtjQrfx^8BJ~L%o8^TRcUnWvNBQsqrAIKrvCw
z0dg}F3nK?34^t600|P@cNC1XGz5=-d>=P{p28I%b6vk#oMurro6y_9`6xMW>T96o9
z4MPfh31baIGh;IgC}M&cG&%gLbV4#x6`)osfUHzVE6qzT$;{7FNKVXy%Ory3UV<!p
z2}%GjL4o&@g@J*giqj{vxJ02mvDm6g0BTT*0>}%HIAJX)%FHVPyIYg-7Gn-Lv>*h?
zceg}}GeLm>_HKM(X=*XZZXr;#fPBRO@-<@-h>zlHRt5$J5C;1?3+n3>re4Mvrdm);
zGL|rAF)d)OVa#G#$e6+`!eGu&%UHtN%m9kr1#C48HH-_H7#T{~Q&?)4vN)QV7#V7q
z7I4-uEM%-@E@522Rl;4vSi{`Rw2-lurG!0&wT1<xCWRrGL6gldM3eCrS5az7X;EH$
zM0{m>wa7a6hgB{1RRYfWscC7M$(f*-S4b>Mtzr-I4R%$?EY{>H0)^Wxro4h%Y(<HA
zDfzj#SV45&EtcZUs?;J-fZk$G%Pc7pU|?Xl#hRR-nihYHy`U&HB{R9?7E5tqQArUf
zz%^NKF-F{Cth~jUlbIKvo1c=JbBnVw9<Hz`w>T9NzMuds0tYfLB-_O2fb)zrD0D%#
zFfj5liZQV<@-Xr+aWM)o7Ab<P=7^8aP0Y-TkJseA#hO=|TTodf0umP}&dy0qEXvbM
zNi0b$PAw^h_(%jM3^5$yBCvO&_+e7HsU=03$;Dvz7lGmpoF2f@3b!*aF*h|n9?9hh
l=X2QP=BJeAq}qYfUoj{#aDd#*D8R<S!NJMF!@<bL2mnPqEU*9o

diff --git a/docs/README.jinja.md b/docs/README.jinja.md
index 9563b1b..7fbbecc 100644
--- a/docs/README.jinja.md
+++ b/docs/README.jinja.md
@@ -1,83 +1,80 @@
-{{ input }}
 # Unitgrade
 
-Unitgrade is an automatic report and exam evaluation framework that enables instructors to offer automatically evaluated programming assignments. 
- Unitgrade is build on pythons `unittest` framework so that the tests can be specified in a familiar syntax and will integrate with any modern IDE. What it offers beyond `unittest` is the ability to collect tests in reports (for automatic evaluation) and an easy and 100% safe mechanism for verifying the students results and creating additional, hidden tests. A powerful cache system allows instructors to automatically create test-answers based on a working solution. 
+Unitgrade is an automatic software testing framework that enables instructors to offer automatically evaluated programming assignments with a minimal overhead for students.
+
+Unitgrade is build on pythons `unittest` framework so that the tests can be specified and run in a familiar syntax, 
+ and will integrate well with any modern IDE. What it offers beyond `unittest` is the ability to collect tests in reports (for automatic evaluation) 
+and an easy and safe mechanism for verifying results. 
 
  - 100% Python `unittest` compatible
- - No external configuration files, just write a `unittest`
- - No unnatural limitations: If you can `unittest` it, it works.   
- - Granular security model: 
-    - Students get public `unittests` for easy development of solutions
-    - Students get a tamper-resistant file to create submissions which are uploaded
-    - Instructors can automatically verify the students solution using Docker VM and by running hidden tests
-    - Allow export of assignments to Autolab (no `make` file mysteries!)
- - Tests are quick to run and will integrate with your IDE
+ - Integrates with any modern IDE (VSCode, Pycharm, Eclipse)
+ - No external configuration files or setup required
+ - Tests are quick to run and will tell you where your mistake is
+ - Hint-system collects hints from code and display it with failed unittests
 
 ## Installation
-Unitgrade can be installed using `pip`:
-```
+Unitgrade is simply installed like any other package using `pip`:
+```terminal
 pip install unitgrade
 ```
-This will install unitgrade in your site-packages directory. If you want to upgrade an old installation of unitgrade:
-```
-pip install unitgrade --upgrade
-```
-If you are using anaconda+virtual environment you can install it as
+This will install unitgrade in your site-packages directory and you should be all set. If you want to upgrade an old version of unitgrade run:
+```terminal
+pip install unitgrade --upgrade --no-cache-dir
 ```
+If you are using anaconda+virtual environment you can install it as any other package:
+```terminal
 source activate myenv
 conda install git pip
 pip install unitgrade
 ```
-
-When you are done, you should be able to import unitgrade:
-```
-import unitgrade
+When you are done, you should be able to import unitgrade. Type `python` in the termial and try:
+```pycon
+>>> import unitgrade2
 ```
 
-## Evaluating a report
-Homework is broken down into **reports**. A report is a collection of questions which are individually scored, and each question may in turn involve multiple tests. Each report is therefore given an overall score based on a weighted average of how many tests are passed.
-In practice, a report consist of an ordinary python file which they simply run. It looks like this (to run this on your local machine, follow the instructions in the previous section):
+## Using Unitgrade
+In unitgrade, your homework assignments are called **reports** and are distributed as regular `.py`-files. I am going to use `cs101report1.py` as a generic example in the following, but a real-world example can be found here: https://gitlab.compute.dtu.dk/tuhe/unitgrade_private/-/blob/master/examples/example_simplest/students/cs101/report1.py .
+
+The report is simply a collection of questions which are individually scored, and each question may in turn involve checking several sub-cases.
+
+You should think of the tests as a help for you when you are debugging your code and when you are trying to figure out what to do. 
+I recommend running the tests through your IDE. In pycharm, this is as simple as right-clicking on the test and selecting `Run as unittest`. The image belows shows the outcome in Pycharm:
+
+![Using unittests in pycharm](https://gitlab.compute.dtu.dk/tuhe/unitgrade/-/raw/master/docs/pycharm.png)
+
+The tests are shown in the lower-left corner, and in this case they are all green meaning they have passed. If a test fails, you can right-click and select `debug as unittest`, or you can click on it and see the output it produced, and you can right-click on individual tests to re-run them.
+
+### Checking your score
+To check your score, you have to run the main script (`cs101report1.py`) as a regular python file. This can be done either through pycharm (Hint: Open the file and press `alt-shift-F10`) or in the console by running the command: 
 ```
 python cs101report1.py
 ```
-The file `cs101report1.py` is just an ordinary, non-obfuscated file which they can navigate and debug using a debugger. The file may contain the homework, or it may call functions the students have written.  Running the file creates console output which tells the students their current score for each test:
-
+The file will run and show an output where the score of each question is computed as a (weighted) average of the individual passed tests. An example is given below:
 ```terminal
 {{out}}
 ```
-Once you are happy with the result run the script with the `_grade.py`-postfix, in this case `cs101report1_grade.py`:
-
+### Handing in your homework
+Once you are happy with your results and want to hand in, you should run the script with the `_grade.py`-postfix, in this case `cs101report1_grade.py` (see console output above):
 ```
 python cs101report1_grade.py
 ```
-This runs the same tests, and generates a file `Report0_handin_18_of_18.token`. The file name indicates how many points you got. Upload this file to campusnet (and no other). 
-
-## Running the tests in pycharm
-Naturally, you can also run the tests in pycharm, and this offers you a lot of cool features such as integration with the debugger and the ability to see which tests have failed.
-To do this, simply right-click on the `report.py`-file and select `Run as unittest` (or alternatively, `debug as unittest`). This will take you to a screen such as shown below:
-
-![Using unittests in pycharm](https://gitlab.compute.dtu.dk/tuhe/unitgrade/-/raw/master/docs/pycharm.png)
-
-You can see all tests are green indicating they all pass. If you click on a test you can see the console output it generates and you can 
-right-click on the tests to re-run individual tests. 
-
+This script will run *the same tests as before* and generates a file named `Report0_handin_18_of_18.token` (this is called the `token`-file because of the extension). The token-file contains all your results and it is the token-file you should upload (and no other). Because you cannot (and most definitely should not!) edit it, it shows the number of points in the file-name. 
 
 ### Why are there two scripts?
-The reason why we use a standard test script, and one with the `_grade.py` extension, is because the tests should both be easy to debug, but at the same time we have to prevent accidential changes to the test scripts. Hence, we include two versions of the tests.
+The reason why we use a standard test script (one with the `_grade.py` extension and one without), is because the tests should both be easy to debug, but at the same time we have to avoid accidential changes to the test scripts. The tests themselves are the same, so if one script works, so should the other.
 
 # FAQ
  - **My non-grade script and the `_grade.py` script gives different number of points**
 Since the two scripts should contain the same code, the reason is nearly certainly that you have made an (accidental) change to the test scripts. Please ensure both scripts are up-to-date and if the problem persists, try to get support.
    
  - **Why is there a `unitgrade` directory with a bunch of pickle files? Should I also upload them?**
-No. The file contains the pre-computed test results your code is compared against. If you want to load this file manually, the unitgrade package contains helpful functions for doing so.
+No. The file contains the pre-computed test results your code is compared against. You should only upload the `.token` file, nothing else
    
  - **I am worried you might think I cheated because I opened the '_grade.py' script/token file**
 This should not be a concern. Both files are in a binary format (i.e., if you open them in a text editor they look like garbage), which means that if you make an accidential change, they will with all probability simply fail to work. 
    
  - **I think I might have edited the `report1.py` file. Is this a problem since one of the tests have now been altered?**
-Feel free to edit/break this file as much as you like if it helps you work out the correct solution. In fact, I recommend you just run `report1.py` from your IDE and use the debugger to work out the current state of your program. However, since the `report1_grade.py` script contains a seperate version of the tests, please ensure your `report1.py` file is up to date.
+Feel free to edit/break this file as much as you like if it helps you work out the correct solution. However, since the `report1_grade.py` script contains a seperate version of the tests, please ensure both files are in sync to avoid unexpected behavior. 
    
 ### Debugging your code/making the tests pass
 The course material should contain information about the intended function of the scripts used in the tests, and the file `report1.py` should mainly be used to check which of your code is being run. In other words, first make sure your code solves the exercises, and only later run the test script which is less easy/nice to read. 
@@ -85,8 +82,8 @@ However, obivously you might get to a situation where your code seems to work, b
 
  - **I am 99% sure my code is correct, but the test still fails. Why is that?**
 The testing framework offers a great deal of flexibility in terms of what is compared. This is either: (i) The value a function returns, (ii) what the code print to the console (iii) something derived from these.
-   Since the test *might* compare the console output, i.e. what you generate using `print("...")`-statements, innnocent changes to the script, like an extra print statement, can cause the test to fail, which is counter-intuitive. For this reason, please look at the error message carefully (or the code in `report1.py`) to understand what is being compared. 
-   
+When a test fails, you should always try to insert a breakpoint on exactly the line that generate the problem, run the test in the debugger, and figure out what the expected result was supposed to be. This should give you a clear hint as to what may be wrong.
+
 One possibility that might trick some is that if the test compares a value computed by your code, the datatype of that value is important. For instance, a `list` is not the same as a python `ndarray`, and a `tuple` is different from a `list`. This is the correct behavior of a test: These things are not alike and correct code should not confuse them. 
 
  - **The `report1.py` class is really confusing. I can see the code it runs on my computer, but not the expected output. Why is it like this?**
@@ -96,10 +93,7 @@ To make sure the desired output of the tests is always up to date, the tests are
 There are a number of console options available to help you figure out what your program should output and what it currently outputs. They can be found using:
  ```python report1.py --help```
 Note these are disabled for the `report1_grade.py` script to avoid confusion. It is not recommended you use the grade script to debug your code.  
-
- - **How do I see the output generated by my scripts in the IDE?**
-The file `unitgrade/unitgrade.py` contains all relevant information. Look at the `QItem` class and the function `get_points`, which is the function that strings together all the tests. 
-
+   
  - **Since I cannot read the `.token` file, can I trust it contains the same number of points internally as the file name indicate?**
 Yes. 
 
@@ -108,14 +102,13 @@ Yes.
 That the script `report1_grade.py` is difficult to read is not the principle safety measure. Instead, it ensures there is no accidential tampering. If you muck around with these files and upload the result, we will very likely know.     
 
 - **I have private data on my computer. Will this be read or uploaded?**
-No. The code will look for and upload your solutions, but it will not read/look at other directories in your computer. In the example provided with this code, this means you should expect unitgrade to read/run all files in the `cs101courseware_example`-directory, but **no** other files on your computer. So as long as you keep your private files out of the base courseware directory, you should be fine. 
+No. The code will look for and upload your solutions, but it will not read/look at other directories in your computer. As long as your keep your private files out of the directory containing your homework you have nothing to worry about. 
 
 - **Does this code install any spyware/etc.? Does it communicate with a website/online service?**
-No. Unitgrade makes no changes outside the courseware directory and it does not do anything tricky. It reads/runs code and write the `.token` file.
+No. Unitgrade makes no changes outside the courseware directory and it does not do anything tricky. It reads/runs code and produce the `.token` file.
   
 - **I still have concerns about running code on my computer I cannot easily read**
 Please contact me and we can discuss your specific concerns.
-  
 
 # Citing
 ```bibtex
diff --git a/cs101courseware/cs101report1_grade.py b/docs/legacy/cs101courseware/cs101report1_grade.py
similarity index 100%
rename from cs101courseware/cs101report1_grade.py
rename to docs/legacy/cs101courseware/cs101report1_grade.py
diff --git a/cs101courseware_example/Report0_handin_18_of_18.token b/docs/legacy/cs101courseware_example/Report0_handin_18_of_18.token
similarity index 100%
rename from cs101courseware_example/Report0_handin_18_of_18.token
rename to docs/legacy/cs101courseware_example/Report0_handin_18_of_18.token
diff --git a/cs101courseware_example/Report0_resources_do_not_hand_in.dat b/docs/legacy/cs101courseware_example/Report0_resources_do_not_hand_in.dat
similarity index 100%
rename from cs101courseware_example/Report0_resources_do_not_hand_in.dat
rename to docs/legacy/cs101courseware_example/Report0_resources_do_not_hand_in.dat
diff --git a/cs101courseware_example/Report1.xlsx b/docs/legacy/cs101courseware_example/Report1.xlsx
similarity index 100%
rename from cs101courseware_example/Report1.xlsx
rename to docs/legacy/cs101courseware_example/Report1.xlsx
diff --git a/cs101courseware_example/Report1_handin_18_of_18.token b/docs/legacy/cs101courseware_example/Report1_handin_18_of_18.token
similarity index 100%
rename from cs101courseware_example/Report1_handin_18_of_18.token
rename to docs/legacy/cs101courseware_example/Report1_handin_18_of_18.token
diff --git a/cs101courseware_example/Report1_resources_do_not_hand_in.dat b/docs/legacy/cs101courseware_example/Report1_resources_do_not_hand_in.dat
similarity index 100%
rename from cs101courseware_example/Report1_resources_do_not_hand_in.dat
rename to docs/legacy/cs101courseware_example/Report1_resources_do_not_hand_in.dat
diff --git a/cs101courseware_example/Report2_resources_do_not_hand_in.dat b/docs/legacy/cs101courseware_example/Report2_resources_do_not_hand_in.dat
similarity index 100%
rename from cs101courseware_example/Report2_resources_do_not_hand_in.dat
rename to docs/legacy/cs101courseware_example/Report2_resources_do_not_hand_in.dat
diff --git a/cs101courseware_example/__init__.py b/docs/legacy/cs101courseware_example/__init__.py
similarity index 100%
rename from cs101courseware_example/__init__.py
rename to docs/legacy/cs101courseware_example/__init__.py
diff --git a/cs101courseware_example/cs101report1.py b/docs/legacy/cs101courseware_example/cs101report1.py
similarity index 100%
rename from cs101courseware_example/cs101report1.py
rename to docs/legacy/cs101courseware_example/cs101report1.py
diff --git a/cs101courseware_example/cs101report1_grade.py b/docs/legacy/cs101courseware_example/cs101report1_grade.py
similarity index 100%
rename from cs101courseware_example/cs101report1_grade.py
rename to docs/legacy/cs101courseware_example/cs101report1_grade.py
diff --git a/cs101courseware_example/cs101report2.py b/docs/legacy/cs101courseware_example/cs101report2.py
similarity index 100%
rename from cs101courseware_example/cs101report2.py
rename to docs/legacy/cs101courseware_example/cs101report2.py
diff --git a/cs101courseware_example/cs101report2_grade.py b/docs/legacy/cs101courseware_example/cs101report2_grade.py
similarity index 100%
rename from cs101courseware_example/cs101report2_grade.py
rename to docs/legacy/cs101courseware_example/cs101report2_grade.py
diff --git a/cs101courseware_example/homework1.py b/docs/legacy/cs101courseware_example/homework1.py
similarity index 100%
rename from cs101courseware_example/homework1.py
rename to docs/legacy/cs101courseware_example/homework1.py
diff --git a/cs101courseware_example/instructions.py b/docs/legacy/cs101courseware_example/instructions.py
similarity index 100%
rename from cs101courseware_example/instructions.py
rename to docs/legacy/cs101courseware_example/instructions.py
diff --git a/docs/mkdocs.py b/docs/mkdocs.py
index 589d74a..9e525e5 100644
--- a/docs/mkdocs.py
+++ b/docs/mkdocs.py
@@ -7,7 +7,6 @@ if __name__ == "__main__":
     from jinjafy.bibliography_maker import make_bibliography
     bibtex = make_bibliography("../setup.py", "./")
 
-
     out = subprocess.check_output("python --version").decode("utf-8")
     fn = unitgrade_private2.__path__[0] + "/../../examples/02631/instructor/programs/report1intro.py"
 
diff --git a/setup.py b/setup.py
index aaa1240..0527345 100644
--- a/setup.py
+++ b/setup.py
@@ -1,15 +1,16 @@
 # Use this guide:
 # https://packaging.python.org/tutorials/packaging-projects/
-
+# py -m build && twine upload dist/*
 # from unitgrade2.version import __version__
 import setuptools
 with open("src/unitgrade2/version.py", "r", encoding="utf-8") as fh:
-    __version__ = fh.read().split(" = ")[1].strip()[1:-1]
+    __version__ = fh.read().split("=")[1].strip()[1:-1]
 # long_description = fh.read()
 
 with open("README.md", "r", encoding="utf-8") as fh:
     long_description = fh.read()
 
+
 setuptools.setup(
     name="unitgrade",
     version=__version__,
@@ -31,5 +32,5 @@ setuptools.setup(
     packages=setuptools.find_packages(where="src"),
     python_requires=">=3.8",
     license="MIT",
-    install_requires=['numpy', 'tabulate', 'tqdm', "pyfiglet", "colorama", "coverage"],
+    install_requires=['numpy', 'tabulate', "pyfiglet", "coverage", "colorama", 'tqdm'],
 )
diff --git a/src/unitgrade.egg-info/PKG-INFO b/src/unitgrade.egg-info/PKG-INFO
index 64824b5..5e7bafc 100644
--- a/src/unitgrade.egg-info/PKG-INFO
+++ b/src/unitgrade.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: unitgrade
-Version: 0.0.3
+Version: 0.1.1
 Summary: A student homework/exam evaluation framework build on pythons unittest framework.
 Home-page: https://lab.compute.dtu.dk/tuhe/unitgrade
 Author: Tue Herlau
@@ -66,7 +66,7 @@ The file `cs101report1.py` is just an ordinary, non-obfuscated file which they c
 | | | |_ __  _| |_| |  \/_ __ __ _  __| | ___ 
 | | | | '_ \| | __| | __| '__/ _` |/ _` |/ _ \
 | |_| | | | | | |_| |_\ \ | | (_| | (_| |  __/
- \___/|_| |_|_|\__|\____/_|  \__,_|\__,_|\___| v0.0.2, started: 03/09/2021 21:18:46
+ \___/|_| |_|_|\__|\____/_|  \__,_|\__,_|\___| v0.0.3, started: 07/09/2021 00:42:25
 
 Week 4: Looping (use --help for options)
 Question 1: Test the cluster analysis method                                                                            
@@ -99,7 +99,7 @@ Question 4: Test the fermentation rate question
  * q4.4) fermentationRate([20.1, 19.3, 1.1, 18.2, 19.7, ...], 18.2, 20) = 19.500 ?..................................PASS
  * q4)   Total.................................................................................................... 10/10
  
-Total points at 21:18:46 (0 minutes, 0 seconds)....................................................................40/40
+Total points at 00:42:25 (0 minutes, 0 seconds)....................................................................40/40
 Provisional evaluation
 ---------  -----
 q1) Total  10/10
@@ -125,6 +125,7 @@ This runs the same tests, and generates a file `Report0_handin_18_of_18.token`.
 ## Running the tests in pycharm
 Naturally, you can also run the tests in pycharm, and this offers you a lot of cool features such as integration with the debugger and the ability to see which tests have failed.
 To do this, simply right-click on the `report.py`-file and select `Run as unittest` (or alternatively, `debug as unittest`). This will take you to a screen such as shown below:
+
 ![Using unittests in pycharm](https://gitlab.compute.dtu.dk/tuhe/unitgrade/-/raw/master/docs/pycharm.png)
 
 You can see all tests are green indicating they all pass. If you click on a test you can see the console output it generates and you can 
@@ -185,3 +186,16 @@ No. Unitgrade makes no changes outside the courseware directory and it does not
 Please contact me and we can discuss your specific concerns.
   
 
+# Citing
+```bibtex
+@online{unitgrade,
+	title={Unitgrade (0.0.3): \texttt{pip install unitgrade}},
+	url={https://lab.compute.dtu.dk/tuhe/unitgrade},
+	urldate = {2021-09-07}, 
+	month={9},
+	publisher={Technical University of Denmark (DTU)},
+	author={Tue Herlau},
+	year={2021},
+}
+```
+
diff --git a/src/unitgrade.egg-info/SOURCES.txt b/src/unitgrade.egg-info/SOURCES.txt
index 6644370..778240d 100644
--- a/src/unitgrade.egg-info/SOURCES.txt
+++ b/src/unitgrade.egg-info/SOURCES.txt
@@ -2,6 +2,11 @@ LICENSE
 README.md
 pyproject.toml
 setup.py
+src/unitgrade/__init__.py
+src/unitgrade/unitgrade.py
+src/unitgrade/unitgrade_grade.py
+src/unitgrade/unitgrade_helpers.py
+src/unitgrade/version.py
 src/unitgrade.egg-info/PKG-INFO
 src/unitgrade.egg-info/SOURCES.txt
 src/unitgrade.egg-info/dependency_links.txt
diff --git a/src/unitgrade.egg-info/requires.txt b/src/unitgrade.egg-info/requires.txt
index 680bd8b..f0d444b 100644
--- a/src/unitgrade.egg-info/requires.txt
+++ b/src/unitgrade.egg-info/requires.txt
@@ -1,6 +1,6 @@
 numpy
 tabulate
-tqdm
 pyfiglet
-colorama
 coverage
+colorama
+tqdm
diff --git a/src/unitgrade.egg-info/top_level.txt b/src/unitgrade.egg-info/top_level.txt
index 8943cd4..948295a 100644
--- a/src/unitgrade.egg-info/top_level.txt
+++ b/src/unitgrade.egg-info/top_level.txt
@@ -1 +1,2 @@
+unitgrade
 unitgrade2
diff --git a/unitgrade/__init__.py b/src/unitgrade/__init__.py
similarity index 100%
rename from unitgrade/__init__.py
rename to src/unitgrade/__init__.py
diff --git a/unitgrade/unitgrade.py b/src/unitgrade/unitgrade.py
similarity index 100%
rename from unitgrade/unitgrade.py
rename to src/unitgrade/unitgrade.py
diff --git a/unitgrade/unitgrade_grade.py b/src/unitgrade/unitgrade_grade.py
similarity index 100%
rename from unitgrade/unitgrade_grade.py
rename to src/unitgrade/unitgrade_grade.py
diff --git a/unitgrade/unitgrade_helpers.py b/src/unitgrade/unitgrade_helpers.py
similarity index 100%
rename from unitgrade/unitgrade_helpers.py
rename to src/unitgrade/unitgrade_helpers.py
diff --git a/unitgrade/version.py b/src/unitgrade/version.py
similarity index 100%
rename from unitgrade/version.py
rename to src/unitgrade/version.py
diff --git a/src/unitgrade2/__init__.py b/src/unitgrade2/__init__.py
index d62d54d..caeb0a3 100644
--- a/src/unitgrade2/__init__.py
+++ b/src/unitgrade2/__init__.py
@@ -1,36 +1,44 @@
-import os
+import unitgrade2.version as __version__
+from unitgrade2.unitgrade2 import myround, mfloor, msum, ActiveProgress
+from unitgrade2.unitgrade2 import Capturing, Report, UTestCase, cache, hide
 
-# DONT't import stuff here since install script requires __version__
-
-def cache_write(object, file_name, verbose=True):
-    import compress_pickle
-    dn = os.path.dirname(file_name)
-    if not os.path.exists(dn):
-        os.mkdir(dn)
-    if verbose: print("Writing cache...", file_name)
-    with open(file_name, 'wb', ) as f:
-        compress_pickle.dump(object, f, compression="lzma")
-    if verbose: print("Done!")
+from unitgrade2.unitgrade_helpers2 import evaluate_report_student
 
+# import os
+# import lzma
+# import pickle
 
-def cache_exists(file_name):
-    # file_name = cn_(file_name) if cache_prefix else file_name
-    return os.path.exists(file_name)
-
+# DONT't import stuff here since install script requires __version__
 
-def cache_read(file_name):
-    import compress_pickle # Import here because if you import in top the __version__ tag will fail.
-    # file_name = cn_(file_name) if cache_prefix else file_name
-    if os.path.exists(file_name):
-        try:
-            with open(file_name, 'rb') as f:
-                return compress_pickle.load(f, compression="lzma")
-        except Exception as e:
-            print("Tried to load a bad pickle file at", file_name)
-            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")
-            print(e)
-            # return pickle.load(f)
-    else:
-        return None
+# def cache_write(object, file_name, verbose=True):
+#     # raise Exception("bad")
+#     # import compress_pickle
+#     dn = os.path.dirname(file_name)
+#     if not os.path.exists(dn):
+#         os.mkdir(dn)
+#     if verbose: print("Writing cache...", file_name)
+#     with lzma.open(file_name, 'wb', ) as f:
+#         pickle.dump(object, f)
+#     if verbose: print("Done!")
+#
+#
+# def cache_exists(file_name):
+#     # file_name = cn_(file_name) if cache_prefix else file_name
+#     return os.path.exists(file_name)
+#
+#
+# def cache_read(file_name):
+#     # import compress_pickle # Import here because if you import in top the __version__ tag will fail.
+#     # file_name = cn_(file_name) if cache_prefix else file_name
+#     if os.path.exists(file_name):
+#         try:
+#             with lzma.open(file_name, 'rb') as f:
+#                 return pickle.load(f)
+#         except Exception as e:
+#             print("Tried to load a bad pickle file at", file_name)
+#             print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")
+#             print(e)
+#             # return pickle.load(f)
+#     else:
+#         return None
 
-from unitgrade2.unitgrade2 import myround, mfloor, msum, Capturing, ActiveProgress
diff --git a/src/unitgrade2/__pycache__/__init__.cpython-38.pyc b/src/unitgrade2/__pycache__/__init__.cpython-38.pyc
index 4429c41fb31c60f6c1074d20620caf2572fce98e..d56ac9f30a848efb81409d9ed034b964f0dabe35 100644
GIT binary patch
literal 494
zcmWIL<>g{vU|?|Iuu61iV_<j;;vi!tkR$^GLva8D149Z!3S$mKE@KoEBZ$qE!<@?!
z#gfY!#hS|&#g@w+#SRu{&SB2wh~miQjN;7YisH)Uj^fVciQ)mvvE=aP@<s76GNdpD
zGib8D1li@M$#RQ5x3Va|G%w{ATW(rTetyv{mfYgf+*^E($t9U(sR2d#=|!o<#hR?Q
zIGqy<N=l0|^U`mz1*I0`7nR)N3=K&wE^$sQPQAsNoS2-EdW$6^GbL4%@s@aMSz=CU
zVo7Rz5m;$_aY<=PYF>#Zf0R&ZUS>&pQDRD}kzQG9QE_H|-Ys?*gF8MR%8ZYX5=Byp
zU>1Qwriht=fuV>6M6iMgHW0xMA~-+<Cx`%rZ<H)TqaK_YpOKnVkXlr1RK(4|z_5~`
zh!3P5MEtUGwu%WYPAw{qDJjiJjd96OF3nBND=ChFYmO-{N=EREV&da7^D;}~<Mj$E
aZ*kb<=BJeAq}nlpVh-de9!3d9872UL_==?f

literal 1306
zcmWIL<>g{vU|_hl*dWo3m4V?gh=Yuo85kHG7#J9eofsGxQW#Pga~Pr+Qn*r>Q&?IU
zqZm_IQ`lM<qL@<HQ#e`}qL@<{QaE#1a#^ETbJ?QUa@nKUb2*|oayg?o85vR-gBdir
zUxG~c3rPkU3}S*X8v_FaCj$e6GsvPmkVT9s3^@$7%q5IjObeK67#A|uvVhqvH7pAm
zi?vD^7qEg@j0`nQMHVG&DNHqt%}k68CG0hfDa_4G{bIGOHOyHYH4HVZDJ&_hz08aZ
z;S8n>feb+m5g<KTC2T2d&5Vo;DGb33n(Tf>j0_A6RRZBfnI)Nd=?ck-$r-77dV05*
z%9C!f<W%J*u4IhjPR`FQC`v6Z&dkrNVs**SOI6h5yu}X_jW5Vd&dy1_#gt!si=`m3
zB;yu)N@h`BVs7d!w$zHu;*#Q9thw1KnMJo)3yL!HN^Y^_7o_IhVo52@Ezo4U#g?Cx
zm6}{~i!&`VCp8|djlC?jC@H@<wTP900Tjl0w;0n_G873hFfjbGakh#HElw>ejwvb4
zNR4sHPcF?(%_}L6Db33)NiRxFNsTEkN=EREV&da7^D;}~<Mj$EZ*hY?7++qLS&|Ae
zyjTPj4U8O&Jd8YyT#PIXT#P)7Qj9DNMIeb}P~d<RfG~&+iaT&z@h~tjlrUs5E?}x*
zSO|(<Mn6sFB2aV|u`@6*6mc>zFlaIs@q^ePXM^2dBn(P$JP;>9LPh`-@k}7&nTkXi
z7#L7&WMN=n03}kejeUsJ!3a(f%pjYK+Nz97SZWwjn3|dT<!YH~7_(Swm_UiNmnocq
z2^#Z@8NwNYp=ltTp|FdEp@c1)tEh>Qp_ZAEp-QfVJ%zP~0g{d&siTCwh8dJfKxrq1
zp_aLhIf5aQp|C50A&&)=azGfCdTuclB^7}}rU>NVDy5L3%+wTxl6-}n{KOQ6M1`cp
z6a`2UQ2<4;LSji(u4kG;Nk%G^Ur>;mSX2zsk(8>CSXz>wn^=;WoS2hSsgRzUms*rq
zlA5BUP?=w<keryOP*PM0Qks&QlUkChkXfRmkYAFKT2!7{oT`wLU!DiGH7~VXp)9os
zlx8(KzzGR0dWt}Cc#8$3{1&HcMRICENoIat5jQC2SRgS6N+Cspph#m(g~T8@F2T{r
z1&PL@)Wj4}#K9606AvR3BM+k*qW~ipBL|}lbCDFtK-OFAxs^rvrFkj0*mBcy^7D&s
zvE&w)=HB9TPAn)XEy~PGzs2X6T#{Lq8c>v<4$5qrj3Js_5I2L;A~<<~4T}<mCv_t|
z1hYsQl-OiIge-`V0}=8d0_<o60d_uzO>TZlX-=vgC|MVCFfcH1uyAp6uyXJN0CxU1
ASO5S3

diff --git a/src/unitgrade2/__pycache__/unitgrade2.cpython-38.pyc b/src/unitgrade2/__pycache__/unitgrade2.cpython-38.pyc
index d2b644a5d515e7f207ce5605697ad2e458fd1527..59bb92f4d418f4c6e20156d57457f67fac1d2d28 100644
GIT binary patch
delta 2120
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
K94s8d983U5+aq}Z

delta 2066
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
Z#3d*cA;iNa$RQ+D&rr<4!XeDT1OTB>8O8tr

diff --git a/src/unitgrade2/__pycache__/unitgrade_helpers2.cpython-38.pyc b/src/unitgrade2/__pycache__/unitgrade_helpers2.cpython-38.pyc
index d80c99b05ba9b98faefe0a10c407cb0555e97b32..ebae664e67677e245b6a227b53dd7158fc9deb68 100644
GIT binary patch
delta 2043
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

delta 2223
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
aUW$j&Vsej^4!;Hmn-Gf-4+A3@{sjPhxg0J4

diff --git a/src/unitgrade2/__pycache__/version.cpython-38.pyc b/src/unitgrade2/__pycache__/version.cpython-38.pyc
index fb1c90bd161b62260f9408fa471df6c4c537f234..ad6a8f2a32ed6b8a848b77969560d841ab9cb8d0 100644
GIT binary patch
delta 26
hcmZ3@xSEkWl$V!_fq{X6Pt0;6w;{8kp20->8~{Cz1l0fl

delta 26
hcmZ3@xSEkWl$V!_fq{YH;ydGs+=k2sdd3s&a{y6U25bNT

diff --git a/src/unitgrade2/unitgrade2.py b/src/unitgrade2/unitgrade2.py
index 8e34131..087343c 100644
--- a/src/unitgrade2/unitgrade2.py
+++ b/src/unitgrade2/unitgrade2.py
@@ -1,6 +1,3 @@
-"""
-git add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade
-"""
 import numpy as np
 import sys
 import re
@@ -13,13 +10,13 @@ import io
 from unittest.runner import _WritelnDecorator
 from typing import Any
 import inspect
-import textwrap
 import colorama
 from colorama import Fore
 from functools import _make_key, RLock
 from collections import namedtuple
 import unittest
 import time
+import textwrap
 
 _CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
 
@@ -96,20 +93,6 @@ class Capturing2(Capturing):
         self.numbers = numbers
 
 
-# @classmethod
-# class OrderedClassMembers(type):
-#     def __prepare__(self, name, bases):
-#         assert False
-#         return collections.OrderedDict()
-#
-#     def __new__(self, name, bases, classdict):
-#         ks = list(classdict.keys())
-#         for b in bases:
-#             ks += b.__ordered__
-#         classdict['__ordered__'] = [key for key in ks if key not in ('__module__', '__qualname__')]
-#         return type.__new__(self, name, bases, classdict)
-
-
 class Report:
     title = "report title"
     version = None
@@ -269,17 +252,9 @@ class ActiveProgress():
 def dprint(first, last, nL, extra = "", file=None, dotsym='.', color='white'):
     if file == None:
         file = sys.stdout
-
-    # ss = self.item_title_print
-    # state = "PASS" if success else "FAILED"
     dot_parts = (dotsym * max(0, nL - len(last) - len(first)))
-    # if self.show_progress_bar or True:
     print(first + dot_parts, end="", file=file)
-    # else:
-    # print(dot_parts, end="", file=self.cc.file)
     last += extra
-    # if tsecs >= 0.5:
-    #     state += " (" + str(tsecs) + " seconds)"
     print(last, file=file)
 
 
@@ -406,13 +381,12 @@ def get_hints(ss):
     try:
         ss = textwrap.dedent(ss)
         ss = ss.replace('''"""''', "").strip()
-        hints = ["hints:", ]
+        hints = ["hints:", "hint:"]
         j = np.argmax([ss.lower().find(h) for h in hints])
         h = hints[j]
-        ss = ss[ss.find(h) + len(h) + 1:]
+        ss = ss[ss.lower().find(h) + len(h) + 1:]
         ss = "\n".join([l for l in ss.split("\n") if not l.strip().startswith(":")])
-        ss = textwrap.dedent(ss)
-        ss = ss.strip()
+        ss = textwrap.dedent(ss).strip()
         return ss
     except Exception as e:
         print("bad hints", ss, e)
@@ -472,10 +446,8 @@ class UTestCase(unittest.TestCase):
                         s = f.read()
                     lines = s.splitlines()
                     garb = 'GARBAGE'
-
                     lines2 = snipper_main.censor_code(lines, keep=True)
                     assert len(lines) == len(lines2)
-
                     for l in data.contexts_by_lineno(file):
                         if lines2[l].strip() == garb:
                             if self.cache_id() not in self._report.covcache:
@@ -635,7 +607,8 @@ class UTestCase(unittest.TestCase):
                                     hint = get_hints(comments)
 
                                     if hint != None:
-                                        hints.append(hint)
+                                        # hint = textwrap.dedent(hint)
+                                        hints.append((hint, file, l) )
                                     gprint(f">      - {l}")
 
                 er = er[0]
@@ -643,10 +616,16 @@ class UTestCase(unittest.TestCase):
                 if doc is not None:
                     hint = get_hints(er._testMethodDoc)
                     if hint is not None:
-                        hints = [hint] + hints
+                        hints = [(hint, None, self.cache_id()[1] )] + hints
                 if len(hints) > 0:
-                    gprint("> Hints:")
-                    gprint(textwrap.indent("\n".join(hints), ">   "))
+                    for hint, file, method in hints:
+                        s = (f"'{method.strip()}'" if method is not None else "")
+                        if method is not None and file is not None:
+                            s += " in "
+                        s += (file.strip() if file is not None else "")
+                        gprint(">")
+                        gprint("> Hints (from " + s  + ")")
+                        gprint(textwrap.indent(hint, ">   "))
 
         super()._feedErrorsToResult(result, errors)
 
@@ -704,4 +683,4 @@ def methodsWithDecorator(cls, decorator):
             if maybeDecorated.decorator == decorator:
                 print(maybeDecorated)
                 yield maybeDecorated
-# 817
+# 817, 705
\ No newline at end of file
diff --git a/src/unitgrade2/unitgrade_helpers2.py b/src/unitgrade2/unitgrade_helpers2.py
index 6838647..7f538f0 100644
--- a/src/unitgrade2/unitgrade_helpers2.py
+++ b/src/unitgrade2/unitgrade_helpers2.py
@@ -38,8 +38,11 @@ parser.add_argument('--unmute',  action="store_true",  help='Show result of prin
 parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
 parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars.')
 
-def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False, show_privisional=True, noprogress=None):
     args = parser.parse_args()
+    if noprogress is None:
+        noprogress = args.noprogress
+
     if question is None and args.q is not None:
         question = args.q
         if "." in question:
@@ -56,11 +59,12 @@ def evaluate_report_student(report, question=None, qitem=None, unmute=None, pass
         passall = args.passall
 
 
-    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute and not args.noprogress, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute and not noprogress, qitem=qitem,
+                                          verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
                                           show_tol_err=show_tol_err)
 
 
-    if question is None:
+    if question is None and show_privisional:
         print("Provisional evaluation")
         tabulate(table_data)
         table = table_data
@@ -84,9 +88,9 @@ def upack(q):
     h = np.asarray(h)
     return h[:,0], h[:,1], h[:,2],
 
-class UnitgradeTextRunner(unittest.TextTestRunner):
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
+# class UnitgradeTextRunner(unittest.TextTestRunner):
+#     def __init__(self, *args, **kwargs):
+#         super().__init__(*args, **kwargs)
 
 class SequentialTestLoader(unittest.TestLoader):
     def getTestCaseNames(self, testCaseClass):
@@ -105,7 +109,7 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
                     show_tol_err=False,
                     big_header=True):
 
-    from src.unitgrade2.version import __version__
+    from unitgrade2.version import __version__
     now = datetime.now()
     if big_header:
         ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")
@@ -135,7 +139,7 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         q.possible = 0
         q.obtained = 0
         q_ = {} # Gather score in this class.
-        from src.unitgrade2.unitgrade2 import UTextTestRunner
+        from unitgrade2.unitgrade2 import UTextTestRunner
         UTextResult.q_title_print = q_title_print # Hacky
         UTextResult.show_progress_bar = show_progress_bar # Hacky.
         UTextResult.number = n
@@ -143,13 +147,21 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
 
         res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)
 
+        for s in res.successes:
+            q_[s._testMethodName] = ("pass",None)
+        for (s,msg) in res.failures:
+            q_[s._testMethodName] = ("fail", msg)
+        for (s,msg) in res.errors:
+            q_[s._testMethodName] = ("error", msg)
+
+
         possible = res.testsRun
         obtained = len(res.successes)
 
         assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun
 
         obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0
-        score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle}
+        score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle, 'name': q.__name__}
         q.obtained = obtained
         q.possible = possible
 
@@ -172,7 +184,7 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
     seconds = dt - minutes*60
     plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")
 
-    from src.unitgrade2.unitgrade2 import dprint
+    from unitgrade2.unitgrade2 import dprint
     dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",
            last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)
 
diff --git a/src/unitgrade2/version.py b/src/unitgrade2/version.py
index e344246..d1f2e39 100644
--- a/src/unitgrade2/version.py
+++ b/src/unitgrade2/version.py
@@ -1 +1 @@
-__version__ = "0.0.3"
\ No newline at end of file
+__version__ = "0.1.1"
\ No newline at end of file
diff --git a/unitgrade/__pycache__/__init__.cpython-36.pyc b/unitgrade/__pycache__/__init__.cpython-36.pyc
deleted file mode 100644
index 41c8cae17ecac0b36d54439732f20e778a3e90b0..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 998
zcmXr!<>jg>`XArI%)s!N0SPcOFfceUFfbH*F)%QsFhnt=Fs3l&Fh((gX{IQq6z&w3
z6xJ5TDCQKl6!sQ|D3%nC6wVfgDAp9l6s{b$T=ppTT#hJ?T+S%YT&^fCMurroU<OT|
zDpmtM13k-^AiMlRl0o)>n5+y83_J`B49*}s(-;^SN*J;jvzTfan;C1F!EELl=4QrX
zr4oiL77&Y(p@yl*poBGrv4*jkiIJg%t%fm$shO!?td^yOJ&U7;p@t=eIfbQ{nUNu!
zA%!83A&4OYq$jC_HHEdAk&z*VA(%mv&96!zyeP9IGcR2sIWajSRZmav7E^iBEtZ_B
z+(b>rTinU{xdlb3#l@NVc~z_~`FW{|nw+<o@{4b=6eN~p++t73EXqsFO})jIT9H{?
zQhbXwH#;S>=oV{1QD$DrEtdR()Vy2#Fhk-CGLy4&Qg5-Ol;##_vfg6LPs&P7F1f{-
zmYI_p4>pIrEVU>pzc}?4Q%c?~#<Z0TMZydW48P2stztrpQ;UjYN=h?QV_fo+OLJ56
zN{VAj^D;})ixN{(ky!EZnR%Hd@$q^EmAAOT-ij|T$}CA`1BI>-D7+bY7<m}E7+Dy&
z7<m|_7+DyKL>U+uk{LmA3=9k)nh6#ipm+gC0aFb_Gh;A=CZnGwa}g-Uia-VyaWF72
zXfhV@GcZ8h3U+Xj2m=GdEgp#Fkf0F&*$y(5fvHFg**1_EH_SFOMC3CxGZyKUFxN1o
zFg7#w3)C`}uw=1<qB(`Rmnj$;rFkr%hy-Cx7Qb6eMM*`VG^NQ{!~${_8=5<dK=u@Y
zd~}N?CqFSolL_K(P@q8E4GL|D<GCP?FG@{J0R>Jm$e#>Mpnwx&E|LV9&T@;*BQqr>
zHSZRCZe>w^X<o`Lw%oLw{QRO@EV;#{xtfe2n%uXz<KxRxi$Dn|J|5y6kp18Q2ZsaL
ztSDi4MC!p=MN*(Jl?D+qAVL;IfE|b+z~RhclbfGXnv-e=inwBs@hprSj2z5dTpX+%
FoB#y+;o<-Q

diff --git a/unitgrade/__pycache__/__init__.cpython-38.pyc b/unitgrade/__pycache__/__init__.cpython-38.pyc
deleted file mode 100644
index 9bc3be67fa220ac7114c9c4fa873a07a52b5d4d5..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1316
zcmWIL<>g{vU|<k)Qcv_@Wng#=;vi#Y1_lNP1_p*=HwFfV6owSW9EK={6s{EJ6qXjo
zD8>}l6t)(ID5ezl6pj{#DCQJ~6wVx$T-GSoT(&5-T=ppTT#hJ?T+S%YT&^fCMurr|
zU<OU@mmnMbLXts-gP0)9#=yY9$-uzi46-Z_WEo=$Lk>eNa|vS>(*oui#)XWvEMPWE
z4a-8tVyzO!1*{+zBSQ^Skwpnx3R4YZGZQ02340A=3Uf14zgR764RaPp4MPoU3QG!W
zFEb-UID;ueAVUyC1V~R-30n$VGb1BI3PUi1Cc9q|BLf3Nl|Xn=W=UpVx<Ybdaz?72
zp585{@}yfVIaRrdD;aNbC+FuD6r~myXXfWsvAX2vr7CK2-r|Re#usEJXXm8eV#+VR
z#Zr)1l5vYYC9^0mF*o%VTWUpSaY^wl*4*rr%%WSY1x1;8CAV1e3sUoLv80sd7HG2F
zV#`m;N=+`g#hI3wlNt}!#$J|Ml$2kbS_BH8TTCf=w;0n_G8Bn0FfjZwceaWNElw>e
zjwvb4NR4sHPcF?(%_}L6Db33)NiRxFNkwAC$7kkcmc+;F6;$5h2Kz0(yeP9Il@%1;
zAmbPqIT(2uc^J7ESs1t&c^IV_Ss04M7#J9mLE!?5A`k|#LD2?|CLRU`h7yJ>#sy3@
z3=2Uq%jl=cT*S`6z)-{iB0xz?ld(tu#0FUbc6N~{0|Ub?9*7elfdW!c%mgx?sYo2%
zMivGJ29QBu8~YFmgAtq<m_ardwN)9Fu+%W5Ff}vv%hfW~FlMpVFoDu&FH<-J6ExBn
zGlVk)L!&>Op|FdEp@c1)tEh>Qp_ZAEp-QfVJ%zP~0g{9u38RF)h8dJVK*=VBp_aLh
zIf5aQp|C50A&&)=Xh0a2aBeXbB^7}}rU>NVDy5L3%+wTxl6-}n{KOQ6M1`cp6a`4?
zPyofQLSji(u4kG;Nk%G^Ur>;mSX2zsk(8>CSXz>wn^=;WoS2hSsgRzUms*rqlA5BU
zP?=w<keryOP*PM0Qks&QlUkChkXfRmkYAFKT2!7{oT`wLU!DiGH7~VXp)9oslw37A
zz-b6AdWv{KvB3gTev8w!B0067Br`v+2o$rLERdK3rMx0xkTS+pNDPAG5*&?OkZ3GQ
zO-upti$O9Bj2uinj7*F?jB1Pmj9iQyj55qcG7Jn1pcL+rnUa#4cZ)r@vM9eaFXa|n
zZdy)$e$g$K+~U&QTb#~`1tq0LnR)5A_#Bf<GRsl}it^Jz`Aw5CM3Wohc2JrGClj!t
zQNr-lt_Noo$%2xc9Egwy5egte5kx3~2#_n$eZparo1apelWGS_;l-fj%fZ6M&B4mS
F4*-zdILrV5

diff --git a/unitgrade/__pycache__/unitgrade.cpython-36.pyc b/unitgrade/__pycache__/unitgrade.cpython-36.pyc
deleted file mode 100644
index 4fdacefd982002048b628fb9e4ce082fe99b01ed..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 11636
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
G9DD$>$2iOY

diff --git a/unitgrade/__pycache__/unitgrade.cpython-38.pyc b/unitgrade/__pycache__/unitgrade.cpython-38.pyc
deleted file mode 100644
index 75fca3f30359a786a8edcc4725b1b6e9cff4b706..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 14886
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%0ABh7S|sfEi%}KQ
zFZ#t;1CIQVBJdy%OOYukURlyI^HRV?7P$D+WGl)96_jjw;5B}?7;~bS3qT#!!ki+|
z+6SaC0S8AeNHHilKrK@SCKg5>MlSHYfB>Tmc;<kIu?VCFC0IZ$LJ$TA3#dDm!U*db
zl`v#6Eo1@*3^QmUe=Rd)dbfrd+!bRkVX0wmW=vtpW-0P1VFfL#XJja0OJRkGH#0Rc
z)_{hq*!-%TqII=n?G-fat-v@YMN1(@Pa!5nTR~Hy1}dbj5Tj?WpsAn<QWfo*8mkbk
zts83(Rb`LjXi(V=ax}P02U_|F?hUEbGNv%pFlMtAOMse~*=$7$pwYKx#yqwX#u~<E
z*kA?IEk-@?G=wJ8EzlbM#FAUgnRz9e(2g8qB6`4r`f<6SfCbqJ>K|1pqYbHH8=J`d
z!pOi-r3WuGkXQwkRtnI{T1O!lG@=Y0np4zdzr|FPdW#)Y@nz<uMzM#v208f$yGF5t
z(newqXi0c#9;7S)l?s|HkTfC+t_w4h<CF9Aib0hfsHvG3#Z**ri#ag|qr;HLz`&3J
z@)4+&3rZ@WMR<ISpeZFj#v+g`?iM6y*(Q840=yNc1vKUWT5t(k77tl)$qE@yh+<3O
z4rb8gy~XF43|eCt03DYM`Nf}G37V<}k5VcmB^IHKZGplW)Y}CoO3(}lwEqWMTE$oc
z8WROAbYqBTE@3HQT>x4+3+k*fOEWBFYzC=euVE^(sbN^a0h+-Abuu)W{oK-L%>;p+
z_L`ix7)x$(#21z3ftpK@@{=j0q-Zm!j0BYtMWDqFw;1z^mVr7R&?VHnL9!qLum<!r
z0;=RoK_Ln%i$IH~*%;Xv*_b3)SQx9sQ9X~S&_Vq&ScMK^gDQBipFt&X3dko6C5&01
zmLqctQ!j`QT64g%fECGKA)q#3Nn%lYYKbOW(H>Aa!U>xCO-#wmOOIj;$pFoQ-(oH*
z&AY`05eNGU+qgVfq6y>)P#}OjA;4HAg64Q|YX>DaqPQG1fd+9os3Q$p>&(bd!d%0U
z!qm)E<N#Xx0B%czSqoTGm_el^NEEbs1JwEjEgCOj&*A_rZUpf`8%zA$Zm|?3B^H5;
zOieDZCyNe&q65@Qyv3f8SPUN9I1KVUTWLW`VoB;P*5sW0;#9=)ambo~P|=7Mb+<U7
z(>W!n?I6E{BaoSmk&96TT!OMORY{<Q0bB!0IDkqe_}D*a^t^;23zRMyOPI32L(w3A
zf;I-Eu=au$y@UHgS&S)c5)9y;i5aLq%3?3}0WF$`rQI5acveP+!n6|31)yFLH#EFh
z7x1L8f!Kw5;PlN7nRRu037VL!QmxJbjr`YECnXlu)+j_*r{*LU6sM-t+Ef>%<|bx>
zl6`HgCVLcXNq$LU&Mg*Dix@nAoe3Jyj$+M8O)N`|Vo6CYPL5*DOU}<Jj^av6EQ*KB
zrbFU^_ZCY@VM=b%K2Su+fC$hkeMsg2#{_FpVqSVGB(^|vyWqC-E!N_k)YO8ay&w%o
zLD>t^uP*{OP{4INm;l#k2N@U`CWGPxw2FlR)b{w#!7K!79W$~qvM}*5RtcfSOi^i`
zpC(gC(Jqk5*w?9pv+!|{^&sPs5(C2CoeT^NB_Ml2t!xfPE?y2+4xS>AsHXBQ_W1ae
z{N(ufqG*sAph%D602T6}iMm^?d8N4pm5_y#panAE^mmIXGatNZp{NL?1=RZ~+6rPF
z01>A^1gJT9i#@jzyg%+1OKx##?k%=l$ObY{*9g2(=@wglQdVkm33#tVQ58rZXdQhN
z2WZ8Fb7FBSct8?7LjvhkfrgU7g9G5^5V-OO7w%xMVDtGc4jaghDmzf7F1BD`U|?YZ
p)e4|p51^562n{Bgpd>pVivX{Hv`{?*tALCEw~#iUH3uID4*(I~-lPBk

diff --git a/unitgrade/__pycache__/unitgrade_helpers.cpython-36.pyc b/unitgrade/__pycache__/unitgrade_helpers.cpython-36.pyc
deleted file mode 100644
index 4ec59209cb632db45b779350e883f1da9136585c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 5594
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

diff --git a/unitgrade/__pycache__/unitgrade_helpers.cpython-38.pyc b/unitgrade/__pycache__/unitgrade_helpers.cpython-38.pyc
deleted file mode 100644
index a40d58d2db15f43562585d0900f3bf41997aa7d3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 8338
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
bA}nv%L`A^k69S9^OkBYn91M&Mj12z(za{tO

diff --git a/unitgrade/__pycache__/version.cpython-38.pyc b/unitgrade/__pycache__/version.cpython-38.pyc
deleted file mode 100644
index 60c21c4fd046cdd33eb3c601e3df33ed76e6e12f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 166
zcmWIL<>g{vU|?w6zbiqMfq~&Mh=Yt785kHG7#J9eIT#oiQW&BbQW%37G?}Vc4fG84
zEc`SXZ*j-Rm!%dJXXfX{$FF24Vq#!`5WmcvtztrpQ;UjYN=h?QV_fo+OLJ56N{VAj
j^D;})ixN{(kyub8^a?6(aoFVMr<CTT+JWr;3~~$rIqoXe

-- 
GitLab