From 7e820f223f4b9ce5cc9c87d56f0e203e26e467b1 Mon Sep 17 00:00:00 2001
From: Tue Herlau <tuhe@dtu.dk>
Date: Thu, 2 Sep 2021 15:33:58 +0200
Subject: [PATCH] Updates

---
 LICENSE                                       |  19 +
 MANIFEST.in                                   |   1 -
 README.md                                     |  36 +-
 cs101courseware_example/instructions.py       |   2 +-
 dist/unitgrade-0.0.2-py3-none-any.whl         | Bin 0 -> 17438 bytes
 dist/unitgrade-0.0.2.tar.gz                   | Bin 0 -> 17257 bytes
 dist/unitgrade-0.0.5.tar.gz                   | Bin 30274 -> 0 bytes
 pyproject.toml                                |   6 +
 setup.py                                      |  43 +-
 {unitgrade2 => src/unitgrade2}/__init__.py    |   3 +-
 .../__pycache__/__init__.cpython-38.pyc       | Bin 0 -> 1306 bytes
 .../__pycache__/unitgrade2.cpython-38.pyc     | Bin 0 -> 22713 bytes
 src/unitgrade2/unitgrade2.py                  | 705 ++++++++++++++
 .../unitgrade2}/unitgrade_helpers2.py         |  43 +-
 src/unitgrade2/version.py                     |   1 +
 unitgrade.egg-info/PKG-INFO                   |  10 -
 unitgrade.egg-info/SOURCES.txt                |  21 -
 unitgrade.egg-info/dependency_links.txt       |   1 -
 unitgrade.egg-info/requires.txt               |   4 -
 unitgrade.egg-info/top_level.txt              |   2 -
 unitgrade/Report_resources_do_not_hand_in.dat | Bin 64 -> 0 bytes
 unitgrade/version.py                          |   2 +-
 .../__pycache__/__init__.cpython-38.pyc       | Bin 1373 -> 0 bytes
 .../__pycache__/__init__.cpython-39.pyc       | Bin 1400 -> 0 bytes
 .../__pycache__/unitgrade2.cpython-38.pyc     | Bin 29204 -> 0 bytes
 .../unitgrade_helpers2.cpython-38.pyc         | Bin 6959 -> 0 bytes
 unitgrade2/__pycache__/version.cpython-38.pyc | Bin 167 -> 0 bytes
 unitgrade2/__pycache__/version.cpython-39.pyc | Bin 164 -> 0 bytes
 unitgrade2/unitgrade/ListQuestion.pkl         | Bin 466 -> 0 bytes
 unitgrade2/unitgrade2.py                      | 891 ------------------
 unitgrade2/version.py                         |   1 -
 31 files changed, 793 insertions(+), 998 deletions(-)
 create mode 100644 LICENSE
 delete mode 100644 MANIFEST.in
 create mode 100644 dist/unitgrade-0.0.2-py3-none-any.whl
 create mode 100644 dist/unitgrade-0.0.2.tar.gz
 delete mode 100644 dist/unitgrade-0.0.5.tar.gz
 create mode 100644 pyproject.toml
 rename {unitgrade2 => src/unitgrade2}/__init__.py (90%)
 create mode 100644 src/unitgrade2/__pycache__/__init__.cpython-38.pyc
 create mode 100644 src/unitgrade2/__pycache__/unitgrade2.cpython-38.pyc
 create mode 100644 src/unitgrade2/unitgrade2.py
 rename {unitgrade2 => src/unitgrade2}/unitgrade_helpers2.py (84%)
 create mode 100644 src/unitgrade2/version.py
 delete mode 100644 unitgrade.egg-info/PKG-INFO
 delete mode 100644 unitgrade.egg-info/SOURCES.txt
 delete mode 100644 unitgrade.egg-info/dependency_links.txt
 delete mode 100644 unitgrade.egg-info/requires.txt
 delete mode 100644 unitgrade.egg-info/top_level.txt
 delete mode 100644 unitgrade/Report_resources_do_not_hand_in.dat
 delete mode 100644 unitgrade2/__pycache__/__init__.cpython-38.pyc
 delete mode 100644 unitgrade2/__pycache__/__init__.cpython-39.pyc
 delete mode 100644 unitgrade2/__pycache__/unitgrade2.cpython-38.pyc
 delete mode 100644 unitgrade2/__pycache__/unitgrade_helpers2.cpython-38.pyc
 delete mode 100644 unitgrade2/__pycache__/version.cpython-38.pyc
 delete mode 100644 unitgrade2/__pycache__/version.cpython-39.pyc
 delete mode 100644 unitgrade2/unitgrade/ListQuestion.pkl
 delete mode 100644 unitgrade2/unitgrade2.py
 delete mode 100644 unitgrade2/version.py

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..335ea9d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018 The Python Packaging Authority
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 822df1c..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1 +0,0 @@
-include *.dat
diff --git a/README.md b/README.md
index 460eea5..c1a3fc8 100644
--- a/README.md
+++ b/README.md
@@ -4,47 +4,35 @@ Unitgrade is an automatic report and exam evaluation framework that enables inst
  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. 
 
  - 100% Python `unittest` compatible
- - No external configuration files: Just write a `unittest`
- - No unnatural limitations: Use any package or framework. If you can `unittest` it, it works.   
+ - 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 a Docker VM and run hidden tests
+    - 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
 
 ## Installation
-Unitgrade can be installed through pip using 
+Unitgrade can be installed using `pip`:
 ```
-pip install git+https://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git
+pip install unitgrade
 ```
 This will install unitgrade in your site-packages directory. If you want to upgrade an old installation of unitgrade:
 ```
-pip install git+https://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade
+pip install unitgrade --upgrade
 ```
 If you are using anaconda+virtual environment you can install it as
 ```
 source activate myenv
 conda install git pip
-pip install git+https://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git
+pip install unitgrade
 ```
-Alternatively, simply use git-clone of the sources and add unitgrade to your python path.
 
 When you are done, you should be able to import unitgrade:
 ```
 import unitgrade
 ```
-## Testing installation
-I have provided an example project which illustrates all main features in a self-contained manner and which should 
-work immediately upon installation. The source can be found here: https://lab.compute.dtu.dk/tuhe/unitgrade/-/tree/master/cs101courseware_example
-To run the example, first start a python console:
-```
-python
-```
-Then run the code
-```
-from cs101courseware_example import instructions
-```
-This will print on-screen instructions for how to use the system tailored to your user-specific installation path.
 
 ## 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.
@@ -83,12 +71,12 @@ To register your results, please run the file:
 >>> cs101report1_grade.py
 In the same manner as you ran this file.
 ```
-Once you are happy with the result, run the alternative, not-easy-to-tamper-with script called `cs101report1_grade.py`:
+Once you are happy with the result run the script with the `_grade.py`-postfix, in this case `cs101report1_grade.py`:
 
 ```
 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.
+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). 
 
 ### 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.
@@ -97,7 +85,7 @@ The reason why we use a standard test script, and one with the `_grade.py` exten
  - **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 `*_resources_do_not_hand_in.dat` file? Should I also upload it?**
+ - **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.
    
  - **I am worried you might think I cheated because I opened the '_grade.py' script/token file**
@@ -135,7 +123,7 @@ 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 (unless some code in this directory load other files). 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. 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. 
 
 - **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.
diff --git a/cs101courseware_example/instructions.py b/cs101courseware_example/instructions.py
index b6e149b..9786bd4 100644
--- a/cs101courseware_example/instructions.py
+++ b/cs101courseware_example/instructions.py
@@ -18,7 +18,7 @@ for d in os.listdir(wdir):
     if "__" not in d and d != "instructions.py":
         print("> ", d)
 print("")
-fprint("The file homework1.py is the file you edit as part of the course; you are welcome to open it and inspect the content, but right now it consists of some simple programming tasks plus instructions.")
+fprint("The file looping.py is the file you edit as part of the course; you are welcome to open it and inspect the content, but right now it consists of some simple programming tasks plus instructions.")
 fprint("The file cs101report1.py contains the actual tests of the program. All the tests are easily readable and the script will work with your debugger if you are using pycharm, however, we will run the script for the command line. ")
 fprint("To do so, open a console, and change directory to the cs103 main directory using e.g.:")
 tprint(f'cd "{wdir}"')
diff --git a/dist/unitgrade-0.0.2-py3-none-any.whl b/dist/unitgrade-0.0.2-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..88df3c4dfc76af895eddef0e9e1a54c7a0cc5fc6
GIT binary patch
literal 17438
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

literal 0
HcmV?d00001

diff --git a/dist/unitgrade-0.0.2.tar.gz b/dist/unitgrade-0.0.2.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..24bc625650b200d9016cc5ada901d05c91e0706f
GIT binary patch
literal 17257
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

literal 0
HcmV?d00001

diff --git a/dist/unitgrade-0.0.5.tar.gz b/dist/unitgrade-0.0.5.tar.gz
deleted file mode 100644
index debd32cec15ab13d6feb708942d2a2a9f1400e1a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 30274
zcmV((K;XY0iwFos#n@j0|72-%bX;|AX>@0DVPs`3FfK4IH7;~vasceT>yqL~vM@Nm
z+pOP#lWp@Q*<>XWcWS@v8FWENfI#9Zs><@{h9uApNgzRQ{o3c*m)L!=jgSNhq{yn8
z>1ms@Hk4I@6cHXC9_}6<5gr~}+XysIRMZd16Y^9o{^eirLBOY8ugBlubNwCvM$7eD
z4Xu=_NcArWiq<OVUvkyI{0X0}ABbKq_lGp{ym9|SKHIDQmwgmLWoPU8YAAZ@iyDcR
zYpTURxBqKpr2L=$|99&D_`RpPju)U$?*4~KQ>)c(^?#{`){gy;qLs>DkP?cNDu2l#
z|LOmK`Df`lR_??EPp4lw!-9RC<F=|F7>-SO&ena*@i7NH=D49}*a01=*3UoP0`a1&
zrmK4X5tO<U&8--yF9{pH_`z0D?H~nkgYk}qb;nXe$6KR6|Mc@uvMKt0u4niGukJt%
zqIpC!e}V7A$De=7flpur0Mc{r?wCF2EORC(eg~n!9B(1Qw&h=&c?1PNCIIybeaw{~
zbJfQj_)$ZVFR#gpy3EOr<!(V!McWTm@5O~+^1f;=&*8w&du@L@HTp;eFGfy%fw*77
z@zh}J*%uk&`ku^(+ijdVp5n(1y>9uN=H7wMG@ZN0+#Nv3RNxPPYgwuXe<_Z3_vO4}
zY*qAlRr6He2YvCKos$#;O*odziMEo%96ta*6)_Nf6?WKbQ*cLJE)CfLOys}QT>+?c
zxwSzRujx;qyy^wL(pfeKHWX;V@{wTw;?9)fmVvH<&AtS5k(7V9M#%LX8Ib73*#-cy
z7?nprH~%pgL_j$0ttEk;yv8nNku>$w#}DY2OV;4~BQmDrHDS*o{bBW|)u&Y_BTGK{
ze#090C<lm|=E|Wd7i>~?@*#ufv(y0)(1*ud{uV<5;VnO;lIx1{`X%X^7~ZM7zT|$%
z(Y9;?Wt9tb!_O@ZsFv*9Q{b#sJAQ->F_yWP7hAN{mzUf#!1?9H5)J$1<t}Z^4fU5l
zHvIu~^Z$(T|0PlM-)#lFKmOONwQBil{4bRd^grYOpYgfBzn`^umS(AsxxS+q%e`T1
zk3h<y(ldYp(sGWMa{^uULc<3V0N6qG;Oo!`^h6+h*)v=q_eOB<$BG&j0VSYH*qQ;%
zd?qWPplRkLC_+0Zh8mCwB`5khF(>P)7-ts)pmp5f319~VD^Zs~Z@7Dy&vt+QX{JiO
z&7kdR{i)v>a$9=7(x3gn%S;(RvyQE1CfUyhv_LXanCG@=`q`z-=XearOp~8Y)y_<z
zo>kBW)dTI#Oy55nzQ2`Xg_xOP`K+k{AWe2FiD$>XQ8W7tl}~2U;aM{s3A8jbm46<4
z+iYyzXWIp%sOWj(J~iP2QQDfIb;kkj_?#vK&QJrxIwc>UGr^0`$K)s52~SMm8uHrA
zE)hN_iBF~@D*kJU{nF4(HM_IO=VS6y^7XQGJWC8tr48G6RXMxx`Z-N~lDD1*RQb{q
zZ?wibWd%J5Mora=^S)x~WYfR<?D(*V94eXVI81lNKtBNzJ<S!p8+@xgACsSWF&wK=
z&;cfTJ8m+-DYMMzwM@&?0RP&-5I$w*##YZ+Ao7Zu=m;?8KHrn+K$zQuVJ4T1DNpy0
zDo{6$_I!7DM<!#=$K209jh&naOg9l|3~0vraNHHsGBEu&(7%E1*tyrK>8X%ooBNZE
zkSjr@^!oIKW){wU*yKvLQ(!693Dk4F2UMP;0<Gi(xn$;a-mDzJ<;~m2+}2k=zOCgn
zuKxT}+ps~K_m2=PtW5;0xIBlE1NDPm3E)gd%vp}I1)4PvjTli=fz1O==R^g^xf4{u
z(`IV`t$ZpPLrzOQ#sxlDIVbL@91w*gf|j_48XKU!+?r26|I`B7+Rml6!DG(fx~>BU
zht~=dBgxMZjvVuhUrdaOm$b6tD`gX8|NAoizhPnVSbzHRDTnK#t*JQ$G(rv>Zx5{Y
z-2H1E{~d!;BUJ`6c1~f?s!RA!Y5hO{<g02<4+7W!SS%`z4CE;;^5l40vHa95ZhbH!
z6=h3-*7%biSU`~iCVk8;k8<-8tL!Y!S01vZ<VjSN7cmv5{QZZ`{i6*Y{pb6?-9H9<
zSIq*ZKLXoZ1OsYT;`kBHwx90@km--6X2PZ?rq8QK!GgT}aQ~gieeiWBR3oUqROS9r
zlw&cz12Yt09|mB2xJ&CEfqXF!95WYz+=HG{QbXW}DoiI`-&bKWGfU({c7U{{rTy=&
za%)>4|2Hd38UiIJnFT&QJw3q6EWmfMa)Pygccm_18zAQI)!Nzy4&X9FhUy>(3%n}B
zr`#kK$Xuuc+e%TTt)>B9eS-DFX<7yjyL`q=>hZ`T*_^d8fHjtx6i?JLAd1hK?T?2M
zNC6+tX`x0t@h0HYtO{az&Z^*P1B*bVn^i2Ha=p_iSRQ5p7~DPG!G1etP9|%|r?lyx
zvMk5^?g47Z-FfLJ-!+XO4`3$KO4W=NeePXk0H|Z?LpC|B$BdWjtadry=-;b`#eW~c
zoLK_uI}0`DG3C*0BBqItP+(t<QlFjmT!|$4j}m@6|1rm7BAwY8leF*Tr?@k+Ec*Q2
z&~tVMTpbY2qXGpFcM$N&lFg#-`XL)8hG*fszKOtlb>I&Vw-L|XWwQ-Ti;b1kY=D}}
z&*|b$jpb&q24GBAq4l8|J{ZPS<tg{shQ?F+;-cVV4vZWk804X81$8bQ;XlSzFTE_*
zvGQ3qbN=Ds6Z+)|7Pez+`3B;@{r214W0uAHBmpE~(frbT`1J8Z`AgyMWH`M;2|B^r
z2PJ_yW80v4U@i$-nDa#Ybz$cz29YjRWr^ZV)f(kDu{zYBKjn>2_u>7QNALygBHxfq
zHF<KRKm=BVa{ndP9Y(A>o*=WSKqY>OOJ~is^7<K8`lpYN$d^a>g(hF6FON6Ta{gG2
z|BgNY%Hmy3@+~EC%<_(209kITf)#UXH0oyM7V|fh?I<fZnZKLZMnFM6yL((ZcJO?s
zIF1!_i}ZZ=*}i*PIfkA8WX5*0341mRcrrpjQxbHzk=0`>Id4As0kGGBto(+2xyjN}
z;V!qkE4;kGHBZo$FE2M*l&N96u#P31VCV1tsucff75^&a{@VHY*Z#-9j^2@@Q2?e6
zs`4>+SIDaBcENPo2bXs;i&9VVa_{3^9!xWGA3i|)C#GdG9q}J-BelHifjK{1MT+e}
zKVFCj7(QlJbL6jdJ>P$Ua{mas@CN<X&!3=Z+P&unlAR-X{{1UdgaBLnF~4~XA2Pdt
zMP&-((`h05;l}ucWvYdJe)IH_Og>&-9y^AjsIdicJrLfql49e^E};MQd};m2fV~YH
zuKVO}(fhc9p8Fk?|N1fa`zGnVuXpbZRL^(6+Pye^^K{gU&q(ro)Qsu#OG40?qN~Sz
zY^E5usk(WBIgUFHu=()$n{EGYB7GOMRZK~kHC^#Pr(+IG5SMqq{`zZf6O-)ecaZ(-
zL+*E&|46$yqiR0ey$_XROEMLN??3!+)l94L{lfG8)BUe`)%<WPcTDvx#u{fcR*Y39
zZ$X^0$$*Vhgfe^I_a9YTdA>^+B$p)!OqRTw56>|&ni{;gK*I)p{&FC>c)A)vE}o7<
zNAh(V$kOiwt<B4))tBer!RY<b2p?ZZ?~hrSJ-&|TA2XYCug7%DOdWsyPHJZI0LDCL
zDfJ^u+!EViYcxtb;B0PkGdpD0c8l(jL{cd9GkYlOrTm<2BE8(Qmd)&$QRx3YlPPXM
zk$(h={DV-ez2|IgC7+p?4}Z<9qL_*PL-yE@nZF@%$K;S3s0E+wls_-nGyDcG%8&Q|
z@Bj7x{NGSX-hbS@yvv#T*DIBr1@B6WXEg<8@zGT4od%3V{l%)zFM&ijbR28?TKqjs
zlCo6@T7XmQU-LjeW-B`M;YLCUP`m*Cerpz$Is89~t_yTm{?pmGmp0>ZdG`kY*kb$V
zMJ22AZx|>yWXJNiS(7lxe%Wy3AA=*`f<t|iF)|B%i{buh)Bf9r@Hg$><sI(8HPjzA
zfzR0JZtMi2dG~miReq)C-zCmN;jZ{2<&Hh^@a5Lx5>O`rMCkrwW+!J4%8&Po3J@~=
zOcfG*eSZ@Dn7uOcXYC^XS-W~G-^t#P4W41rld`qkf59H0bSV8J8>TlF5L#JWvCrzk
zLu`M?egRp#*Li>!7^Z*>+&^T&JUrfo!QF!hrf;!bvV00XBYQn;e{+R<g=MdIB(6#?
zis9W}$hL3J@BY~Z*xR$>_ZIKqeCc*-yhV7uQu)Ixi|boD-1>CyJ6lgy{rfM;WGovE
zN`$^4a8?he(f-p@vVsODZq|)O5TKOKoUP)%zQr^|9!^6bWH1Z4_wHZ0<6Ag?f&~+I
ztS`^YCr=fX{KGplT4<#F{#xei-9JGWY@fwsK|YhS3>&(EJy+5d>{mv8cMbb}e(v5H
z0g30#{y5F_PVFz;z35<4YuI<$fY`_Hv_l}llHuh`Hl)Mz-CzBezZx&j68udZh3@{E
zMJwX*yAgS~RafSca=dc)O3`fHmJRVowBtXd1fT<f8sub8Rg54OtISpTtqZkyvcwI9
z(M;Fp--DdF!2TYZ02NsTb7|iO2tkPjB+H5R9=abGOGA#;kRQwc4dpCkQOn3eg9r2T
zJ#5mAMcoyfzk~bycbP*8pS5*xh+QlJ!Lpbj%pdE!VVyo_;*iyxha;$G*L;KvxpL-?
zJ^%hj1C_al%s=0st@lFL*w}6J?z4R|B2GWyx(9T4eMyG-&-Q0K_GT7kU42Q0R!3R^
z^W`z-m00i}bH^oo==k;U@v|NK{6gpH)XI1Q0+MXM9Lqc;nbMVvV>UH1{J_sE_7MpD
zfJAEz0KnI$QfZAJ(=GM889)t=Co!UMJUPQJEfo(J(2~fXVgC6(ls?}-<{onKAn{u3
z6(M4?>$T~Rr}TIW-aJ_1-EHIu$5#IfreBgXZS5<bY4yLnq7FzX+b?HXAo!#-sC{Wf
z$;AJZo&ZQ0<cg~2^tePM9_RjeG~mE=3xzXE-{=<)^vj!GIcwc@2SMS<zt=Ix&o4&^
z7X{Ny@dDRt{xm0a1x<+d*}l62f};VoDk@6uDfhqrR}MZvcMkCN!OGnYlC6ikV-nDP
zI{XdlbKxu^fW8<Yq2T-a$6^uu`aAe<iqdhD;YkU$Ps+L&Y<0ExdPWAq`tV`v#!n|q
zQn`iMpnu2d#hK^pg`CIpA;US&ghl~0!|1^&kH0@x2BxXTUM8>a(%B2FKV8}a%wdX_
zq=>obBdF~uS?`J-5=zIuW6BfA?QgA%tZ;!K0%W(ArUOQ(D=6{HI6dK1AM}I^2ig~D
zpBNr_{1I;J!goh@N_iE}uuYCUeJpaOoZ^xE`2I0>rZRrHR#1iy714FIznt`xxCSGx
z=fCE-5Xj3qV9Sz&49QCQQE!6A>V~4Gheh7-BGj?4=y`t~0rebBQ@vD8J)8l2c`*Qk
zyu75xE~M>pse0$Y<6}QyGHS&Wgl7o$$qy7TSYPEa9StNW0AR((8j`Ug0S~6LKJ+NO
z1wWmm9kacy;Z26udX^>-r#H0uCEbjNiJ*F5Whn91i>ksMzB8x9a;zVK(IFY85$vB{
zLBJ(_SkW(MZ3it)N&4_gWL$JXM*ykG!vj<AQ2AHrwDg!ucMxLFaPacibqL?TAx@GF
z)R_D@OWnE<fu|Gn6z&PqIeA`Qz`Q{9PB_RhvS6(7Jje6X0UD4?aqQ3cP&dWizlkSg
z4$R5arz^BxPL#OG5-)zNM1WFxKIxPES+5$)^A=ud^DJUtLOp|YrJdiDzbts9ONzrK
zDXzh!B|+kAQ^7-4Wl5gbmI88Gss$ZObq6}IUeo8YVmOvwym%wwu+UYXM%QfhhJDm1
zfa`>p6o5-Wv7-oJpK~9AGm<K*dEJZ2*zc)uf{^na==%~k@2tiwqF-{xvD4qD`WZdX
zdLS8S6KUh(!)3?e?P(1D;6RNY+kZUmm5k7rC->eIN)Pano2_W3nUnK-m(;!xVtAYj
zkmcp%Jsh74fo6sWU!2bOrPh0rcrBsVot2JLNt163Rj*u`T@~b`%!D7(9M|2I&=aUm
z*pMt4ITHNTj&s@_4@e%B&v6s=<lOrRDIOE)oF<_1xFepkYE8N*soOEn7}r=XK>|Eb
zBKi4T{`F)@{#frr?nCbE^%04Ohume$K^{wt@(|)f?l)ND6%MH#&jL$8h0GJ%tcDG9
zs-9@eYVLRN^Xs*xnG{>zk){e2?1%U;6s!g4Sy0H&{SF^sv*5|whd1TpMxXI)K8v81
zuRSln3$?fX#H%J43U})Nr2b0b#9zf+9#uaya)obzE!+b8mJy&;8pDqH0I~z}F}qj)
zf5Q!zN0n1vIJa6ZtWXi64Jx4Fjuvc)s*q5(=kK7dO+4wLA#qs;OuNZt8HQr4!!ufV
z0rcFxBL;n3he&O$OP`PPmnUbB<mIJ_c69Q1$6`BfkO4+SFV_qp)Qj=xi0nnZFR#p*
zt!jSz?YEo&*X)uN#*f*|bOLg2>YOS&w)`cZMd+)_$TZ9Q6~5_)SmM3?6<i=nna18(
zou8rW+-2$+`4ZFNk}oejan6mxNLJkdGys0Z5di$0`W7KLjZ1s>U96t}=+AXC&vn5J
z9>M_hgG*OIasn-pqS*HNeE<7tnEm?s{_LnqpnGZ<AE$z%_wjZW>dln9Kc%6^{a8<w
zRY{cBZ*!cIo?^TJ*UI?}K&fq<M;=eY_i!$Gu_bh}slH_y8CN0#&-q;lXttnSG3_;!
zYkTQZ2veLg%HOE;md1Eb@_xC}3@1bN%_116JX;)oxfaG0!VgN+Ns*s$d48+TpWkBl
zJ>vW)O6yTl;T$5>jY-IkcjWYRw$l;=SwA&4-G6z?#jvs^H(P4I%?aPdZ|4kh_u<y(
zeAxN$1E0Hx_gV3W5xE|c{&_^+CCI;=mEKoj$5iwp_0`z%0s3zj1>b6bSGoH^p-K@z
z-k^k@&Bjl`aPnLd<mHwbc@gpE6=b|-eSDx)JC1B{l&erTfVhCkCm0GPHI^`Vz6jgr
z(nG9|Imv+mB-AK~7aRjPdOGn2=4tIRK6-n8(h@W^R813prwvNZ&b;CwdMY3rJpAlj
zg{jHq;Yr`imI2gECwzFy(RLE!0<IA#{$q*;Kut^A1=k=yo?A-r6!r57T<e@r=UP32
z16dw!lAc<XqVoz_l$_l;`=k+ajs=g8%Xozz&Hz$KA5uu5k_#j5m2Iv9^}G$y^O*bJ
zS1Rqd3s4^uGJnh^J0Sr3gy8WyY`pyH8NOrRV2WgdapKhc-8GlQtCYF1etHp~Y6tV8
zxc}mITsGlyCi1;;h~7%(G1EUjd5X8XUe}K=En3K+siwOYOh4Nse#<&AV{E0IyC-CF
z3E)#;cm*%%o4o&!xeoc1#SQ)|nO;@Hz*FFHKpZ~w)dVO!m40mh-{Wk_+Wh%yo9n4A
z3>tJ?a7*_8;8saiC!B3bJ*71ghJ2zy0@7B)EO3v>aIF}xdn2bfR`BJg&-X7cP6G7h
z<@5a)7}9C2?qj}%-|(pRG4m66;pgLxP?!Wqdyt%mAd<ie5CYuCe0hNr@pNVH{^84;
zCP5-SeHYSadiXpjS{@KpOu`9dbi(yY=^f>Xt`0g^^khAiyZ9i?#jF*^dNAPe@t1hq
zfo5RL&F`#~{!xpb$EC;wsdttlk63^Da+zqUM<)NICEhPu+&Q1pNH{6JTJUg|n4)#+
z{x1-ZqpPOjCp(U?NPM*C6mti>dQ8@+AFi-?1)bt^%SMiyarE=e#Q@QZg{jNN=IK1p
zz+r+r4St=lkF$JvWs)RFSpE$Iq|r9w=ad01qN05{vcP3<voG)Ted@82teBjyg<ojD
z>!tLwJy=ol;dlPpVdTtN7J3K78YM9*9?o|$et8#otP9~U(~zEqu$rTL-~$XVpxObf
z-!Xw^g|xj(8{il3u6rSjcW*D*`OUucjg5nASeZu(ud&XowUE1e0g5>BD11?z7odG&
z&pXg5Pl_14LHjc39hZN*sd1|3;W1?`?(vngPUXLxlRQpJdL9xY{&6A3$DNAw5Zo;}
z_Te&KlJ)2Xb>gVx>-{ajGd~l<kGbSFeIIT~;W-j#UNP@Lx{c!vJdXqP^6t0XO!REf
z10Q2M1`L58PV?>5$c)dI=6=7Hk9Y9-3h8VC)da(N#BgKJa@f~N_%wDfj=2&V8o+J<
z>IPcZyej&TGtzK9Vovhnuxq9xi{{Z^CHB&Ly31JKS*BFTXls@==VvVK+#uEKbog?M
z`@E+TQ9H`(r5-x(YRJ%=$K1<Xj{f*oYsUvilf3B}(T|x8-z3tQ4*f?Yaw&w&#7{|?
zFE^Td<PI$9f}@P*;OGx6X`t1>z+=IQPi*YIM&4bX2der#spV@tR)GSq2`9w9KIPh%
z+yOC#Pg%YEJw5%sz5R_IzwGrlNW@1>Z*GWQlljxBy<dQFcU%R$|8jIHx;BELai8LK
z3Z9#K7QrBVh776(0s(4-A)MeI^XL0d9|~XomdpR`WBmW~XXRJ$=L!BO<Q{VW=kaX;
zzWp2Aae^;Ck?NP+r@{wNGR^q6&-baXPz1n&8BP*QQO#%83}-A)Q<BF9BQhlu^eO`d
zqo<`|E8roY%v4^JJ}p7(gS;5qte@|nKHn#S(PGy<NN_Px{9^ptG{0Q<E`b-xwtSX<
z*}G?O(&Srba83}99;a6^_!6I-Z-tyrT&Q5qGl#e&2f%TwWu-j5$#d=F_SQf47}qYL
zMf?*wFWd-scM-$xb9N9rI7`R~W0wR~xgEw1R-X}Z4!-`rP<A%}#9_W}rzGY6sBm^!
zIGp0Lz{G#+kanN#f2)vopKr#ryCCz;sCF>dkH@u(-B91gwR<;a<ik;NE`ytWzW=a+
z(vU>8`+Wa5_z(xS0|U?FaSbqav56y{eg2Wqbzt&+v)+qvb+Fo8R&=%8vDR+|t@~zG
zM+@!;s=67j?%m2#XTtBR=DPyby<1(n9rW$`{*e%Mam`SXXV(r*S`CciuyVK}vJ*W}
z5qn}Hkp9YB1@Ibz%KD@z0?AH6#wsB00~rVy9Ml{yM&=eOpp&;2tQfFG06`tg#XXS{
z=JS0*nRsA-2c0<m832400ZWX&g+27PhA1DYlFO%sKjxr;5T^k!4=GVk7SWA><43K1
z3IUZ!VG{G{e4-EO8(U&AUCx8|oel+@M^J%9V_gOFyvFCdnkt@3Jg50CrkU5#_%6-H
zQ}nttz6&sfAaCyyW9MchzISJwXZS!^r$~IqY07a=>CDOQboL6EMW*@^N4$Q%Cih!1
zUtymH-@A5nIeM(b#5u;-yK;Yt(=Gz)UAe-XGF-<#i4#t47dN}{+&w1QQM(l#?`*5%
zc*^vZDwnD8ipXo?brqN8&sT&}6mrMfUS0TpEVkW`2e&(tXz9i5k#*QRpLJaPD$3mj
z+HqvN(<;ZCXm;_6&}%%qi=y8j!|uY~PaFBF8Me?|fZ^(nEUts*9Sk=QBiDVt55ctR
zF$aGgcP~#bj!_7}i$v(IL)fJ?1AzZLtP`knmp}coZD}yPTpA58mxjYj8+L48=)dm7
z0@|k)!wt4G$kD@-4+KFyfbNU&i6B0I5Lr&AP*S|JF}k6;zpb+0c)DF_m4D2C?sOIh
z7!=RB^H2);Q+qCbZ=TaLE%ET-%ZBkHC4Bmv%Z{{u5mzsF9#}5{B3<r+<<8^lomX(-
z6Ax7yki4@vdeHatOYTCNBq(XQ-5vNk522SXP6eqCJ!C#7d_Pv+g^a$&#{+;*U@r5V
zhr$E7(#cg4{x0`U{JV1?H)Gx%!DWZJ%bhzuU5sDHy#l)j9vUY<`gqR>y!riWstV&6
zce(r~-nan0aJtkW<<j$Lc4x!>OA>Ji>e1I7m-F~_>Ae5ar|LRF+sVeT3ux}Yo^Kfn
z$H;5vTiHjly%W0b&5)BstUGJP)0wv@a{m5Iry%FGZeC*A0YOOuC8YE;Qgt0S{^@dY
za|NiIm<Gl*g->zr-mIEm1iU*@=_dIybFWgG#v$z9F4$!eHHkkLFLiz+w%zrTIuxwl
zhsv9VK)Ln(hur@Ld9oJW{aoQWS@Mbl-lf^E))%vQ?JA_*TXs8hh11VZ@ntM$0_B|s
zv%AcaPmO>xzaNOi55%v_eSZME+;s%IE5jCsvV+VQk6a%CGr=wF*P-j<+4yrlf_==L
z8u2*|69!)<zrJ2OT%Ab-=$F&)UqN+mvz~+mWKAo{$oZ{4fakx`!q2Z&zPsyijC}VG
zY*<`I!8_;un?^-yUcEeII+;VDp`ZJEmgCqNkW;o(;HR6}j&bSW?|cX-dMc7DzSjKk
z5RZ$eXD}kBq2|tZ7@>0dWS_Im8?Fhj+2!~fzCQ+;gYP#lmmG8)0={18$8*j3Y6fL0
z+!Ge(zE0>#`CP|lJIhpxGrbKpcdhUNv_dY9F_(iu=3?c7J|y3z2S7rQ41m2eH@O^E
z--{fV%M2ZNY}+@OEAFVHJ#fiexj0<gtNuxIUGYqk>y=U9$wyrDgV=8_SzQF#j;3}z
zu4nedS^CY6ylp<dV`gPqS69*3-q=?els^Vr%iY}-K;HZnvPn3#vxHZ|eYu?OCo&O-
zvVq*3e`Whq5y<apSTvX=?xe3-Q?bX3c`*F<hitoCZ+5I=*SxnoAJU=pW~(Ndcu0rj
zxHc^L5--)p@p$5M#z7K^Moc0FIMQ<KCm~<rQTFJB8T-W@y>np1FQ_eCr~w}GF)Vn6
zWN`N;9K<o&*RkePv;Zx(n_iLtH!p$na*9E7niib}Lpoo-vQtC$N7rmFjrHqghd3(N
z#hbU0xXzQa)<sUUCos!$a<7qlk}cwRN!VE)9RN;&wJur$W}T_mNaEdgw9iwVvcht`
z8t`#st|P;r$KuKg<#85)3&!%e8Oq}=TIVsipaxE(aJ{w3-v-}0>cMZc_Q);Z)oVn(
z{He1~v9*r$es3nLq;5dp@>@#jb}}U&vLGY@`_5KMFXMV$EwY^@UX?!jZ^hf)&~x(z
zt{BDJ%9mK2h!-y)rLnt?<r7`?cs^9T5;j$7UyjG9*RkcC8I<c9kH<HV;W$!&-UVl4
zOX2PXPIGg2DV)oSE_|fUf^empCtU`(p_fhs%9hoCI(XLQ%H7>1Qm>VKUs$YD{F9iI
zUt)h8Fr|XJA@LGDZkr|<PR=k#eFinmDeBdA-t-#3Q$PS0&aln{Je~qvoe$cn4vg!+
zh+B1ZzlozvysllvJa^&bWnQl}!YpTF+V|e;d=~lSJMMM9a)W$xuk(>FzT;l!S1HWA
z*ZJ}==64;8_~-6*&OFJHb+7a7HokYS^Hp=deXsL*$9&(t&R3oDUH3YlH|5=XozKkd
z_wIE*%XYfg`TAt-zo;`WE^odBbak)uH9|jrp5ey5&X=t5&b`k6g8I|yv+s4jVvXy2
zoijX`|M7dBvt6Hm=w9dh%piP|XX*ZP1T4!4DSzF7zes-mIYKM&*YSTA)-Wp?7bwLA
zkXr>{-)v6MD<CgYKhK*gUzk|^0{_<XeF=i?!W!V8D*RK9AJzGJQTTt8z-!dtkA@FX
zsop~6q)IlQ1AvXKpX!ug8-P%q6$JVMrpPd%cAk)^l+9-krd-q&YaLifeUlVxCYZET
z^)rl701cwtxI{Ud6JY+B<Y)%Tuf+joi%E`FPR&HCdFpc{Ex~_4VX<+Sv{?q&pc2G_
z`Wtu+p5zL(|L{3#f_5t?eAxv2po-v0fmH4{|4#iqX<-9}U~`~|nmmXqs6s}-FF6MN
z$%o)TCM7PSe$_y}#zFF^zfsu#0U$O$d!SUUn_{*E)i*&+OB50xe8WyDfp>L?hXS6O
zpxUJfo2P>YsMWM!qe&z^rK;{HBYml=zkd#3wICe;kw8(k0s%G35WvC$@8r(ssJ=WF
z0K}A=za~VHARf{{g<OSPbkR`@L88`TD%WEw!#1L@BG|zqq%i~uk*fLI?Nhc08qasB
zYPriy&kWc3Bhg2*#6J64$7Oa*+2ictbUYz52KS9<)mha%{JY%$Ui$u<-@oVnccfgZ
zmagu9N0CzLKli`?8J}-C<6f9{kLgJLcxG`OH&TB7>F1xm-+oW-ow;qlrxz%F+j>tg
zu(@Tuzb1df;Csz@%iw$8YQHR>K+ZDSA0VB6+-kpS=C`f(@2Do}w>OoYcE<j(N`J}y
z*kl2g`0?q&vD9}=7>-%LIc2!Wc$zeTx917pWTQ(@zJFroa1H8e?vR1k_nPn5kTWI_
zXVAYnhxiwv5o2-GDT&@Go#qi&`r~pQQA*Xv_s%0yE%D}%<abOEAcjVKPB~e7dj`n7
zyjY@Pzr5U~SYDrafDE$}1JM7moW01N3YVbcb=o5*Bu5cb&yC0QF)1CJ6Uj)Nz`v!!
zU!VsG^bAR1-tY%KB6*{Zl;owyoMqU?av!e<J?5l?;if;2I{|6T@FToi?x)ADd^p}i
z_8s})zrXzF^KWARo!k@u5c{uGsiNqW{Z~S3)&JOkf5zu^M=%LeP^<j>6I@}2TX#>2
zdW^uHPtu;GS_QsT)cieXy3SzS#%80%csBJShxA*tJ};uw0$FHS5q!$<PkjgfR_Io%
zg;Om|W0YoHq6W3GC^*x7t!FBG=fKRT+(BB<)j$!&89R15{gp&*t0BR)7E?={qHeb)
z>MfQHJl^D|B<XUlJD$!o6gOMaV#;a}=|}=~5SZ}@!$q;LbyXT!F#(B;$pyQ1_04dC
zAcqOEpfJipY_la2W6shHk!`Ko?8Xvpmt9*czQ(aFtTyHlk>XmaLupvZwvZM=a7c^N
z*DTut<p5sTy3e&JZH=ro9UG5XZj25&WKyzR_|LUQtlM940EP(uwK@<0!LgtqfQulY
zDJ{0uqPVEl5^<j7Ft%l_IC78m*{(WiSZ-}4ij%!C9*d-4S*!7wj5gSs9`J4pA2I}2
z_6qw&-O>HxxG?J$civDLErUaABKN%rDcJLBqZHXaH82ButFQ|&SaTI_I~f=<W06j;
zZbyxQ(IHCFx;f~Sie@Y5GyCD9pmgadS~|tfkX<#9Vuex(7sIy8hL4-&#$wa%auXdX
zOY0WU5hTrr9h_?ciWXLM2eq&^-5s@jtvgzF+ti+03p9seIB(3zLbXya)Ns+n9Hw!=
zeR70v7SbR>i~M2N>{Y2ld&RDc-1I<9HuPpuQu;HiXnOjjSnhO6b-$^h+r^Hp^@h!8
zZ;NuRR)|XG*kI;JrGaj?mfh_Qtg4CIEGHb6=Cr^Lx_qtInM<>k?Y8(;FFH5}LzLCg
zx;Wm9Ol(gP%LP6e;#ILy8?{@Dh@TzM7E+zEvb~Tue$kn_I3>;(wZnv@$B5Y;3MIr*
zXWLf&;LeF5?V-w~*XtIs>VRgOxaEyGw6osKON|0~AP;8O!-upZtjNKFYiRTJOw_fh
zt+BF6Mx)MtMf2RWtgOT)Ti4gVxwg@0#5DQtBr+L<BrClZhA}<5FKzc`Jya|PTkXS1
zzuT>@E8Jr3l(t?Q2w>f*%`H6Y*cGYRwh2n^wKdJJQ1$6{vmi~e(C-E4C|rbfhFMRV
zi`BBkF!+2*2L>In_IO*Jp`6;>Et)7-z=o{`rTE6QM9vL;xgHRBnVJCdjDi-j?YVep
zYMxVS^%PQ=bSJ)`9W1xv%2A(dG|h>@jTU=s$#1H3&!{xfri<;YZNm-Oet*^n{adN)
zb5{%viLf_R*d7^ztWw5|S%&K^A<oH8TkclSsyQIBm515`wNk1brrxek(EFW_q6#r(
zkS<#e*nZd4*X}Or@5f|`Lv4k(%F|#Y=yJC{+tG)?c)*w=!7O=I2lIQQ_0UBIlH@Y$
zvE(+jak*F>Qp2InOHxp<7Q6a5h$<D6q$+BWsuH3TRyu2R8c0p~(37iOsaz^i%m5H{
zI1W{9GwIbkRJ7i-(aNNcN3~jSW7CJ7UnATu&?x*`C3tkS<>qFA=^G*_I385Is?e$L
z*=AiC<5emwc_Xe|oG-PB&$2Y$D0?OwZJLWs(4QK6Rwa3wBX>PUm=oc)SM11hs}Ti6
zYhz6@ia<s-t(3a~sWl5@1aQP+P0sd0$xv9AmK!~0wkuJ4Z=kJlRtZYJ#1Ir#Mf<{(
zl}H4|f{tq2a_F-P7=OLCIqvl~>fWhE{GyHVD_<>1b=w&<!diFVXpH^l3UlPBII*@W
z;`f3|v}(`x*1^$mrP}W84SUPBc5R@<oyozQ)7l<aN>Xdv^A(ntSytC3C2E0*4R*cg
zGlPNbFna^(2#3L_M+EW&(Kbe14@#4+&@YjI^IQVQ>z(Pea`3P^HJV#Hwe2dd*k6mK
z(t)?u^x?pwy^SmcO1Q8|&1tU;itKNhNS&2>UV9*i98mfLLDpt9K_?NTzy+mfQ<=Bq
z`O?~2;dbHGP&XK1DmQ4(795SuRWd3xWT7hik<|@1_^L{52FhkTFRL<M-zn1tJ?~lF
z=8P-!wZUSu&}geq1GQpVg_(^?^`O7t1{}&%m@!q~;|F<)O;E<0;k{X-BvlG{y<eDi
zSEZ0&Pt8^&PXs~rXao^MmR=}^SjW16Q3IQk2}T+?wO)HZnDmiCX~H$!<+6jTA=4Xy
znYAFS^ch2v1TpWg{b7xuWnVZ*wPo8}=~hYXXn-C4B3CqJrRuX(xMK-{8}+euu#gD4
z$P~I{*WtK*r)y0P-9<N)g93{x18Q893(Y#V^%||trn?kyoT#;@a=AH;R;xyNIYC*h
zJV2fL%I=bGN75&Lp;IoX=*IABGqPG(?rKV{=_|6_s}qyybSArliB%|KhK=eruDZ=i
z&7%0e-!*38X4da_ie7gTFq&n1hd~|bAT7PD*Tl{ktqV@CO)_1e1xb3uH@bqiLqe)h
zVt3tTuhv+Pi=EJ3t;l(^&es*qlm_i}XRuwj8G|YFtRvJ7x~Za~-B}z$Q&(xLF+Ctn
znOqG9Ubn=W#c<|trQU!cSIya=PAm$<KpIy}ckOpY)|bYTB%<VM%dQZb-l}Gy!E9zF
zB^c_{O>v42H%4#WH~igxtl^<kP)S8u4SLdgSF%gP`FdaT`b|}}MrKE^*u5!Yu7{;@
zv)mY?K#*4YDl8jFU1^o(vmQfq1AG=BdUJ@=Mi9s}J&1@^SOGGLPA2^k?Mwqd3OYu4
zz^-UHu%pouFO>J~Y0(%MSZm)1x(#JvZnYu;I<nm_7@KxYD45N$F4P34S=7|!bg-Ha
z2R@EY`PIbr2mH3UAC|0^w~5MVxhkU#mUPIWX=2#U^jDP)U*0WEy15cM`w7C<qzcmM
zi5;gW>zZGzg?kOPk+M3C8fwt1PVk!F9Ws5zGWC@nj(6C)vDF-OI~Li=2$kd>Q7LW;
z{9-VxTU*&#sR~--)RB7F&-psfls5jz;U)&gZ~Qtv71)_zGA!kGiH;ENXVuX`Sh}cu
zSk1LU&DRil>dw{!6nDnJ8k-MS2dUDQ^rcv|6}dyT>%&<)oU@`ot_qv7s8>1^FZN7&
z(URsqxi`C95cRrU7Da8oiu<*`w`tpK&{^8tPN2+g<d(RF)<?$OZlU5S2Z65&j=N}v
z?5qm3%cw<RUEHa*>Dj&;^-ZV2R;gjHQq(I2LZte=_Fi00*S(I8nG>22OZ`o_b9z|W
zoH0~GnHI-L@i3ch33Iz^Z33gwpRKlz-a-zWTDQO%W3eO%n$z8(y{We6Sr#9yYog}j
zW2f20JzCt!?Ut>saDkUN)*Tg9Nz`YEVkk(tyJZ-4=)1G7IPLm6XaSF{s3}ou_ncj0
zYBoj#rlXoxSsd7tYG+fb4F@b)S{zJn(kNN&Dj0<phn=|Su}gkmk$3b&3e+*VlN*ce
zE<o3%n!N&cPt8%cF6ZohSsn6~aYPKMu)lJ;)Ch~Fw$m@}wiTNgRSAddHoRHD4JyWA
zE~}-IGz_L%xl>_?>Ue+9>bn*#FWYm|Ux$<Ku5}1&V;fU=g|mIxYcGsRk7-UC%|_Fz
zjCYYjSKWcGhn_LeS3xkg$mq~V%SOYPlyH4MpI3#oLaYSW4UigJ-53nE84nstu`SFo
zW>w$K+O^I|)uzpbQNSg!tl7h<BR3^+H5MtVzCkt}bw1<@OWV{sn5)!=UTI(-IKEx!
z&&sn>Ya@i?8PymQotizxn#B@ZYBG9@qIhSxFKTQf+#9_qN49Nw>2&uBFUWeiv|(_P
z8=4Y9iDvCU4<l<?Cu($UIFXn}S=6SJJw@BQ)>fk`<i@u|rDe9rF;%vy_0XW&z-H_A
z8I5p7&Ie|zPjqXIX(#BSU}%Z<BtI`#$+o8qZD%5F`t;h6N9{w~qV+{o-tNa@kK1#)
zwIFNcxJ!yF1+|I`w<2x%%5KnQ3B!>)s4s@yPIakF!n)X%Hi6|YXp|VX#^VDU73rbS
zw#li6I;uU<(Eg~j8ikT1l<-ZncqmQWNpC$uh9RY(Gj`e@_sKr*T8HUk=2sTog0|U`
z>o9B;2M2o-wh@9{g+5nmF%ez_v#`!U>>#Qz>@*5`Knk^DFbYdlTOU__l%kuh{-}m}
zDyj~c^%_G1wSdubzdEC4QLpX~x-vnTHEq)C*flx~sWInNbafXh>?|x7n%e`V6-M>S
zcI+33xy{aJiry;7NN1}qXEJT}33=L(R|GBCgE<q4O{LonhCw9noS+Ugy({`Plq^)7
zXx6U;2u<y*2wO#{uX$xVk|kS_^b)h2%GQ|SX}-PKR0WLe?&uv>YSqz#O}Il(CmMW_
zD^;w+!kE*;TD8|Q34%TJX=J?~i~7h|4)_g2F2#NbY?W2JrdutdIA8PwaUW_FK5w$T
z&|lY)R?R9)WwSSKhT3FCGDM--TAQ2|jkIAybJTf*k&U5GYOSi<j2dl?X<^EkTn-!5
zE-2S^IXd+8d3D6KhCQc8h-`5^*iGt(#x!vDqxPiAZ8bI=V79cLE!{b<bg6Z}trFGd
z#0=Lh%8BO4axuV`Vq@50_FzUhUpKS~Q<lj2U{3nNUMtDg%F^47rUUY0ouDvj2aREy
zE_BvaO}1RNIBuwZ+1T~la|few1{pfcL_4SoA+4*NGc!oj^2-xvyeu1BYw3W-xN{3@
zV&V>!nFhs&{W`zu4_TQ57FZ|5_JPSqVYDinXt)_oqK)mEOsn19b2F@EmRrt3FROKK
zTrcD5u-x45OwXKcNl#*$;hZZ=_BgCBjlEJIktjhB!^qRs>a@Z4bwaVU$w(aYo1Ihx
zT61A6+Pu*R+3koDiGn;@5;QWb?xe=VADecwSZ)eK%SFn%Gall)(Zlw=n%taqfWq#|
zJ&dd#Y`TA-M{Qbjuzoubo0BMTLJb+tbgsF_dtxAuwQ#o$2AxiHuxAqP^wxOq5OJ0L
zy4D_(p+;lm9u!^-=7YmwhGA25J(>4Z-!V{6Z;#xG)SL18ra<a5zfa4wR8tyV**UCN
zhZ#TUO=pJCTX8cwoL1e&h{EO4gr9Y)J!_;ItrF5&*B9iv(VULuHPTe~E2dJ~5@=U6
z*t)sE7lrYx6wNuJwdzk~w^EgfO27~TiVnA{rM5*^v!Kgr&TQ8X59`HfA$lq^Akg*#
znRa|%LOHtAZa3@P9&4I(zb#ZGd?}4PD^4e(0Y@P#zuDOXyR2#IB5QlpG7zlQuxS>g
zmR#;j@=D(6PUtk5(t1U#7MlhsY{`WskW)`lXk{01Twg)=Rl1=Lq)}9z16Crv6)TJ@
zZJaMfz60#5K4WZJ1$>6d&59i@n(Gj?do!bN$WE_bCAP!B#KT6f<;{?W=Z{^C&<uK9
zclC0|E(jVziukl#BUnz`N|f$2^eUkG#@JN0qbbI<2|etP9a?o*)0h@p3t}`Lv1Sx7
zJ)+$Wr(>Z{xs&cFAP1OGmk$EP%`v>Ai`Y_i7KKnNn}&!-%Yhtm!+J!wC`B6e`aH+T
zjcTXe1H#j9`3@M{TZPF?LrNB6Qmw9|nRIn!j>&n8cBoxrN3W(5UTDqq8MdE{y6vIN
zuiFFO?c$Pw)Ovy26tp1XR_p235eafZaI{EuYKT7-w{4zVcidUHFk1z~5SUfl(@Jf&
z*Isp8cA;9$xm;#ussb#birL(VRl*-zOh5p;Oeu(iDMoiHR0%H=!Dh#?jI^dUgRwx>
zC@?PrrTUm=MMR4two|7XR8?WH9bzq`YY)N&s+ah#)TX&9=Z{4MjI@Wow(E^OVIKC^
zT`E#_0_{|d%|R5}2DjbmNO^1%f;4n06L(osB|~;gn6j$Qc!ZdDDU@4>c$s$%mTHw4
zf}0*%#ahsv80}ig<7uY9=X-sdUTin&T-r)#+vv@823vZ%U*Ax?H>glfe@(94xx1K+
z1rrlFon$(aRAeh+ML<UT@c>MuS)}F6*Trg3-)orXwYX3~sZPD9Aa$g@8V@#Orn|x^
zFPaYPqhMVwq9u1xsg(LkSVA|$s;x0SprSFPXHt<PAi7I%GUjkBM$%oZif^LQ#y#k$
ztPd^0pKZHS(;(XQh1Kc{nl2!PErB;`V7}{g7viS2CI#QFI}9@^01j+8A*(x1zem%Y
zUXBQ9G;4Kz&z~$BBo%-fjXl|DXbjq(S7vM3Hx*pj+UNqqY;;)YTU}@9wJ{b8%hKL&
z1d7o*1oV(xDYCLy*2f#1z@|fsrZ9tTO`1go({X_@q#31~<<(FeGgYiqC%S{Gig^;v
z_<N4_88fIeo`z7P&=1RNTE{0`6c!L>(Vy_t)bWCHnNz)`g{ze%QF4_-btP2Eu;gur
z!XT8I+d-cYyrDf9usuQ^>jZ;z+X7bJPZ?YjbW^d~yuRia_?~FiEuVB*rd^Phs}KdI
z6tK#Nq$&^8?QlsdWr?i=%`;HV!BU}WB^Tib=DuAo&or?vf(~L=vay)jh7;L9k~;#h
zycsYV+|&m0h!h;BU5U&hv#+oD0kdSLJ_?5E(X{UG1*6-v@l818dR~{I`)FgcsZK@?
zGU`{rgv4wKY-vdD2jafX&&I6*F>~6?NGbY)xHiVE5+UFPhKuk(TT0vhp+xCQbIk2Y
zl4S`_3+RzE-!u`wO;!wGFG*}`(<249P4{RK?X{v7-|`n6X_EGKN$3t+mFjM_zyo`8
zGs9GecWd5&DUOXPu+mnM+&TzmvE}m>s@U~+vt<c&MgzMk6uOIU`*1i&QBAi=WgU85
z*IWsch$k1TesjGPdz((Dv}BhvwV({fJA7tR=G->971}9z`_R*eLog+huvVm(X$Eg^
z4ogjv=L>z$%k65{STl-T(Wab+@P^lK%Mm_kwcCP-%*k%(aJ17n$g7?QY_%@k*0g>k
zP<mMb7Kb&S`5VFqlZyb%qNh%?wc*yNXn|?6$grCkRmFLNr)8yB=WL-qa3+0wzL`yN
zZI4%RecIC*e&5_y=_)s!8Z)ypWs63q+}p98eT_E@!}0(O7xQUPq`U1!9jkVzsL@h)
zTVR|vR~4e{3=je_+T;x1(-Wa(nnrg+uP5Y`<lV(&()8Slxk31~W7jpk)>Ij!?y?r;
zjYvCmRs&#mF9<>I4@Sn+9a;R^K>FIiS<w6O1`w>lMOB*~l^E^7jYV<O@2C=sAgtG}
zb{dvb=2jc3OHBk}HSLf3W;kh=qh^G<t1edaS|v>0bp-j)5{CA;-PUofink+bh1vdS
zLUr^pO=!wQUXVh!5%iEbHtS96%N2tf5ttkMcx%}whC>4|?<kTFi|(jAv+6(!3ybZV
z4&`7}HxPO>DTRXxt8mrbe!d5?hja`fa;XkxG~7nD0V>`P4OJ+3*ksH!2AjsFFAtnn
zVXcwN8eXP3p5Z1-a_Txp-zu#Q9_>2VYBW&z3L;U$s=lNudW-2gYLn3-&k(mww@?66
zea*m3d?By5ChgV?x*J;Nyd2J^U8~ibbQ>Z&9&xJeFvF2F!DQ7t@KU$kYfpHLoChX3
zZ1-xKzaIAcx`yvNS}P)p?Hb=Q8kJh$7N^X#6*AsIV5my7)>@Sa*7wRZ;40D|qc$Mk
z$O4)SsCAyeafYZXtk9kmwgp3}C=uuYR2bnv<i}ix7nh^{yo*oAy9vGJ<Oxet#LyaW
zY^6Ax){TNDmIlZH-w_ARbt1!{>pV{)(F`jLR??Csq#-sKSBevl>?nRK9F?5eVA*EG
z-eMGu$31^pvlN%_5|h3*v?&6$*E6lHc&yc&dHh`K?N`#oVZhwhTH(OXYZNsum@&3$
zpmdSy)@qeTt+8_o-5R@gxw_Ge%(1GEQDfu}+ip}*z&wDpwMJw~GBa_?)<G|=+g4N-
zBxO<I)&*_RHrAU8?-BcT2b()WNsTs?!gp;J*jp5{(ola$Zu^x;Lj=nu7+}$23&t6^
zh5l;g)}w70VIDoz*OW6F4Vi;&cYAol*6M3P#wt9~n(8#y<A$7v7Y2gZGDFrM95{~)
zyX{(QX9l6J5oEvY;)1ykfOaZVLgdwTO)XXxHDJklgn)UaYjJ*~#scB>df2$!nJ6yj
zAS`2VJ958gO@z{1U6<9?VGt_SmUyUnLw=wd_y)Jv3t+b5xI#KKDX;{kt9x|T^7xh5
z=fv*DLi_b<FVgq5^|ZIc+@QB2J3?n_O&ou++jAnKjd{*-IELFeQ!qp3oRKzZ<Gad)
zp?Sxv(hHKL-Kw;iupLhk+0d1IV#X*`N1PK}CG3x9D?zREPDDp*M`}BiVBto6ENrU*
zr?^U}u93xr=e9Gf*E2^pg>fO6oHtdQmlmtCjkbDnnXD}q24-#OJ+;+G1byJ?R!7;Z
z<z0n{LjBNN;9W@SsZ%2?h7*F7P--iMK?Py>O?TC$#<MYplI_lHHR;R{hd4}t0W-6-
z)pF-B0pqjOv`ug3y?~yC>>lHBnj8#iHr%WAL8YqG%$(o}3TKBE(iMy$O7X&|Ws4NY
z%zZF1rzdztGFz+>w3iOBYrz1?3iP~gtvLyA5g5JiuiJW?Ll};4WB3ARz@(^&No%%i
z>_c;oaY2nb)OepRk4B8X*GuMfNEzHNSYd+Tb=iX~l3*~Lju?u^O>)!nt84F22gIu(
zJA75=r*lol3!uB^6>T^PHU|ptTRpnMwaK2**DQB36C$Roa!$X^_@;p4cq`QP(SD?q
z+LobnMYQdUBX&VgL|*Qw{oZP(EE(AfkpSb6brcwgX{nXwZci|6k{C>!wYRD}d#zjT
z&}&-My)hp2^v<C!kOP<9j)`e!+2V*!(;loP0Vnm{wjXNi?yOKjN^G}XBn1;~1z~5j
z@~N$S7>7h@i%9~%?`w-%!16wCFrL4_NkVIM96>0ToXWVxXoxcac9=}8dq$=2l=)7(
z%G*GR>c(~vloef=w0BaMXZEYnOdSYQVJ!8@F;=Pc7sa-qHf^p)jtX6}bHE$j0k1UO
zbvdAEb*J&JD=Y$9J8X5t?pImP=#z^UPXj|*)3q6elq*|&EZXa;NJZ?(AXti_x*>1t
zT3HBoNVQR^=<{*^Fltbki>%yYXBTMOg)%HnTyYaEZ22(7qk&WEc~nqAvAQuLL{kzy
zK>+g|2B9Oywno^ZHlmv=(pYlK#m-<jk(Rj;n5kFTeUIFdOV4mQb&vQ>ywvRy^j<PY
zq7)9x)k4RrTaBVa&4KAyr`*wOMV8SSBm0P}1gkO0M{AGW$o2ZtbbafvrK0}6(ruK@
zzC<hz#Bw=v%7SYW`!QSOsR~*elVx$ph|YRi3Z~>_7P{1w?v$;r>h=L6Hr&Y(Wa>?K
z8=|o;5S6B(9;!90ai~yAe=-|~?fP!yEV`Pd@U=?QZ<giB2AF;3gk!rJ(&b&1!n$j1
zgEI|d$_~nHkK@qwj!^`pJqx?!RGGKUp6lx<rO))5Hk|bdrMeqZqj{Od8$HW3G?c>}
z990z&Atze1KMxR><OPFnmF$7g3ieZKPKZNM6s&Hy?Fj4ym~2h8TSZ2U4{~Cdg{ZXL
zH}$EvM8x)#>sES}P;F~_569eST%XqP16QgQ`!nq@aU08ap<Y#0)#<7Rrx)mD6CFA0
zgTc`yyfs8ym4Q6nMXiEaad_2ejKvXEgey*RIIA$~xT+YVdTY2X^=m~ua4lm)gt$uD
zC6?@SfMxhumt!@u#4NBL!<k^hiM1@w>g>xJ+v%Ig*4Us^c33yvt)Vy6qFC4uwPh=m
zc}A-bicw({*pnI65XT%sP>S0o1WoJp+dSoarY&NkWq|2EU|GsC@RjG{HPc4M{2p0U
z!JMhLS8Ksyfl)wPEsPqyU3W**b%SOPeSKn-*Mign_L)rk{$@ImfHC2%!nTZHr8VYp
z!%mBxcTqt!mH`69wqyJK@_r$XF}!4LD&o4}j9Nr<hgW<&EFV^(NtR1efoE&&aupY%
z>7-vLXo|ytNkPn3?A8#K<rMR<wlMK`bzBKZ->n$aQLk0PkrFb&5ff!et|!S$#RIye
zjWM&{q*Q3GM?BMK_SSeP)F!lWs1o#I<d671IdYae-;$%MO9?Kq-x!WGz`#7r-4WGj
zz9mC0tgm>xTnLRJiFdj{EgJrK&1{0=SSqw<0kxI3!m4aoNR<bcT6v9z^eh}Gy}@Rr
z(EOSym^F@88Hb&<b!j53277MJRdlM$a(fZOm@a7w!Tg}ffh>=hg>2x)V7f7IT@_k;
zmFuq7qk%+~THf-oXzNke*7iOzSXA5y@6!!TXs*gu8R0ut#q2pEFt;b`!LaW)No9aj
zq3AZOXsalDx6~2%@*1)FLzV2(a^0e^Lv^#Dn>sD+dL3U<)`hVbsBEFEVr7Ev5VW!+
zRv5)0;ilE|45ZdxqXJ@U^VPN-1XhhAkn&)#HR@P2!$rSJEt;El*`6$V{RJ&G1u*cB
zJ4U@a**BLaPPO+M(<i2CdpemAJyJJ%p6d=Uwc@T6rnhM!Q*t(IH}TNyRkbZjv&DHy
z)-iIA^+W?l6=zM+e!IC?PFMq{@ivcj5y8V&R9{2Gh?_1HYt+T2R7)##rxMW|b|X#O
zXf)nw4?E6aMMqQKP(^e_n)awuZ_rw|Mbpay-9s9Ihf?m?P<IC&>0+FtDAV?&h&H+-
zD!>;$0S4Um!krPLQaJ0k7WKN0TdOH&V(q95x@rVQf!PL`i^Rx{oI%*xg&Ye|bXLs7
z4q6L7(0CGz@l2nsb@n1^N$rKj(BTO4Ds8@F20d;)@RsAK4e%$1qYjDoScfHd6jc>F
zWH4$k2x%;+tB%WH9l<h#R((3RheSllO~-Otn${&4K4Kkf%iw6CU0(9r{={0FT)&{9
zI3Pq5uM+&h;Ze|itlW1h)I!rVdE)d(W35wdttb4brR|rr!VhFS!nARd@9gc7ia0d0
zXzd2;ZAkO<bkZGFP-Zym4FjnXN~LjaUIx>s3fl)Z)qdv5T)>Zr&3dyor#QiOTg-mf
z<7(<;H5s)x;}PZvRAUqI%T|fu7~HXz18&`0fthn*4YYyBH!v;I-MLIuyiK^C(=%h%
zoDl7eh_2_W@r+W$ax`PMZm-ZExRPYd9lwu9_;`3QTw2o5UdQCR8n?0r<wLOLsn&W>
zUo3IKIMgso88e1Es{^Up5KDCw9!w1B&JCI@*{h+<bECetY7sh#>9w&=Xp2RmQ(j4n
z0y%H(-L0g}tksHMT1=~@bRw(7&=b%%U2bO7r~1KdJ6g?zJ6uAWh=AJWR$5;V=#@wh
z1fY$<Ks=vWjZswG&*x348O+x@Nv};NiV&qi4kim}Y&Y%lVP5Nif0R}%^tPj}+$A+2
zmMv3ze!hQz9>%}q@YoGo$w~X1yN`XH4b{u#k0G=*Bha@JjH*{Of%0{h%i?RchySte
z$=~b$dpfJ|qldq~eg3OdL+V%lzeu%S`H%napXmR4b_K-GKg9<M{I#iyUVH};JaKb6
zMG(jTNY0{M<xEbdz$?>K^O*bk6wp->ONCJ;POvRiv|s$qR)p7f#h0o+=DbpJZCQM_
zDB}Y~_Y_+Teag*XoRFNDTW;+*HuuFTt@K(-QHHmgz+n9FWfH7EIeh}(*=m?ej&%K!
zM8P@5+*OlX(*2yYjjw`n;2i<5y7;QGr&|cZLopX;!K^*}dN`dA84rlT$K;Oi`06T%
zHoO`!Nl!z$!xJg#fe(0xU3?o^4Cm~e)@#=FmpHH}d^{cny9hxAU&gUW3@F|)S}(`*
zGWjEB#{ehs9SAZ0F=1Y5D~l)kro_BUPjwtm<CWqAd6h300DEy)i2ldB$DH{HZ!wEO
zD7iEYYaGP%j9%vP49GVbp!D%A10;R!sve9u>*vfj=gXWVta5t9Om~uNM^na6FCq11
z!`;8v!B@w#QVPx=;pJs#GLuhw;bs1koTP#Aa(c($Gsh}l`+g5YCED(j2Uygx;x9YD
zfAWokntRCo3Qwq^mt52~g19TL8<~hD<n*``;`-#Xvs`Jn8Fnhb&u?Tm|8SM(X=w!c
z`D1SXaM8QxC&b`=tgw?$MPQXL50@z8$$7dMC3wy(ZhtPHc1z%ih8=f-nqJwLG{8tt
zF74s9lS*=N*=s%NyZk(@3-r92#(VZR9uUDdswTgGe1-M!aM`99EyIV52>?BO&#|v;
z$x71RoaOtsAOB&nB5#}C*7?Vt|E?gV<or*iUar(jHF*BJQbztW{{M;NzXRm|7<5pL
zg3uG);|Q@lUg32)D4araAM-!KKY9NVjG0QHKcfipkf?14B*+A^yn~n7{O*5+A*o^3
z_|DtAyPtm=!}FHL`IS7!`+fo^XP74FwfG+4%Ujb#IDqU^$$QK#;Z<vZW4C^KP0rK*
z*WR~4IdWA8_82c=MH<3loF!&SjV2RGJyNOFJv}{^BahoNJu{8RGvk@@FYS)HS}IB9
zmQ-q$)IIWeAkIR_0!wo8W$`&?S(A{pAsY;2_bjl4&pMohfLVhRPB_LJFveiaFV5Pq
zz~0Y$uU?f(-8~<VS&+`@(^A#@-gobP_uY3t#?^Mo>UzSTlhW}lb)9-S<7laWMq}Yv
ze3VqJ?kwB&9&VpbncP4rlo)RR8IgU*^ON|9q<vkeC&!O_<&rJ3I9r`O%~Jt)G`6Oq
zzXhVtY4IZj5Gl3eXiVFj{oFwqqZzo6r-u_{$V33+1Z@GBJy0Z0(pz$1cZOcDG9{gc
zaUm;%0z3e*keIUrc%Dp-S0)Bs#xT<H5X*>ba*7P7hT+P~{#>X-ZC>PXtDih5p}2g3
zc@HSAo24gzvc>eSp!b*#e9f-Ism(^r!FYxS)}Tb%6xL5vAt<CtuxmTjT8AP9LP^Zn
z;$X%u7vr`yY=K<p<P3P%XyC>KoAxpc0g%!N%sFy8nj<C6D6nEysnfM&jxaGD(UWP+
zU{al$E#BhHY|C>9C9N{0*N_>q1gQ|(imZSj#uC1A3LZGva_%i^Mx<Hqm1<VIkv1@|
z2+$D_vcP<q6hkyCGw6tHLL_ULMqsk8QFZ}bX$H7OP;`;DuzV>Z;T5%qkTGx*)!y;g
zY_n<-Itmh~BuZr?ehLxsbUYCthGuxUm=Deas0ONw5VxVlNCXxPa7|6$&)nt<Aed&U
zfpPvgtT%y^Dv0RRureG2k<!a^xOa>;h~+$xGV5guPMF&*8^E}Mu;}!FqbZukk!HzO
z3stjPfHCS!qQV%;8Fzrw*zF8p3}P!yKflqml{4?)$*c1Z%BF~w2nePX4bC+HH0503
zu!o%0vW0RyzzQ(6hrn`LU6Ftkk2?|!$X+No{u;)nAgFLgE}#eQS;pX{J^%sjKH}1G
zo}#K&Wv+RP6K#?VyMywh5a;tBW|%N_LKIPaB@N<?Y2_tJ;2z@mq~OPX6^vh`ibD=w
z)|Vi`UhU%|KxZ+x8zXGyc5_I9z9rz44NTTD0D)Dfd>;;H+0u}Sqga}T$ml0VK_N*4
zbK?LDlp0Lnoru&)Fde$Y5B>im<bR2`>*cCGOZk6%YJ6u%|2MUBXKpC}Ux?2Srf<9H
zS4T!J{>nq|+ker>)-9L9vrhKWyC2yywdJCPk*l`6sAXJt@7B?~SME6Wg-;ifKmVm~
z9DLPy>8~HW;_dI8TD#)XXTJC7bbjAw^Dlnww|?fKcT`S2ct^$l*b{e*ANca2Cl9=9
zE&ck@AFbZs{NV8$Q=fVMi{5thnfJYN*MI(n`u-Q+wd0Szde;L#9IyZH<)3-M)~|o+
zl1H|@@#fbX_x+p1M{axcZ;l&lKdS!Xqj%qM+1O(7w$HrxAAa+<|FCu6V{d%;(d~b8
zMeDMgzWbe*UhM4p;7higzUytxZ@;eg(m#I9H+LMm|BLs&@YHX;Hv6q3@BQB2z5lD<
z%3M>sZ2SY?d5f30<}=B!e(d2Vul>vCpZ;8T=`A0=_e1}<d-k50KREKjr>4I6XV3i4
zJ0?H+;eT=Q{GAWp`>HP-`NVJSz3&(P*V7;R{Wm@{M(cR*+(#dM?BJjO{>YZQF8Yg$
zMn?W*s{F_A`FQpF7val`Z~oPv9{SHcJM=#lLI2Z3`hRZee|bxq=->Ox)pvaSf$w*7
zt(V^Sn_vF#|K-@%@BHZPpZ<@3_lghQ{HFK*t1I7d`li1y^53{~YVr2fho5-j&9{Ew
z-!-@1`S8pCe)XT9_qy-jGjqkRZ{5EAuJ?OO|NbkV%l^|9hfYr$Pfh;G4aFB7`m2MB
zcRuo|Kl{B0{&w-3FZ|K#KH{v6{ov#GkL~_X?|sROzEb<)Eiava=ihJr_(=A$mrOtT
z_Qjul%6j+LzH!O7-~3-cf7#34^RD~<!_PkRr|<gG?>650!rtYNFF*Z%wwA8A@5`_F
z{uQ5wQ|@KA|3>zCzp-oQ)=&Q2>+imN%hfMVUi{flzU8{5&;Rp7|Mtpn|LyAAN8a?F
z7k%-uKmFS0f9HE2_~H$p@!qlfgV!%Vb<ZC?{)P0XuXeUx`sCxcz2cKMZMpi_pZU2{
zU)cWgi+^$X;EWUdwJ(od`lkDTc+&?zH}MAJmmd1cTi+jlr2COa>wCOkd%<HbpB%}&
z@2&6K|H{RmAKCJWi=F`H@P^#;{^7@+Pn;S3PdqF1KRGepNB@&U`hRZef8;wOZzlS`
z{WU8uyEA{+)315KE3;cKy>#@+|NENQo1dDS`R<>;>Ptr+c%%2sgTMXMBY*vkEl=)y
z!L3gp`~2wsEjM2B)a(A`4_^JUTkk2n>Y>*5=bt+E^dDX_lDPDLT=H)BQ_uYC)emR?
z>P@eGeCMm*_D>flp7`d>SGU_&KmJT-Y1IAtXTNs)^zS_K*d4$0>i?E_=jnHT^XrK>
zZ2iP7(-&RzgT(5?|A^y#;1Blx=p`cuJ}|Q7o-N<qGBR@KEAD>qCuJ}Gai;$w(74kn
z7SH1Pe?$7m@1gtuo#R9O|8uhb*UlWC+dq5!gy}TTTOS*(KP<ak|A~oRu>QHp$?0MI
zw+nOsBLZBG;RZe$YuhCteP`9q$QS+%%fKRoQhbc9Clm}nKbG`=^qK>ixx@R9oX<Ws
zqW_(fyA=ITjZXpnPfQQ>KNse6t=+NE>?Csoo8IJ&oH;%kJ8U)Vyifb1G4-0zWHffX
z+h|zrUf!57>UdwaX49>i2;QnG#0^S_PPb5W)r!_O*e<HnM`H)w240_5p)+Y{S+|yC
z?qajt>6+!`Y^PhZv)W*0x}BQa&KoDXwsFvI*R8I6ma!X_Q_mY%<0`H_8aw2a?4}1@
z%(Sdh4eIZ+`L=*2bp7FL4j;Mk@M!F4-Rhu;koM@OkN%I%&g{E()@+n782wL7PAdCP
zI0^2W#Qi@vF*&6F3-Q@zT<_D>Xl&N<dYO)!>0)j-Tl`?U6$!(9%JwJ+dzilQx)w;B
zZyG&C>KsPg_OO$TksBZ1ZXBf|`17!fH&hj;+HEt>z-u+Al;N1zP1`Q>bs}E7p+SPZ
zYS-NsR>c9!H+UN-7?77Y*xDdt9K#z-zPd$w50T(a-h_%fY+3lYZ40{&PSf3J*kw%6
zR`01I*K@KsJ&|0XWx91E+ekepoY8cRw&N}1wVPEcIXFlMulniA7HZ;TX8c>`wz4!3
zfHOQ7Zyf3N(P?(<D&B2+Xxvce4%E#)&Ihlh=l0DSY&2=iVXC=0-@J~-)QU@+6o+3U
zjB9PTTdf%_rzNi5M`MeNi=#1oAc`4Pr?bQJYHSpL75r_;vdt=5>rq4g)v|0(%Q>-;
zQOz71Ev#8hG6d?jxE{>HrE6q=mI!CnaQ?ha!pLMqr=rQZuo;Ebv;ddO){a%DO~xE{
z6TZ1kG#sX)2y;0IGF}la32Pmz)S>9`MxzHcM`P5OK5AT>^SB-}^^V<c0?dG<dTB<w
z9+4B2$&~Q2S>A#R%^xFJxvVW5tOYHcpeiz8Le#qv?J*>L%5-n7U04I=k=Y8Gbg}JO
z--?Bwi^qV{C(xo2;OzuZd(Nm?t7J2?>LAb1?8o5Qt!VGV=D@xU8Q-Im*-6E=I^DJ{
z7#k)o$cUSBXbSj5Q&1N-A!aceBj%^Gif+qo1_mZ94unaWZU}~^u4f?oWHZ@L+qSa}
z%Y$Vbq^$uebCu<WvTLh2Z4V_hG?lV^21u4Uib4cW7Nn|K)1V=oc)ppuj=CXKALX<C
zjN8nB7={)jdST+?Xj&tfIw4*UW{c^OojP#kvO+g_-_D>F7pB<^lD|ShK$TgsWg&GM
zGIPQ~VOEBQ6iaPN=umdoDC@OrjE!+IZ*0s230G`=WG`59fl-zui}6!T2+soCG@4}x
zun%Y-P=WT5GTU(2AbqMDfKNTdGqTBdnyYRd@U{WFiGxt2UBHCh4Qlwkqm2w%zW{Bn
zqG1(`VbyLU{_=i>QQAquwhR`?kp!?rm55kbEcu&E3pbZCKxz(P)<))o$wVcXr1=}|
zTDUF4_6}0NL>}7ec;Ya$o@5??GQg_QRm5HP$ZnF&SCSoxmGHwAyuR+1EF`~D%|Z51
z0r2AD*X$rxI89*;XRneCqsMEI3L<XUpvy;O9_wQ0{USp3)-D<MsM)1quWn{kR*Q1q
zG?9Rt)~Zt_>msyw#I0BIf3*>7ra-vXf|JlRq)lTQr5Rx9^d6T{IxPqTP9e-NQ^O3n
z9UDN4A`Mx@D<dCHA>v7D7Wstbm_bAcwFf_(wzN|dxPx>@7>dY|N75nK9Y=m4gu3yG
zY;GbuF+MSF<aXw#rt{;wKxFi(E0oR=+wfg;@<uqz(`c-4o<E~8%p|>%GjplFv{B|6
ze~!)^KdxGwNJVE+I?EOnT%hT5`505#sQ{cO^2TN|C_QVipFr4$lLVa;>?aWRGXK!o
zLn;dP6Xyc?++;R4iLl@AG##&othS@k#Zi<&5c+}K@F3><A2?3nM_av>oWU!qjnR-j
zoxnuh(u6v<JDb}b-P&l3OaKEX6yhLgq}_u937KgEdN?RV5cfxULHv$RkuAjlN{l@k
zyYk8_qpe73BT)vUQf6Y~*tXU5?HEnLUp6*y_3c|NUsgpX-O0!ksxW+|ioy`I#0Q$i
z$Wbo({B1pxSY2>|F?jyOgb6Itm9#VU$jBZynRRVE7qxAHY%@_@C{g_=gW{^&G3Ald
zw*l>FDaVDBv(31%)*~R2lwfq$TmcGi5AT4mM|k88*F!VbF1hSs2J*7iF0+Lzm*;7r
z+^-g5(T5z!lduVSlspSXC*@Ef4b!D???T-rn=OA~ytFH_(XiFg0O>T)LZ9(dGZ@y-
z$ZRm~Njq_Es30O8w3{fgtRWypt}d9la3l;E@On}n+&^<29Og41<z3sOy`B#-(q3E`
z(d%;-uTbj3^Jt}F)5aOLq#YZB{n9~%rat`@kU-I80FMoG%P{zkzdC3%49pv(sFK~r
zvhb}_v-s#pKx&8+Z&HHDs;8t)eI$gAG6ln;bx}lg6^*b2*li&Nm8C4>D6a!Jnl;dE
zlKdZFkZh@s#@SxCMTy`^B_cqH*e69)K&-{FbxlPU36J*}#~ChjY_iQ3%pef$K}a5U
zHBt#!Fawfg#4$-=u4Hq>yU1q;t?i)*`u7=D6{~jo^amlT0@@>?ofpJE-3m>FKL$*!
zR_W@}8o9~1<fZ5azydRCpjmqx4dSuy2I<M6)8;ZvyHpcF2Lu_-k;jD17?|*F^Tmo~
z{mgR+A!1AdwUD>tff`2%r~_i+)wt5ELE~cydONZFj%seesib4tW?H&}kgo>x+u)+;
z*G2v{Y~$V|ah|35s?}ZsfTYqw!bE3EkI_`L)v%TcN&Cq-&5f~d3i20=4utNKwdB;D
zjygnC;IM~lgkrL31VJjH$FL--z<~;|E$Z?;+xyRXyv&xuYmdlOQ*JQx65He&Z;`a$
z*k!`T{k9DY4#!m-6!w-~0+L<U4f8!Xzu_5>IX6KHz~OWVUxa@Mo;cmE^g3#zW=r{e
zlb=Wh&R}VnTN`t4HS8v14V_VN8w^ek58{OKsOv-Om8@7P0|f;AKBdgxL4tQHLT@8|
zj1EfQA5XEd#lFo`ZLyLbP*>7oXA8l215i~$gkV9`W#1|x#dce?RbX;NvEsO~?W4&c
zaVhf70)ojC5U(5_WO<)sr39cLEFR)ri1#{8#(t8Emn2+JrP@S|k#ZZCN-x1GyLhq|
ztXtdt)e$T(AJJul`S+5|wQ<+3*`;McH4^xeT`k!-BR)I_9Ac#EhKS0CAl36wZ{P_<
zkKHagp6$sE9J;O}5Pbh2e_xPlFgTyX8G&}`Y||+bcB4NTlAJ;Ycgb0WLpQYNb1-t!
zaY^mn5jTBn#QU|e*>=N|7$~-W9s?4$C)}c}4!K38kx)=U1VF42uVL+;bPjV_KO6wF
zj@)a+eLN7D_^@h{?%U_VmtVe}Vb|zs8w3%c@5;mg>L70tLsZ+E#hcOzQ3^ZpZ$4a<
z2#^k{cn}Bb<3nzxZl81nTSL^bG5!ENmt&P16z+5Ek7_%(?0MkKDcbw++z^UpL18M=
zPy&ijLkc{?v0nm=RRK^A3Zm;Ga?L7?tqoF4nRy2k^aQDCati`sj8=I}4l&RqYZqX_
zVE5o5kfbX8tymATDEye<q!dprW{BTV@C>NeY&P8za-oo9C*@CKous<$v@J0$)j*o`
zFF~mj8^8ri`)CbZ07$x>fx2A>PYkB9pLQ~o<w@33Y>75D0Z0l302`X;(T)#OM<?E%
zkyK8P{dkxnT_tdjHi^?}d6}U7MHVdW2y8m+;K!IjBp}3swgc>e{7fBxLshdBO(CK&
zVkjYKspr#OTE&v+^jczngNC?<BZIAg2*eN}wP};Jev7D<A*C3K6G}>@>n(9mTEz20
z+v+Vcmw`GR5Zi33<V(hcU9vqNz4cvh$%f6=aY=k;wvb1ZXXor@m4y}@h9%IUtg141
z@#P-8JQV2A(CGd|SQy}3!i)g8s9X;^Gf@-+tnzGITjdTP`cPNflb~)hvykAiPofVo
z>RgE?6u*GFO7F>h!`0X~@6evpRuzL%2>JG{Sv`G2Oox1b)zS-4BOgL^3vIwO6Y|mp
zSyv-_SSxQCPUN)90Dd$Dw$|V<n88YAQ^67T0rcmcQ{eH(41f``gBREw_ZUao!F`qM
zNFIu31Ue`9M<~TzS}amqt3c55eh4Kf;xcqeZ2KHv7hfbwh~fF9*wI~b>7_?Ui(c?9
zhEM^$)Zx@Guw8T1&SY>9q!5rEmLAUnK#AilD|gVrA`|YItFBX)sOPe#To9a+`NUa4
zvbezcRGy`Mf;SCg!?lv!nOH@mr^FhuXdpkT?Ty75|H{d~H6$8RLLYhu+jV;t4^x^@
zWg3Sxe!6%aYV9QHDTzsLXNw?46#4MHs4?$A8RA}Er%g<u<3bI@SxfhZ*NC3?F(PLM
zsfew!DAX^)rxq6;4iasYtDR0LZUXYWJ}+6s<aU$zhUJC)Yo!i{V0g1F#)Go!QOxyS
z>SaB&nnZ4|9b@3U37brrMJ^7aWH&+1we3M@lwBOtr@<GMB*RXQV}5R62p*ksc^VZP
zI)uZSN0*vpQ{c*=0et60-u{R%6ik7|^Oo)66%;%q-ijwwfg4u9;X4A$#U9|4Fbb8B
zB=y|{xAGEQa0Lfvl7#{kCMl4|A$18<J=$hM9q8fQ1sK;RDwaws&z6VZru2;tC>5nE
zH-!ul!9AAY=x368mF-k;mBfWIU&`aI8rl$m=R1UpwBz%Xfe&zx;_xU{8Co<Eq!EhD
z;g7DT2LKZe_R{1-;&N6BD||kXwh<2Ff?x@9U~_>RVE<NJfQY0dmKWeFAL6y^dEVQC
zxBN5&84y9CAR+633*p6#vftntjg2+ku`w}zZo&<X+(>qtbSxoBNQzuEN<T6LflO;9
zWg5p_B+a^u*Kj<QW!rAaJ%U$I^yqK7cxP((<2JP625l886z4)B#y;2fd>ATQ3{>BG
ztsb_NwL2wqk3j{A#WWfKOJoy5@c}5fgr+W8II2P0z_Qz`a0F8r<J;+==s;v31!fpO
zg`x4|odn0usysM}xHeNCP%{jTj{qcP_Gsh5_4KkN<|s*FjRL6k@k}}<NTT2~5|M_`
zH+g~)wZ+{eH5a55pDSyDOK`G6LrF}ygkb<>tOexKu)CJJo>1+n%YNCb7}d~_`#jly
zdT_pMnWakg0@{C%PfdjEzbAK24gLQv$Y<WJR*NXTEsVxGR<+2so&|${(XBwi7)Pcz
zq?Ml@`acUNzq6-*pmyc|Ke2OSoczD0hW;NH<ip{3anU=jTUU{I=?O+wrT3bJF25E^
z1}q@;4Fw~P7?g_(`@p_B#iA%$ETVL#nxL+dY+a3qsX{_kO{Dp;C|eN!#Zze@T$tBu
z7>NObXktOs>$dBK#HKAS<rwPhL{dnw6G<X148kq)J1Hc5Uldt`-xSFsrI64(Qe=U$
z?}h@+o`WBaY)}ZH#kRfD1xXMgbF0(5)tW%CbgU(ey+t4r@s|l&FnKf+Dz-o<tm9h=
zr)}~^y(l1!+ksWsZ`D0p6$!jLm4NE=3G(|(ESyenOPotMk#*K`Q{e~_snambVMwbp
z;{U$d=lt^j>FMds_<u|JZx{OiObz+}bGZJx+V5HR|C*Na|K!eHlj#4oD>psd|1Zdg
zqR^sO2|9F`#xMUextO4?0-aqNM*Ik?<KyyGtLxS9yK#P<X+~ol4;MuTQ;G~F+-Zxb
zB?x$eu<K}4<^nC6F}36<&ywS$Kb||H%6L6L<gstl?>`gaVR2-Q9%~j0M%`*Gl`Z3B
zo?^1&!{o^nZi8aS#Y>Zh*KGuf!fz-AFDiA{ZHHT-hxA?q<VSI+Sa#aQrCyP==E=Qj
z)KL|+sJo<eE*N{wA{QwZO&N<^Zp^ZZ7E+kPHOuE|YD7h1cPgYNl0_X41O0}(-A1ZW
zD1-Vac<%Wn0x1T9ec;Sk{eRFYgH)53(oe;xIb}PEem1E<5(8=kqvKPYb#1+5Lx)^6
zZb`aJ=+TqX8kAv5s8Q56;)SH%I6gP=BHlr}+yXXhdY!V{?S#tI-738124n^W?18jn
zqIq#mJg|L}3(I2tJ@ggu`>E7{(E4DrP1qaZO9QX;UDmI&ha~Eg#l_VmUlw=7C9|o;
zUM52s6y5!~W3+z;Y03xkUaJKQ0aTOJvsFYudCY28y)=+!1IS&-hsN00@)|zx0}dC1
z9{G#*w%fu1n5uQru4+jKPqAp@eT*7Ii3V$PD1VPrE93!OWw)6?rUeYHUF~xA4!l+{
zL!&AxKn%o)BHuv)PbnyNlGGN}spu2brcEtGz&hBf){+enT(5qxq6CW=Ll6?-W<*VR
z=}#4YM0Lhx{FwqY8+HSg%Qd{Gb;9rob_`X65BdlkD}|QyWEiXZu!pRV%OTL2Rl7sx
z4S+pf3-BG)>0UCWffQ3(gjSKri7fiMExu{s>1jPi0X>Kra?#g^x&}{e1vsY(6B}KV
zCgtvCqIct7;G%N=9hei+%we}FC<cpFx=o^^P$d(6y4s!Dm9AA6h26ST;|-u;VLnh)
zHwcBp<gO`9E{ayuTLW@ySv|aW5ii388eS~1P4Scm>{LEhMt6mH6#3$e7)N-y7@oj6
zaUxMPA_1=Ep~H^hduT%P9$|`+R^}jSgg607hY6bU;6fCldgUeJzTLWpxK5>FP!1St
z$xBiK6U!qDoTThGWn>KPu^dDyWdvsqWg6DWB(|6`uEZWgV-O}=hw+96k%#W7@a7HZ
zy^S_P#wqxEI-ZKER*BDYdZf&n<Jrm<2pxt`;SZb^Ci6-4)u%~oIGc<DXv3=(Dw`Tw
z|2iGB>*O@@|I>PjcIaQ$NapO!Zezy=&F&b~Y(FBPP)cnR9w0i5=c8BkCk7itJA#b}
zT+oG<fDmfou%UxF)HmTo?D8z735p9-ys}M#M6eHhHxSDr<V51(5i<-l>f6YOrdRFu
zlItl^%d5F-MOicOP&O<c1|>8U1mW<up1>ya5C9_P{HMzFOy7^>U<3UYedLU0HRwl1
zdC%BPDIbkYsu5k(QJu+|7n4zd4s|vgG}s%^Vc#+k#kYH*cAbh5DeMK)<b-<ApvRI!
z5G}<T@jqQAJc&8$VEp)xY}Y-*?jH{x;>5zPH>mUN{8<RkQs)E|1p=T)wg<umT!n-&
z5~tK2dpe<6k9TTqdyTAsk?it=JFo}7iC>Uu%DhQ!t7I=(rRDw->Xk|30*oysBN`HN
zadJGZ2rs2m9UH$E))kk6qK-};Xp|Hn&S)YDB5b&ku&5NIKQW|;`UCnL#4Oe$x@{q*
zpk&lkxEypIO$yt>geY1#LuyhyT#cpB&&dn@quUHAUpPvYREnnuX)VfD!h>j385K3G
zPO0YGK(l3?NugN=P;E5DZj1(-LN*;c;+a7oeY?q=!6%+t9}mxXAmOd(+y}BQK%R9(
zTAzK%x4FPuU&x^#6n*-xe)9K;?hGkP3}C!(NIC5keiUIvM{zok>q@WSK3x=v+d|_d
zCAR!=KzhUk!f`m{?y|&|%jgzzbr0LO$S9S(bIJ2kMEmevdWFhTB<rHyP18)_R4E9U
z<;e+=Dn!$_kl`<S5|V$lTf*C3F{C7#i3eu}L#w-MseUIk9>z)CmfZ33x`c#Ay9L$U
zj1DNBrJux2EXi?b#H{+P)U73VRYxB-$M$4J`I8Ozg>MzMlo2gKCjsHjN1Gr7l5O;t
zgVJf)W-4v`N{FRh8E7icV9pzSH3Fk&fRp-_U344|EgK?{f)5r7Q<L#9mXLOmtcAq`
z#}iR{aQ$c=!6^h!Aff5;fuVnr{rYwViL*a6ky)#+HV%rih@gVgg$dJ(mWBIKhw?+J
z%#++&B$ANl7zjt=NzzM2svpfLWbk|_`JCYhW_Y&Cd-2D$HaCjyRdV`QQ8CuY>q@p(
z+eViyrDww}G))&IQEQ-GM46(;eVD~Ir8n8M*P@zB^IlEaYqgfu!}&z9=yIFIVq$@k
zMB6=1CT){{qAF^_1236E2?$?_+>S|Tpy8Ign2i!`Gm1q#db2Jsky_}R41&kp)NnNh
zEW(}~XuI8362NKE^Fjpp!>ZBvfwtAE!LnNIQcVz?(?JhZ{g{f0A{}(%;H=^({1F<j
zqZ&P5T285Z<Uy^Ydz7P|UkJWz*b=?xtDJkTN((bz1vqs&k~*uMl=e~#ORf9@`K0sZ
zrs;Tm!&nuWl^xIPF3Cq}R!XNrqwt#+;~69w(=<%0)k1~6K@H{tnyBDplXFQ7D8OT%
zgKui|RAj+N5;p!x_91|XSw_DF0{HRSd~l-4QjrgB^6|j6$IF6JN2o}2<#&MXg>~oJ
zovXFv;s0bft*cxCSUNPWCtkwRL`uK5*tTxt#0BwN-B~h^VmB&VtchHw*}?wNp~Obm
z#>E7@Y&^UQYjj&1MCZPH=m9qc;kJ|@&s^N2A%#aB+3OA?zOF@A->?JAo4hXBe~Y2|
zNu>p9U6=MTOVwY{K~ArD<q;6{B|ygVYC?E64WeTY^>$n|DgG;r;(zPk`9V+qeLP{w
zVECp6QK3Ev-=1Q<mIjY;z&Pd3T!~+4+-SAY{exV2gK=7fbjj{_r^58H&Uj8EoGDc&
zdVG<GqB4af->Ab!PH-Fm%TxZQCU6OK^7bgU9tB1bQ64$qU?4hYJVL2c5m1PjYm^x0
zMd)(|fXY7y2d}jCm10tp^cv(t`cfl8ucVD)KSt;Kxi<1qQFeuyYCdw}D@=`I+n0kd
zL<^BG=ef?pfayx?xSE$h(zt=UKZ?+pv>Vg0b~+-?b0Dp^3YmF|dpS*e6;$wFsDYg}
zjr~FFz>!iAnRxWrHd^V;uJ#5i9$fXlLE!iY-++d}Jg?@vFrN@F6ARLWC@lP<OfS=Q
zv#zo&q#-C_!_<rDdyUA~K^Ir(FEO9lv9QNT?#a{NE#)!e78CyMFjB_t;?WLxv<I)2
z@aO!jy<p7m$Ur47wI?Agf=)tnaG*ibMh+I)BOXx98)lDPedPG801jG}LB*41#c7t|
zN0JXF{;T;4OuCb_NJ>qZ2@YC>3xGTTpL5=GhkO+m0`^JpU}zP*Y5UJ2`n>}lowXh4
z`u3l>ox3Jw{-4RI-1zj!cy4-neAm$a^Fn;0tSDLgE8GRt^@jK@UZZCi#qJZY<!@!L
z$L<9F&tAo;*6mJINbhKW5jGY~8^Zb$?|i$keX$kgCY(&z#w}RP9MB7v43CQv$5*4?
zn0;l!Hlvyys`v^gN07+*oH-h!uV@V<ADc76I_)UENd{a)M1)-x(UW5D!3o?3j_Otm
z@pyce-6AmQfr$L=C#)yF$d&Tsy?mw77u*6Li;5IBN^PtYhQ9w!n7IKB7?~AgV(=TT
zC&Ff6%sLT$Lfs@VH1+uzFrL1rX$*;xj~as(vy%d{avZ-V_o(91wY6Z{s0rZMGpy7w
zlERlI<wy1srA5F4=~knvQp=(i>qj#U5x+#Y#S{`K4878=o1?KAPm4>R=4gr{(ue3!
z#zWiZme^)7%RVsD6DRA#mj}BTe80%C%2haidT1JZIZC8|lmt;L;rFq~QOZx+CBD+u
zpbYa0_F#$;U@6ogOMj}eTf&V3E17P)nw>N+&yvbITWXZiEYGZU8g;VvPKz*vXvWD}
z9z_kuthEy$#T<l<XTL0yl4N6AWjG-SdPycSD+yFAwX0qsu?N25Ng9tXX{l8g#%j2W
z6%t1fy=_TQgp3NkleQ!y#MxA0V2>HRijq2F=#r8)0Hww~fT~^Ww7WLUPV{)ZCgPdP
z3RxNYhn344bR*A1o9;%Ov;2#6(So;5N35dVR2MvGii_gkL5MUe#B8w7b-EJQsT=h*
z)9ttzPo_ixS6UQ2MzS>1xSmJ}1I{%?s6#v(CQ{7vBYUQtDX=#r&}_S7ty=9u;;=*)
z2g8a99NK~2blW23cODw$@1Vw1z#ppwG=$ru+r~i*7y>M4w~;`+^g7Uttb=eDphz$%
zNH`um40>Il-B6-<!#cUasL?Ay24q4w7)en#kAW?i-9alU2BJDj2udk3xfg|BVp6hW
zNjrkZR`6UB(2pTZ=>S9UpnnJvPpY&XKZk-;iE>;qC}XY+(6Fc)1yL@bor#-qI^v2#
zq4Su0EC!1w2}I*nJ}<25HQAOp3GL}R(1<ghHXdwC{#2)Xc?YW*qpJAY9Sj{s?vr?J
z5d?QXm_ws4tnisWWDq7Ty9hYqN7zh^-syZSY%-<_D4PaxpF=N{ebT^X)Xm8F20A(-
zx~|ldLT1v3O7JZy68)FqE`s%SMXDHrA$#*pUC$&?x^YYM%p#@xcXO3CVTaQCx)>3K
z6j`2928$?V^fZ}D&F2<OY=zB_gNAItDWwVxuTw~;TxqA~^O?y7(xXawC^X^CMrV%)
zJ$l3>ea6s5IUu>>dj{2Ddbc^P<b2YZPpl;t(gysOH~r$LyTrM45(`Xi4y&U0`ZSqZ
z5Pd>Z=hBL5M7M^m1?N+n&!@+sIsBg!|0k5=vz*hK=Nl_v6jYH3s1Pu}J()5+z<v8R
zSTY*VNgU5PgF<;`i4jMSWdNVvm_PTKe}-7d*%_58|1=O33hGQ~!q23dPtYi>ApE>&
zukcEaQ(R)KET|)+$^VKhEhgg_7U=+DH%XAqP9a`)-G)TirN9-jF<&R}*6A3ewIA>k
zLG}e?maLQ3zXha+_RtGPfOM9Stc=w-{L@aE@@BRp{7Mk(+%;^cf>Te%x0kcq8`<qQ
z8`}@&w_lszemq2wlwZXz=M8LFH4`kOrC7mI;)F!^Txlbo#4v#zosi}#0w|_}9aZ9o
zI0B^5t<%XEdQHpbB9-rHLo)~rY*q3$t$7H3>{hNNoJ*!)oH{Mo9t;R}tK<q@?ZG10
zqya=8E&5d&YhACsQmoOz9C@aHC%NL^ucpPxJ!osF??F;-AaSC(BWG+a43Y^j@RZZ+
z+Pam8gqljkaSGZvoktxs0X|^2E={cBW6eX_;}uggpdQzsYrJG!?{%d}umdtVz@a%s
z9zwyIY4T=J{eLUQ0wyWI2}4+D`BVM(N-X<?p)?SDk)>}HFvXV<O7AG35{B?)0Ht;z
zn3|`crPC>)#23H~UpgUO9m?$Nn+TGv=cSBafih9oQl7D+fa>9~q+QR5!Xf>86sEC0
zejQ}f3`A?XS8Ig29~igYEEnQod%2|8?lprr90c~PTl@$3aNt*%9|wM=1J*Y_yBGgM
zV_7NA--;$7r(nOz10tmjf5Xaa`;NbF<qb9b1VaEG@t4zK3q*|$U^UeDG3cnjs3Hw0
zDx=l+m)r>U=m;q)7yK^Qy^X8HF-1`PY%cN`o%heo9h%)24;YIL6d{BFRZK;CTVSJW
zo^e%_C8gGgDkh%|E+*8dN&KE%1Bj|BM%M2+m7>j1{f2Fj?^HDIMJ#E)>7z>sTh@YT
zBEQ1ZkG&h&5j<Nd>R2P0{pkQF)On;Y?nJUy`88nhms4!U&!t5CM&m8s1QkN2F1t9L
zJ+-D65k#DWeHTxHV<7t-Vn&in@&AbwfDK+lW9u9^f*Ytbi<#Fp7%@5!YT|w4Sx`u|
z0YcH@$c;aUPozLk`n*Pz3gHQt@{t4Ge)n1&VqGW$p_mk=X$Oy73GMyBg&Zs<t|L!H
zicyvLUKdq&EJ^hXQW21kQ#vgGcRaoW$|ggDP3?$h1225QEd<Z-L<b#g3~)K=qr0jA
zxL&p~c_pGgEzs$x!&N$Puzk+&|D+|<xd(&WDE`~7aT)(5w{vPbH!_}^nx32*-v3>Q
zj~<mxgm9aRM_pir;)KbACz}*;7z+-^ktPK~kxf12sgmO{2-<FH#$eJOPSx@Cf_gj>
z`y?izN|u|tEQ^6imN8CAx#`yuJ?13?z7d8-@n~_Nn2bUjpQuG<%b5Krsf|3bwv<R4
zWVKw$2YnwkFqq|TqvcOLt=^MjyM9~4iVq&zK9Hoh##6phg@GyN>W@<CSkxo5vTqi(
zA{_VuYeVl9=Ol01>V1ISgkY*eBRCK;6g&UJ(9GHfO?B|9w3iZnYZ5S^4lWNFQ?0iw
zzT_!d2vih>Lh_#|$wtNDn`m<r7uj@$%@^9wwH?Yp{%_jVY6b(tX3q<2JhS+3Q<J%=
zVf?orll3p#C@|U0Qm<Hdn#-QqIoUbC@t?<Y!S$cWP41c;?*A9!Gc<!6+W&1p|3|Mm
zkeNHY|H!i?|BvsS+!f;gyLRS=^8W?-Tnh(NJaA@i;A24E$eH7#vBMy3<#ii9^_tLR
zG<Lk(XjtuD-Z+=I#h7BSVP{%a6*}8=MCQ@h3`JJX8-C1X`7A@xmh*-dZFw|yh(kBS
zSSfV#Xl$QvU6(hmKYY#MBR3w#EEHA;@0helL;45$mu7Egyzg&%|DOuWf78>s@ge<R
zh!4jHk4eLcn1~D>3mv3}V!}@^{U1Ma{jt5X$IqJlH<AA#od0EdVtg3?`NHh~Gl%E)
z&mKQvI?dRz*_nOU&YF#KOlARztsj4Xd|hwN*trD%kDW{8|ACb?o%X;o^xU_v-c&hd
zZMB)w6Pqo!ajP|#MXPlOims0Bu81lC<sw!5vFO0>vGx6dV(T0iV(YV#*d{d%u?-}W
zsP`SWRjk{qcKz&m){y_7KWJ_!|AqPg1fB_p{Qp9H1~3hus)mx^@H6}jKf}-PGyDuc
Z!_V+D{0u+C&rihX{{dFZ^s)eu0RTHt$%Fs^

diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..b5a3c46
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,6 @@
+[build-system]
+requires = [
+    "setuptools>=42",
+    "wheel"
+]
+build-backend = "setuptools.build_meta"
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 29108c8..aaa1240 100644
--- a/setup.py
+++ b/setup.py
@@ -1,14 +1,35 @@
-from setuptools import setup
-from unitgrade.version import __version__
-setup(
-    name='unitgrade',
+# Use this guide:
+# https://packaging.python.org/tutorials/packaging-projects/
+
+# 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]
+# long_description = fh.read()
+
+with open("README.md", "r", encoding="utf-8") as fh:
+    long_description = fh.read()
+
+setuptools.setup(
+    name="unitgrade",
     version=__version__,
-    packages=['unitgrade', 'cs101courseware_example'],
+    author="Tue Herlau",
+    author_email="tuhe@dtu.dk",
+    description="A student homework/exam evaluation framework build on pythons unittest framework.",
+    long_description=long_description,
+    long_description_content_type="text/markdown",
     url='https://lab.compute.dtu.dk/tuhe/unitgrade',
-    license='Apache',
-    author='Tue Herlau',
-    author_email='tuhe@dtu.dk',
-    description='A lightweight student evaluation framework build on unittest',
-    include_package_data=True,
-    install_requires=['numpy', 'jinja2', 'tabulate', 'sklearn', 'compress_pickle', "pyfiglet"],
+    project_urls={
+        "Bug Tracker": "https://lab.compute.dtu.dk/tuhe/unitgrade/issues",
+    },
+    classifiers=[
+        "Programming Language :: Python :: 3",
+        "License :: OSI Approved :: MIT License",
+        "Operating System :: OS Independent",
+    ],
+    package_dir={"": "src"},
+    packages=setuptools.find_packages(where="src"),
+    python_requires=">=3.8",
+    license="MIT",
+    install_requires=['numpy', 'tabulate', 'tqdm', "pyfiglet", "colorama", "coverage"],
 )
diff --git a/unitgrade2/__init__.py b/src/unitgrade2/__init__.py
similarity index 90%
rename from unitgrade2/__init__.py
rename to src/unitgrade2/__init__.py
index 23b1c9d..d62d54d 100644
--- a/unitgrade2/__init__.py
+++ b/src/unitgrade2/__init__.py
@@ -1,4 +1,3 @@
-from unitgrade2.version import __version__
 import os
 
 # DONT't import stuff here since install script requires __version__
@@ -34,4 +33,4 @@ def cache_read(file_name):
     else:
         return None
 
-from unitgrade2.unitgrade2 import Hidden, myround, mfloor, msum, Capturing, ActiveProgress
+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
new file mode 100644
index 0000000000000000000000000000000000000000..4429c41fb31c60f6c1074d20620caf2572fce98e
GIT binary patch
literal 1306
zcmZ9LO>f*p7{_PEue+O)@KO$?1k(eOQME#mkPxa6kb=Y|0-7qpT509=Og7%w9y2rU
zc2^DuQgJ{ke1$|k^()Pl6JLQ7&tq>$=~({HGcV7~c>X^>zIAIzpx76mq~Cgk{DqBI
zivx`>;niP*aKdRp62gbv;qEh<Q0{U68A%uqcnGxvGX{lQdWl#1iC+duP=-lZ4w3<d
z+(#rH{SE7ogTo9LzAiol19<o0)fEV*oD}5TF?7K$ot9qFbGM7#*1e+oV?!@Jj3{ZD
z`po#8we*5fVuF@(=YswD?zz`Gi?AiF$6f9{cPKd`pOPQQkK`D07Lem#Kt3mMsNg_R
z*mb>gq;iv2^C(NRQ!yToEnCj4Tdd3UB~3<|ENdmS&Skas9?D957!U0Bb?>y!v$H~2
zCbf0z)STLY=c-CeVSVv5*G5~fJcBOl)he%yb!9Co>++_oW8eC6wh)=IgOj`v(=IJ|
zBGgQ3p}-it<I2*Lmqfh<t$!Zue?EB(LwaJGQ!#lcv!)c4(UYdi&0M8iOti{wT6>e}
zG>4(-bX>3OsQbX_5<XYp;`$vBLPNR*&yc!g2=yJP6%J&0IoAba^se)23j#wH^pdsY
z3hku_v7^vV6`-K0F;&|b<FR{r8zQ^aAECdQ9q7>vgfMj*^nW|L(1DP4JN^N|h7P)+
z19n!wt@n)E63)Q;-E*K};k67Qea?;u+c^IM7<jZ{;E4SEyGx9JHdMb-AdQmst_ir;
zlAfcU4&cc_N{}56vwm@o$xo1ZOez=2d6gc^)J);cC_M1`-l56`kBp28ner%&W}rPH
z5n3FjW?g=F5}8x6Y1g$#mBx%2j5bD=smZgnC|1#2R6?aj@cYq9Hh^ap8MVTxTol5H
zC^z>b2}`MEu0_P<vfAugiDd*BA+vGVf%KX^3OxkI;gELl&C^WO2Ii^}^u})Q91^15
z#A#H#ZsV}GQHhkJan~TREy@6)kLV8I6w<qnx`PXPHYit0HWjyic~VHJtXt})w1fS$
zHVyn1bNj|unaQ7s@0Fb6&lc0ec-WsAS?uuW7E5mbhx*?5CRFd?th*@hqwJ!5fN}$1
a7j+bd4@$|KLVST(>kuS#hojI7xBmrp{x(<u

literal 0
HcmV?d00001

diff --git a/src/unitgrade2/__pycache__/unitgrade2.cpython-38.pyc b/src/unitgrade2/__pycache__/unitgrade2.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3f772f63e4a0c6727d15b104e6cf981814c53043
GIT binary patch
literal 22713
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

literal 0
HcmV?d00001

diff --git a/src/unitgrade2/unitgrade2.py b/src/unitgrade2/unitgrade2.py
new file mode 100644
index 0000000..a0290ca
--- /dev/null
+++ b/src/unitgrade2/unitgrade2.py
@@ -0,0 +1,705 @@
+"""
+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
+import threading
+import tqdm
+import pickle
+import os
+from io import StringIO
+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
+
+_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
+
+colorama.init(autoreset=True)  # auto resets your settings after every output
+
+def gprint(s):
+    print(f"{Fore.GREEN}{s}")
+
+myround = lambda x: np.round(x)  # required.
+msum = lambda x: sum(x)
+mfloor = lambda x: np.floor(x)
+
+
+def setup_dir_by_class(C, base_dir):
+    name = C.__class__.__name__
+    return base_dir, name
+
+
+class Logger(object):
+    def __init__(self, buffer):
+        assert False
+        self.terminal = sys.stdout
+        self.log = buffer
+
+    def write(self, message):
+        self.terminal.write(message)
+        self.log.write(message)
+
+    def flush(self):
+        # this flush method is needed for python 3 compatibility.
+        pass
+
+
+class Capturing(list):
+    def __init__(self, *args, stdout=None, unmute=False, **kwargs):
+        self._stdout = stdout
+        self.unmute = unmute
+        super().__init__(*args, **kwargs)
+
+    def __enter__(self, capture_errors=True):  # don't put arguments here.
+        self._stdout = sys.stdout if self._stdout == None else self._stdout
+        self._stringio = StringIO()
+        if self.unmute:
+            sys.stdout = Logger(self._stringio)
+        else:
+            sys.stdout = self._stringio
+
+        if capture_errors:
+            self._sterr = sys.stderr
+            sys.sterr = StringIO()  # memory hole it
+        self.capture_errors = capture_errors
+        return self
+
+    def __exit__(self, *args):
+        self.extend(self._stringio.getvalue().splitlines())
+        del self._stringio  # free up some memory
+        sys.stdout = self._stdout
+        if self.capture_errors:
+            sys.sterr = self._sterr
+
+
+class Capturing2(Capturing):
+    def __exit__(self, *args):
+        lines = self._stringio.getvalue().splitlines()
+        txt = "\n".join(lines)
+        numbers = extract_numbers(txt)
+        self.extend(lines)
+        del self._stringio  # free up some memory
+        sys.stdout = self._stdout
+        if self.capture_errors:
+            sys.sterr = self._sterr
+
+        self.output = txt
+        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
+    questions = []
+    pack_imports = []
+    individual_imports = []
+    nL = 120  # Maximum line width
+
+    @classmethod
+    def reset(cls):
+        for (q, _) in cls.questions:
+            if hasattr(q, 'reset'):
+                q.reset()
+
+    @classmethod
+    def mfile(clc):
+        return inspect.getfile(clc)
+
+    def _file(self):
+        return inspect.getfile(type(self))
+
+    def _import_base_relative(self):
+        if hasattr(self.pack_imports[0], '__path__'):
+            root_dir = self.pack_imports[0].__path__._path[0]
+        else:
+            root_dir = self.pack_imports[0].__file__
+
+        root_dir = os.path.dirname(root_dir)
+        relative_path = os.path.relpath(self._file(), root_dir)
+        modules = os.path.normpath(relative_path[:-3]).split(os.sep)
+        return root_dir, relative_path, modules
+
+    def __init__(self, strict=False, payload=None):
+        working_directory = os.path.abspath(os.path.dirname(self._file()))
+        self.wdir, self.name = setup_dir_by_class(self, working_directory)
+        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")
+        for (q, _) in self.questions:
+            q.nL = self.nL  # Set maximum line length.
+
+        if payload is not None:
+            self.set_payload(payload, strict=strict)
+
+    def main(self, verbosity=1):
+        # Run all tests using standard unittest (nothing fancy).
+        loader = unittest.TestLoader()
+        for q, _ in self.questions:
+            start = time.time()  # A good proxy for setup time is to
+            suite = loader.loadTestsFromTestCase(q)
+            unittest.TextTestRunner(verbosity=verbosity).run(suite)
+            total = time.time() - start
+            q.time = total
+
+    def _setup_answers(self, with_coverage=False):
+        if with_coverage:
+            for q, _ in self.questions:
+                q._with_coverage = True
+                q._report = self
+
+        self.main()  # Run all tests in class just to get that out of the way...
+        report_cache = {}
+        for q, _ in self.questions:
+            # print(self.questions)
+            if hasattr(q, '_save_cache'):
+                q()._save_cache()
+                print("q is", q())
+                q()._cache_put('time', q.time) # = q.time
+                report_cache[q.__qualname__] = q._cache2
+            else:
+                report_cache[q.__qualname__] = {'no cache see _setup_answers in unitgrade2.py': True}
+        if with_coverage:
+            for q, _ in self.questions:
+                q._with_coverage = False
+        return report_cache
+
+    def set_payload(self, payloads, strict=False):
+        for q, _ in self.questions:
+            q._cache = payloads[q.__qualname__]
+
+
+def rm_progress_bar(txt):
+    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.
+    nlines = []
+    for l in txt.splitlines():
+        pct = l.find("%")
+        ql = False
+        if pct > 0:
+            i = l.find("|", pct + 1)
+            if i > 0 and l.find("|", i + 1) > 0:
+                ql = True
+        if not ql:
+            nlines.append(l)
+    return "\n".join(nlines)
+
+
+def extract_numbers(txt):
+    # txt = rm_progress_bar(txt)
+    numeric_const_pattern = r'[-+]? (?: (?: \d* \. \d+ ) | (?: \d+ \.? ) )(?: [Ee] [+-]? \d+ ) ?'
+    rx = re.compile(numeric_const_pattern, re.VERBOSE)
+    all = rx.findall(txt)
+    all = [float(a) if ('.' in a or "e" in a) else int(a) for a in all]
+    if len(all) > 500:
+        print(txt)
+        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))
+    return all
+
+
+class ActiveProgress():
+    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):
+        if file == None:
+            file = sys.stdout
+        self.file = file
+        self.t = t
+        self._running = False
+        self.title = title
+        self.dt = 0.01
+        self.n = int(np.round(self.t / self.dt))
+        self.show_progress_bar = show_progress_bar
+        self.pbar = None
+
+        if start:
+            self.start()
+
+    def start(self):
+        self._running = True
+        if self.show_progress_bar:
+            self.thread = threading.Thread(target=self.run)
+            self.thread.start()
+        self.time_started = time.time()
+
+    def terminate(self):
+        if not self._running:
+            raise Exception("Stopping a stopped progress bar. ")
+        self._running = False
+        if self.show_progress_bar:
+            self.thread.join()
+        if self.pbar is not None:
+            self.pbar.update(1)
+            self.pbar.close()
+            self.pbar = None
+
+        self.file.flush()
+        return time.time() - self.time_started
+
+    def run(self):
+        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,
+                              bar_format='{l_bar}{bar}| [{elapsed}<{remaining}]')
+
+        for _ in range(self.n - 1):  # Don't terminate completely; leave bar at 99% done until terminate.
+            if not self._running:
+                self.pbar.close()
+                self.pbar = None
+                break
+
+            time.sleep(self.dt)
+            self.pbar.update(1)
+
+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)
+
+
+class UTextResult(unittest.TextTestResult):
+    nL = 80
+    number = -1  # HAcky way to set question number.
+    show_progress_bar = True
+    cc = None
+
+    def __init__(self, stream, descriptions, verbosity):
+        super().__init__(stream, descriptions, verbosity)
+        self.successes = []
+
+    def printErrors(self) -> None:
+        self.printErrorList('ERROR', self.errors)
+        self.printErrorList('FAIL', self.failures)
+
+    def addError(self, test, err):
+        super(unittest.TextTestResult, self).addFailure(test, err)
+        self.cc_terminate(success=False)
+
+    def addFailure(self, test, err):
+        super(unittest.TextTestResult, self).addFailure(test, err)
+        self.cc_terminate(success=False)
+
+    def addSuccess(self, test: unittest.case.TestCase) -> None:
+        self.successes.append(test)
+        self.cc_terminate()
+
+    def cc_terminate(self, success=True):
+        if self.show_progress_bar or True:
+            tsecs = np.round(self.cc.terminate(), 2)
+            self.cc.file.flush()
+            ss = self.item_title_print
+
+            state = "PASS" if success else "FAILED"
+
+            dot_parts = ('.' * max(0, self.nL - len(state) - len(ss)))
+            if self.show_progress_bar or True:
+                print(self.item_title_print + dot_parts, end="", file=self.cc.file)
+            else:
+                print(dot_parts, end="", file=self.cc.file)
+
+            if tsecs >= 0.5:
+                state += " (" + str(tsecs) + " seconds)"
+            print(state, file=self.cc.file)
+
+    def startTest(self, test):
+        # j =self.testsRun
+        self.testsRun += 1
+        # item_title = self.getDescription(test)
+        item_title = test.shortDescription()  # Better for printing (get from cache).
+        if item_title == None:
+            # For unittest framework where getDescription may return None.
+            item_title = self.getDescription(test)
+        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)
+        estimated_time = 10
+        if self.show_progress_bar or True:
+            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)
+        else:
+            print(self.item_title_print + ('.' * max(0, self.nL - 4 - len(self.item_title_print))), end="")
+
+        self._test = test
+        self._stdout = sys.stdout
+        sys.stdout = io.StringIO()
+
+    def stopTest(self, test):
+        sys.stdout = self._stdout
+        super().stopTest(test)
+
+    def _setupStdout(self):
+        if self._previousTestClass == None:
+            total_estimated_time = 1
+            if hasattr(self.__class__, 'q_title_print'):
+                q_title_print = self.__class__.q_title_print
+            else:
+                q_title_print = "<unnamed test. See unitgrade.py>"
+
+            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)
+            self.cc = cc
+
+    def _restoreStdout(self):  # Used when setting up the test.
+        if self._previousTestClass is None:
+            q_time = self.cc.terminate()
+            q_time = np.round(q_time, 2)
+            sys.stdout.flush()
+            if self.show_progress_bar:
+                print(self.cc.title, end="")
+            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))
+
+
+class UTextTestRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        stream = io.StringIO()
+        super().__init__(*args, stream=stream, **kwargs)
+
+    def _makeResult(self):
+        # stream = self.stream # not you!
+        stream = sys.stdout
+        stream = _WritelnDecorator(stream)
+        return self.resultclass(stream, self.descriptions, self.verbosity)
+
+
+def cache(foo, typed=False):
+    """ Magic cache wrapper
+    https://github.com/python/cpython/blob/main/Lib/functools.py
+    """
+    maxsize = None
+    def wrapper(self, *args, **kwargs):
+        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))
+        if not self._cache_contains(key):
+            value = foo(self, *args, **kwargs)
+            self._cache_put(key, value)
+        else:
+            value = self._cache_get(key)
+        return value
+
+    return wrapper
+
+
+def get_hints(ss):
+    if ss == None:
+        return None
+    try:
+        ss = textwrap.dedent(ss)
+        ss = ss.replace('''"""''', "").strip()
+        hints = ["hints:", ]
+        j = np.argmax([ss.lower().find(h) for h in hints])
+        h = hints[j]
+        ss = ss[ss.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()
+        return ss
+    except Exception as e:
+        print("bad hints", ss, e)
+
+
+class UTestCase(unittest.TestCase):
+    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.
+    _cache = None  # Read-only cache. Ensures method always produce same result.
+    _cache2 = None  # User-written cache.
+    _with_coverage = False
+    _report = None  # The report used. This is very, very hacky and should always be None. Don't rely on it!
+
+    def capture(self):
+        if hasattr(self, '_stdout') and self._stdout is not None:
+            file = self._stdout
+        else:
+            # self._stdout = sys.stdout
+            # sys._stdout = io.StringIO()
+            file = sys.stdout
+        return Capturing2(stdout=file)
+
+    @classmethod
+    def question_title(cls):
+        """ Return the question title """
+        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__
+
+    @classmethod
+    def reset(cls):
+        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")
+        cls._outcome = None
+        cls._cache = None
+        cls._cache2 = None
+
+    def _callSetUp(self):
+        if self._with_coverage:
+            if not hasattr(self._report, 'covcache'):
+                self._report.covcache = {}
+            import coverage
+            self.cov = coverage.Coverage()
+            self.cov.start()
+        self.setUp()
+
+    def _callTearDown(self):
+        self.tearDown()
+        if self._with_coverage:
+            from pathlib import Path
+            from snipper import snipper
+            self.cov.stop()
+            data = self.cov.get_data()
+            base, _, _ = self._report._import_base_relative()
+            for file in data.measured_files():
+                file = os.path.normpath(file)
+                root = Path(base)
+                child = Path(file)
+                if root in child.parents:
+                    with open(child, 'r') as f:
+                        s = f.read()
+                    lines = s.splitlines()
+                    garb = 'GARBAGE'
+
+                    lines2 = snipper.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:
+                                self._report.covcache[self.cache_id()] = {}
+
+                            rel = os.path.relpath(child, root)
+                            cc = self._report.covcache[self.cache_id()]
+                            j = 0
+                            for j in range(l, -1, -1):
+                                if "def" in lines2[j] or "class" in lines2[j]:
+                                    break
+                            from snipper.snipper import gcoms
+                            fun = lines2[j]
+                            comments, _ = gcoms("\n".join(lines2[j:l]))
+                            if rel not in cc:
+                                cc[rel] = {}
+                            cc[rel][fun] = (l, "\n".join(comments))
+                            self._cache_put((self.cache_id(), 'coverage'), self._report.covcache)
+
+    def shortDescriptionStandard(self):
+        sd = super().shortDescription()
+        if sd is None:
+            sd = self._testMethodName
+        return sd
+
+    def shortDescription(self):
+        sd = self.shortDescriptionStandard()
+        title = self._cache_get((self.cache_id(), 'title'), sd)
+        return title if title is not None else sd
+
+    @property
+    def title(self):
+        return self.shortDescription()
+
+    @title.setter
+    def title(self, value):
+        self._cache_put((self.cache_id(), 'title'), value)
+
+    def _get_outcome(self):
+        if not (self.__class__, '_outcome') or self.__class__._outcome is None:
+            self.__class__._outcome = {}
+        return self.__class__._outcome
+
+    def _callTestMethod(self, testMethod):
+        t = time.time()
+        self._ensure_cache_exists()  # Make sure cache is there.
+        if self._testMethodDoc is not None:
+            self._cache_put((self.cache_id(), 'title'), self.shortDescriptionStandard())
+
+        self._cache2[(self.cache_id(), 'assert')] = {}
+        res = testMethod()
+        elapsed = time.time() - t
+        self._get_outcome()[self.cache_id()] = res
+        self._cache_put((self.cache_id(), "time"), elapsed)
+
+    def cache_id(self):
+        c = self.__class__.__qualname__
+        m = self._testMethodName
+        return c, m
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self._load_cache()
+        self._assert_cache_index = 0
+
+    def _ensure_cache_exists(self):
+        if not hasattr(self.__class__, '_cache') or self.__class__._cache == None:
+            self.__class__._cache = dict()
+        if not hasattr(self.__class__, '_cache2') or self.__class__._cache2 == None:
+            self.__class__._cache2 = dict()
+
+    def _cache_get(self, key, default=None):
+        self._ensure_cache_exists()
+        return self.__class__._cache.get(key, default)
+
+    def _cache_put(self, key, value):
+        self._ensure_cache_exists()
+        self.__class__._cache2[key] = value
+
+    def _cache_contains(self, key):
+        self._ensure_cache_exists()
+        return key in self.__class__._cache
+
+    def wrap_assert(self, assert_fun, first, *args, **kwargs):
+        # sys.stdout = self._stdout
+        key = (self.cache_id(), 'assert')
+        if not self._cache_contains(key):
+            print("Warning, framework missing", key)
+            self.__class__._cache[
+                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.
+        cache = self._cache_get(key)
+        id = self._assert_cache_index
+        if not id in cache:
+            print("Warning, framework missing cache index", key, "id =", id)
+        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")
+
+        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.
+        cache[id] = first
+        self._cache_put(key, cache)
+        self._assert_cache_index += 1
+        assert_fun(first, _expected, *args, **kwargs)
+
+    def assertEqualC(self, first: Any, msg: Any = ...) -> None:
+        self.wrap_assert(self.assertEqual, first, msg)
+
+    def _cache_file(self):
+        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"
+
+    def _save_cache(self):
+        # get the class name (i.e. what to save to).
+        cfile = self._cache_file()
+        if not os.path.isdir(os.path.dirname(cfile)):
+            os.makedirs(os.path.dirname(cfile))
+
+        if hasattr(self.__class__, '_cache2'):
+            with open(cfile, 'wb') as f:
+                pickle.dump(self.__class__._cache2, f)
+
+    # But you can also set cache explicitly.
+    def _load_cache(self):
+        if self._cache is not None:  # Cache already loaded. We will not load it twice.
+            return
+            # raise Exception("Loaded cache which was already set. What is going on?!")
+        cfile = self._cache_file()
+        if os.path.exists(cfile):
+            try:
+                with open(cfile, 'rb') as f:
+                    data = pickle.load(f)
+                self.__class__._cache = data
+            except Exception as e:
+                print("Bad cache", cfile)
+                print(e)
+        else:
+            print("Warning! data file not found", cfile)
+
+    def _feedErrorsToResult(self, result, errors):
+        """ Use this to show hints on test failure. """
+        if not isinstance(result, UTextResult):
+            er = [e for e, v in errors if v != None]
+
+            if len(er) > 0:
+                hints = []
+                key = (self.cache_id(), 'coverage')
+                if self._cache_contains(key):
+                    CC = self._cache_get(key)
+                    for id in CC:
+                        if id == self.cache_id():
+                            cl, m = id
+                            gprint(f"> An error occured while solving: {cl}.{m}. The files/methods you need to edit are:")  # For the test {id} in {file} you should edit:")
+                            for file in CC[id]:
+                                rec = CC[id][file]
+                                gprint(f">   * {file}")
+                                for l in rec:
+                                    _, comments = CC[id][file][l]
+                                    hint = get_hints(comments)
+
+                                    if hint != None:
+                                        hints.append(hint)
+                                    gprint(f">      - {l}")
+
+                er = er[0]
+                doc = er._testMethodDoc
+                if doc is not None:
+                    hint = get_hints(er._testMethodDoc)
+                    if hint is not None:
+                        hints = [hint] + hints
+                if len(hints) > 0:
+                    gprint("> Hints:")
+                    gprint(textwrap.indent("\n".join(hints), ">   "))
+
+        super()._feedErrorsToResult(result, errors)
+
+    def startTestRun(self):
+        # print("asdfsdaf 11", file=sys.stderr)
+        super().startTestRun()
+        # print("asdfsdaf")
+
+    def _callTestMethod(self, method):
+        # print("asdfsdaf")
+        super()._callTestMethod(method)
+
+
+def hide(func):
+    return func
+
+
+def makeRegisteringDecorator(foreignDecorator):
+    """
+        Returns a copy of foreignDecorator, which is identical in every
+        way(*), except also appends a .decorator property to the callable it
+        spits out.
+    """
+
+    def newDecorator(func):
+        # Call to newDecorator(method)
+        # Exactly like old decorator, but output keeps track of what decorated it
+        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done
+        R.decorator = newDecorator  # keep track of decorator
+        # R.original = func         # might as well keep track of everything!
+        return R
+
+    newDecorator.__name__ = foreignDecorator.__name__
+    newDecorator.__doc__ = foreignDecorator.__doc__
+    return newDecorator
+
+hide = makeRegisteringDecorator(hide)
+
+def methodsWithDecorator(cls, decorator):
+    """
+        Returns all methods in CLS with DECORATOR as the
+        outermost decorator.
+
+        DECORATOR must be a "registering decorator"; one
+        can make any decorator "registering" via the
+        makeRegisteringDecorator function.
+
+        import inspect
+        ls = list(methodsWithDecorator(GeneratorQuestion, deco))
+        for f in ls:
+            print(inspect.getsourcelines(f) ) # How to get all hidden questions.
+    """
+    for maybeDecorated in cls.__dict__.values():
+        if hasattr(maybeDecorated, 'decorator'):
+            if maybeDecorated.decorator == decorator:
+                print(maybeDecorated)
+                yield maybeDecorated
+# 817
diff --git a/unitgrade2/unitgrade_helpers2.py b/src/unitgrade2/unitgrade_helpers2.py
similarity index 84%
rename from unitgrade2/unitgrade_helpers2.py
rename to src/unitgrade2/unitgrade_helpers2.py
index 8421562..d007fd2 100644
--- a/unitgrade2/unitgrade_helpers2.py
+++ b/src/unitgrade2/unitgrade_helpers2.py
@@ -2,19 +2,13 @@ import numpy as np
 from tabulate import tabulate
 from datetime import datetime
 import pyfiglet
-from unitgrade2 import Hidden, myround, msum, mfloor, ActiveProgress
-from unitgrade2 import __version__
+from unitgrade2 import msum
 import unittest
-# from unitgrade2.unitgrade2 import MySuite
 from unitgrade2.unitgrade2 import UTextResult
-
 import inspect
 import os
 import argparse
-import sys
 import time
-import threading # don't import Thread bc. of minify issue.
-import tqdm # don't do from tqdm import tqdm because of minify-issue
 
 parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
 To run all tests in a report: 
@@ -109,31 +103,27 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
                     show_tol_err=False,
                     big_header=True):
 
-    from unitgrade2.version import __version__
+    from src.unitgrade2.version import __version__
     now = datetime.now()
     if big_header:
         ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")
         b = "\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )
     else:
         b = "Unitgrade"
-    print(b + " v" + __version__)
     dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
-    print("Started: " + dt_string)
+    print(b + " v" + __version__ + ", started: " + dt_string+ "\n")
+    # print("Started: " + dt_string)
     s = report.title
     if hasattr(report, "version") and report.version is not None:
         s += " version " + report.version
-    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")
+    print(s, "(use --help for options)" if show_help_flag else "")
     # print(f"Loaded answers from: ", report.computed_answers_file, "\n")
     table_data = []
-    nL = 80
     t_start = time.time()
     score = {}
     loader = SequentialTestLoader()
 
     for n, (q, w) in enumerate(report.questions):
-        # q = q()
-        # q_hidden = False
-        # q_hidden = issubclass(q.__class__, Hidden)
         if question is not None and n+1 != question:
             continue
         suite = loader.loadTestsFromTestCase(q)
@@ -143,12 +133,11 @@ 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 unitgrade2.unitgrade2 import UTextTestRunner
-        # unittest.Te
-        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
+        from src.unitgrade2.unitgrade2 import UTextTestRunner
         UTextResult.q_title_print = q_title_print # Hacky
         UTextResult.show_progress_bar = show_progress_bar # Hacky.
         UTextResult.number = n
+        UTextResult.nL = report.nL
 
         res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)
 
@@ -157,20 +146,16 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
 
         assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun
 
-        # possible = int(ws @ possible)
-        # obtained = int(ws @ obtained)
-        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0
-
         obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0
         score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle}
         q.obtained = obtained
         q.possible = possible
 
-        s1 = f"*** Question q{n+1}"
+        s1 = f" * q{n+1})   Total"
         s2 = f" {q.obtained}/{w}"
-        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )
+        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )
         print(" ")
-        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])
+        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])
 
     ws, possible, obtained = upack(score)
     possible = int( msum(possible) )
@@ -185,10 +170,12 @@ 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 "")
 
-    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")
+    from src.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)
+
+    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")
 
     table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])
     results = {'total': (obtained, possible), 'details': score}
     return results, table_data
-
-
diff --git a/src/unitgrade2/version.py b/src/unitgrade2/version.py
new file mode 100644
index 0000000..a0235ce
--- /dev/null
+++ b/src/unitgrade2/version.py
@@ -0,0 +1 @@
+__version__ = "0.0.2"
\ No newline at end of file
diff --git a/unitgrade.egg-info/PKG-INFO b/unitgrade.egg-info/PKG-INFO
deleted file mode 100644
index cc1c911..0000000
--- a/unitgrade.egg-info/PKG-INFO
+++ /dev/null
@@ -1,10 +0,0 @@
-Metadata-Version: 1.0
-Name: unitgrade
-Version: 0.0.5
-Summary: A lightweight student evaluation framework build on unittest
-Home-page: https://lab.compute.dtu.dk/tuhe/unitgrade
-Author: Tue Herlau
-Author-email: tuhe@dtu.dk
-License: Apache
-Description: UNKNOWN
-Platform: UNKNOWN
diff --git a/unitgrade.egg-info/SOURCES.txt b/unitgrade.egg-info/SOURCES.txt
deleted file mode 100644
index 9026e79..0000000
--- a/unitgrade.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-MANIFEST.in
-README.md
-setup.py
-cs101courseware_example/Report0_resources_do_not_hand_in.dat
-cs101courseware_example/Report1_resources_do_not_hand_in.dat
-cs101courseware_example/Report2_resources_do_not_hand_in.dat
-cs101courseware_example/__init__.py
-cs101courseware_example/cs101report1.py
-cs101courseware_example/cs101report1_grade.py
-cs101courseware_example/cs101report2.py
-cs101courseware_example/cs101report2_grade.py
-cs101courseware_example/homework1.py
-cs101courseware_example/instructions.py
-unitgrade/__init__.py
-unitgrade/unitgrade.py
-unitgrade/unitgrade_helpers.py
-unitgrade.egg-info/PKG-INFO
-unitgrade.egg-info/SOURCES.txt
-unitgrade.egg-info/dependency_links.txt
-unitgrade.egg-info/requires.txt
-unitgrade.egg-info/top_level.txt
\ No newline at end of file
diff --git a/unitgrade.egg-info/dependency_links.txt b/unitgrade.egg-info/dependency_links.txt
deleted file mode 100644
index 8b13789..0000000
--- a/unitgrade.egg-info/dependency_links.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/unitgrade.egg-info/requires.txt b/unitgrade.egg-info/requires.txt
deleted file mode 100644
index b8b3f85..0000000
--- a/unitgrade.egg-info/requires.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-jinja2
-tabulate
-sklearn
-compress_pickle
diff --git a/unitgrade.egg-info/top_level.txt b/unitgrade.egg-info/top_level.txt
deleted file mode 100644
index 5f808ad..0000000
--- a/unitgrade.egg-info/top_level.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-cs101courseware_example
-unitgrade
diff --git a/unitgrade/Report_resources_do_not_hand_in.dat b/unitgrade/Report_resources_do_not_hand_in.dat
deleted file mode 100644
index 9c15fa98decdca1da9d38c1989086f8c4c1ce960..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 64
zcmexsUKJ6=z`*kC+7>q^21Q0O1_p)_{ill=8CV)vYp3V|xeT8qo;6HpUYNnaD9gG-
Rw_&~fw$HVUAPJVpC;)i%6A1tS

diff --git a/unitgrade/version.py b/unitgrade/version.py
index a23ef3f..a68927d 100644
--- a/unitgrade/version.py
+++ b/unitgrade/version.py
@@ -1 +1 @@
-__version__ = "0.1.8"
\ No newline at end of file
+__version__ = "0.1.0"
\ No newline at end of file
diff --git a/unitgrade2/__pycache__/__init__.cpython-38.pyc b/unitgrade2/__pycache__/__init__.cpython-38.pyc
deleted file mode 100644
index ac7b672193da207e651f61b4bee3e1791e27a656..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1373
zcmZ9LUyIx}5Wpq*@BX<Y4NY1~d-Wv{a0&ZxPzWKEhD)J+IojmHUCn~=TDm>&S+*m~
z+3e!WLof89koGIw(WiVRz4obJp--Lh?)K8iXfzs2ni<Vc&$qVv1lqmnPO@|e`3ooS
zHwz};La(2K;DpnhNE%U!I?Gwa_<-Boc|#+MyWD$2BAffX2crWk`nfB;$di8L%U;xz
z{irVo(LfHPA)LUTk#P7ooJ&G#266mSs5&c)INm=<(eI|Yp!A^cL9YuCoN|(rGfUGM
zyRce%Nzd#~w_E#?)?aCQ;h;uI%hUtya@NvwMv3-X%B^$u$L%wxwPt=xS_h+lYf*AY
zz9v7Br{oCt%wUgu-en0fdi#ok*X4~vmFcXQ25FL>h|y?d*nDE_d?}N6kU(0>N{Jd%
zSUOM2LhOV+bA4ltt1Laug<)lF>?+YG#^aeP5-E%;US+kejU!LNWSmN6g*J9siNe^t
zkyYp#x17vGs!i`W%SGI6^WeTFWi6Bk!5PL2LyzAPbqi+yJlK0Ueh$Ctv2ISp_(_>I
zQWUx#H$|qWD&gWv+a1So2Ie>(RSQT1lZ)q&s=$k{KL$alPlxdJsZIJYeg>oZ1nenZ
z%%-7^b?fRh1Vxh>y<jc5q;QLLKeUt&R)w`x0}vrqAEAyRuf%Q8%y1RL>Q-<;%|H;Q
zJ_Y$dk2V;P-_GOjpsdNDYcjyI`gOUh?G|W*x^JHW2{Wf<+~W3Ic1YN|>VHE0pRMbE
zNM8JA6YZY%)h`q%qhz_QJ?^w*#n6fjV97#4kQ)xGURy`xXV`f}3Y)`O*f-=DrX~tw
zRq({f^3H+E1P^o><YmHxB$$9);SpeYgG4Xo566K%5$kzXiA2@7V*-C0UCKmfX_DuQ
zU@8is5-s@sU{N-JW)Wz$z@=Q|LW>~N_k$9SQuC}90Wasp+G`=^!TQOCeh1M9<x$rl
zTHqUkG`;U$rJ~Znw%P(~Xs;@V=qV(`Q1M|I`>Qf4k#H>Q1|&A53=q0UZvaj{{oGPt
z;DLbn_ZjDayeAi`Yzl5%d7PJ}GPbN6X?lA}r5kt}Q*-Tcs<W5kM^#So!G-i7+=_1g
zhxYDhot8pwR!JeO9Y38nbL+juSE|~^RbQeAQ0$<%gW@iVD@;4BW7U5oOWx$-8-%|`
O7KhZg`vc$cum1~XJ4#Xj

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

literal 1400
zcmZ9LJCEEp5XVXCxsS6icAO?J*+l>a#_r_+11SO{fgK}h4ncgu!fFJq$lKLglw^wX
zdKWquIk!eqq;QequJl)8n<`%+Rc55U_+kqDYdE52NY0PR-rkTvyYnbaesKu-3kO%5
z1%q#)*FS@B!f8$<jVMK%<t$=+#BJ`pqLIa2?!6+B&3!(Aw*xbVxhuWMlYZpOK{SxV
zXedX~NRFd1L|~6eIQ|>rl8~BF96uMT&dMT=kB(E!d)ZtteCQ9L*S~^r%1KU6ElpSK
z+-m6sJ+(XAZtV+Nf2rxYgBB$%Q(tSBvzDGQO0?HfZk@5;f>WopR(?xb2Uq{vqGSd;
zvf()cyV(DV)XM`xyXOfg#CZvE+_P@yux{^2QCP`#f2J~>6^kHE(xsS8CWfu&#?H4g
zc}t^FTFOd^8n?A|9+ri;9S+R(OK)6d>C;>oR@TO@61_AY&s32}VO;Sdt95N0`4n8n
zsZ>^IW0#dEjLjQag|2bS`AVeP3{J9K#NBTmoZ-Bzg~Bs~;uMCSyd~-;jQ+VdU6xWz
zb+Z)Hhh^GGQRsTw6q#PAgo}69;WUmjaL4ha+L%$dvv>{r6d1MM2O-p_V|a%28t8<o
zTi{FaL@pcJSj4VqV=y#X(R0?43kt_ak3vg%;8j>yg$#yNVdQSDy?h8mGw##($MFGp
zY6e1>`Uv!Y8EtT2pf2N|VC*oVJ4_(6`eS=v+by8iK>%2+oR)Em+ppP-uqz16$YTN!
zJh}?Oj68c|6YXw(rvM)%+b^`ootE@y^>6@U7D6&3PaxW<_0oFwrhgxh15(%=;$pu9
z$S^fmxN-%zk8JN8t4#1fmqA`8JV=5$XirIiRSpupl|P;YdMS3}suGE+@sBxtZFDIU
zoux^hZ-Rv=gi5sFcY{sY0HH;o)dr_>kqa$?Oy3Pk2&L9pEdpMyi(S@2tb^Tc4E>I!
z_ll+VV6}ibEYb|Vf02qx1L6wn9NK*ykrj0Vr%~~KQHOm|l}I?2vBpXRQfy2a;B*L3
z4FRygQXhjKN&g|^9LV?NMwLy$jVn*`vQ);FbtBE-K~m`kZpgx1`!3blbMccZ7kKYN
zdK~UWH~xeCaI)K$LW=rLA-Ww+T{d&;%H(&Z`UGcvit-uC=O_WnZ4|s<SEM7?|3;R)
U$;ExV3N?~BroKHK`Hp}6UpOyG&Hw-a

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

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

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

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

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

literal 167
zcmWIL<>g`kf~^UPiK0OIF^Gc<7=auIATH(r5-AK(3@MDk44O<;tOk0PdIo-)jJLSs
z<I7TuiZk=`;^S8`6fptSfr(${&Q>v@#XzZ;lG2RS7?=Fy(%jU%lH!=syv&mHqQsO`
d1j{G}YKC4x<t+}I-29Z%oK!oI<)49=0RZYhDn$SQ

diff --git a/unitgrade2/__pycache__/version.cpython-39.pyc b/unitgrade2/__pycache__/version.cpython-39.pyc
deleted file mode 100644
index 613bef2848d43d5e78803c81d3d366c27a5e2c62..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 164
zcmYe~<>g`k0wp)iL{T997{oyaj6jY95EpX*i4=w?h7`tN22G|aRs%gtJp(^Y##`L+
z@nxw+#hLke@$oAeikN`vz{D>T{fzwFRQ;0Dj8uJ>{N&Qy)Vz{n{nEV5lJug)lvD)E
bNFQo|UP0w84x8Nkl+v73JCMzvftUdR<gh2T

diff --git a/unitgrade2/unitgrade/ListQuestion.pkl b/unitgrade2/unitgrade/ListQuestion.pkl
deleted file mode 100644
index b201d4b453d94b66ed44ac821d72534a90b09811..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 466
zcmZo*nR=X&0Ss!VX!Mx*WEPhMmZlb$Waj7ThK2wc&WXjTx^PB*QdVkmiB$<uB0e*(
zBsD#?sMyMIO6(L3Z)R^MZ^l$IjW7Zk(Zi8goRU_Yn36W7hsnrzN@@=evU{fV@S@l|
z#halW$>t393=VHbun2}hAi1_FARn@pWR~QlPU#T<8KnU8f}Wn<lpdCn%-qx|?)D2)
z7k~n!G=sf|2W(++Nl|8Adhryn2^qrfAXyN|5bV*d0D}ljpn&35-QtY=qLL{fGljtt
Wx%ow@un;W5YP3-@UVz>FQau2t#ipwO

diff --git a/unitgrade2/unitgrade2.py b/unitgrade2/unitgrade2.py
deleted file mode 100644
index c094340..0000000
--- a/unitgrade2/unitgrade2.py
+++ /dev/null
@@ -1,891 +0,0 @@
-"""
-git add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade
-
-"""
-# from . import cache_read
-import unittest
-import numpy as np
-import sys
-from io import StringIO
-import collections
-import re
-import threading
-import tqdm
-import time
-import pickle
-import itertools
-import os
-
-myround = lambda x: np.round(x)  # required.
-msum = lambda x: sum(x)
-mfloor = lambda x: np.floor(x)
-
-def setup_dir_by_class(C,base_dir):
-    name = C.__class__.__name__
-    # base_dir = os.path.join(base_dir, name)
-    # if not os.path.isdir(base_dir):
-    #     os.makedirs(base_dir)
-    return base_dir, name
-
-class Hidden:
-    def hide(self):
-        return True
-
-class Logger(object):
-    def __init__(self, buffer):
-        self.terminal = sys.stdout
-        self.log = buffer
-
-    def write(self, message):
-        self.terminal.write(message)
-        self.log.write(message)
-
-    def flush(self):
-        # this flush method is needed for python 3 compatibility.
-        pass
-
-class Capturing(list):
-    def __init__(self, *args, stdout=None, unmute=False, **kwargs):
-        self._stdout = stdout
-        self.unmute = unmute
-        super().__init__(*args, **kwargs)
-
-    def __enter__(self, capture_errors=True): # don't put arguments here.
-        self._stdout = sys.stdout if self._stdout == None else self._stdout
-        self._stringio = StringIO()
-        if self.unmute:
-            sys.stdout = Logger(self._stringio)
-        else:
-            sys.stdout = self._stringio
-
-        if capture_errors:
-            self._sterr = sys.stderr
-            sys.sterr = StringIO() # memory hole it
-        self.capture_errors = capture_errors
-        return self
-
-    def __exit__(self, *args):
-        self.extend(self._stringio.getvalue().splitlines())
-        del self._stringio    # free up some memory
-        sys.stdout = self._stdout
-        if self.capture_errors:
-            sys.sterr = self._sterr
-
-class Capturing2(Capturing):
-    def __exit__(self, *args):
-        lines = self._stringio.getvalue().splitlines()
-        txt = "\n".join(lines)
-        numbers = extract_numbers(txt)
-        self.extend(lines)
-        del self._stringio    # free up some memory
-        sys.stdout = self._stdout
-        if self.capture_errors:
-            sys.sterr = self._sterr
-
-        self.output = txt
-        self.numbers = numbers
-
-
-class QItem(unittest.TestCase):
-    title = None
-    testfun = None
-    tol = 0
-    estimated_time = 0.42
-    _precomputed_payload = None
-    _computed_answer = None # Internal helper to later get results.
-    weight = 1 # the weight of the question.
-
-    def __init__(self, question=None, *args, **kwargs):
-        if self.tol > 0 and self.testfun is None:
-            self.testfun = self.assertL2Relative
-        elif self.testfun is None:
-            self.testfun = self.assertEqual
-
-        self.name = self.__class__.__name__
-        # self._correct_answer_payload = correct_answer_payload
-        self.question = question
-
-        super().__init__(*args, **kwargs)
-        if self.title is None:
-            self.title = self.name
-
-    def _safe_get_title(self):
-        if self._precomputed_title is not None:
-            return self._precomputed_title
-        return self.title
-
-    def assertNorm(self, computed, expected, tol=None):
-        if tol == None:
-            tol = self.tol
-        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )
-        nrm = np.sqrt(np.sum( diff ** 2))
-
-        self.error_computed = nrm
-
-        if nrm > tol:
-            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")
-            print(f"Element-wise differences {diff.tolist()}")
-            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")
-
-    def assertL2(self, computed, expected, tol=None):
-        if tol == None:
-            tol = self.tol
-        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )
-        self.error_computed = np.max(diff)
-
-        if np.max(diff) > tol:
-            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")
-            print(f"Element-wise differences {diff.tolist()}")
-            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")
-
-    def assertL2Relative(self, computed, expected, tol=None):
-        if tol == None:
-            tol = self.tol
-        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )
-        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )
-        self.error_computed = np.max(np.abs(diff))
-        if np.sum(diff > tol) > 0:
-            print(f"Not equal within tolerance {tol}")
-            print(f"Element-wise differences {diff.tolist()}")
-            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")
-
-    def precomputed_payload(self):
-        return self._precomputed_payload
-
-    def precompute_payload(self):
-        # Pre-compute resources to include in tests (useful for getting around rng).
-        pass
-
-    def compute_answer(self, unmute=False):
-        raise NotImplementedError("test code here")
-
-    def test(self, computed, expected):
-        self.testfun(computed, expected)
-
-    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):
-        possible = 1
-        computed = None
-        def show_computed_(computed):
-            print(">>> Your output:")
-            print(computed)
-
-        def show_expected_(expected):
-            print(">>> Expected output (note: may have been processed; read text script):")
-            print(expected)
-
-        correct = self._correct_answer_payload
-        try:
-            if unmute: # Required to not mix together print stuff.
-                print("")
-            computed = self.compute_answer(unmute=unmute)
-        except Exception as e:
-            if not passall:
-                if not silent:
-                    print("\n=================================================================================")
-                    print(f"When trying to run test class '{self.name}' your code threw an error:", e)
-                    show_expected_(correct)
-                    import traceback
-                    print(traceback.format_exc())
-                    print("=================================================================================")
-                return (0, possible)
-
-        if self._computed_answer is None:
-            self._computed_answer = computed
-
-        if show_expected or show_computed:
-            print("\n")
-        if show_expected:
-            show_expected_(correct)
-        if show_computed:
-            show_computed_(computed)
-        try:
-            if not passall:
-                self.test(computed=computed, expected=correct)
-        except Exception as e:
-            if not silent:
-                print("\n=================================================================================")
-                print(f"Test output from test class '{self.name}' does not match expected result. Test error:")
-                print(e)
-                show_computed_(computed)
-                show_expected_(correct)
-            return (0, possible)
-        return (1, possible)
-
-    def score(self):
-        try:
-            self.test()
-        except Exception as e:
-            return 0
-        return 1
-
-class QPrintItem(QItem):
-    def compute_answer_print(self):
-        """
-        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values
-        are send to process_output (see compute_answer below). In other words, the text generated is:
-
-        res = compute_Answer_print()
-        txt = (any terminal output generated above)
-        numbers = (any numbers found in terminal-output txt)
-
-        self.test(process_output(res, txt, numbers), <expected result>)
-
-        :return: Optional values for comparison
-        """
-        raise Exception("Generate output here. The output is passed to self.process_output")
-
-    def process_output(self, res, txt, numbers):
-        return res
-
-    def compute_answer(self, unmute=False):
-        with Capturing(unmute=unmute) as output:
-            res = self.compute_answer_print()
-        s = "\n".join(output)
-        s = rm_progress_bar(s) # Remove progress bar.
-        numbers = extract_numbers(s)
-        self._computed_answer = (res, s, numbers)
-        return self.process_output(res, s, numbers)
-
-class OrderedClassMembers(type):
-    @classmethod
-    def __prepare__(self, name, bases):
-        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 QuestionGroup(metaclass=OrderedClassMembers):
-    title = "Untitled question"
-    partially_scored = False
-    t_init = 0  # Time spend on initialization (placeholder; set this externally).
-    estimated_time = 0.42
-    has_called_init_ = False
-    _name = None
-    _items = None
-
-    @property
-    def items(self):
-        if self._items == None:
-            self._items = []
-            members = [gt for gt in [getattr(self, gt) for gt in self.__ordered__ if gt not in ["__classcell__", "__init__"]] if inspect.isclass(gt) and issubclass(gt, QItem)]
-            for I in members:
-                self._items.append( I(question=self))
-        return self._items
-
-    @items.setter
-    def items(self, value):
-        self._items = value
-
-    @property
-    def name(self):
-        if self._name == None:
-            self._name = self.__class__.__name__
-        return self._name #
-
-    @name.setter
-    def name(self, val):
-        self._name = val
-
-    def init(self):
-        # Can be used to set resources relevant for this question instance.
-        pass
-
-    def init_all_item_questions(self):
-        for item in self.items:
-            if not item.question.has_called_init_:
-                item.question.init()
-                item.question.has_called_init_ = True
-
-
-class Report():
-    title = "report title"
-    version = None
-    questions = []
-    pack_imports = []
-    individual_imports = []
-    nL = 80 # Maximum line width
-
-    @classmethod
-    def reset(cls):
-        for (q,_) in cls.questions:
-            if hasattr(q, 'reset'):
-                q.reset()
-
-    @classmethod
-    def mfile(clc):
-        return inspect.getfile(clc)
-
-    def _file(self):
-        return inspect.getfile(type(self))
-
-    def _import_base_relative(self):
-        root_dir = self.pack_imports[0].__path__._path[0]
-        root_dir = os.path.dirname(root_dir)
-        relative_path = os.path.relpath(self._file(), root_dir)
-        modules = os.path.normpath(relative_path[:-3]).split(os.sep)
-        return root_dir, relative_path, modules
-
-    def __init__(self, strict=False, payload=None):
-        working_directory = os.path.abspath(os.path.dirname(self._file()))
-
-        self.wdir, self.name = setup_dir_by_class(self, working_directory)
-        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")
-        for (q,_) in self.questions:
-            q.nL = self.nL # Set maximum line length.
-
-        if payload is not None:
-            self.set_payload(payload, strict=strict)
-        # else:
-        #     if os.path.isfile(self.computed_answers_file):
-        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)
-        #     else:
-        #         s = f"> Warning: The pre-computed answer file, {os.path.abspath(self.computed_answers_file)} is missing. The framework will NOT work as intended. Reasons may be a broken local installation."
-        #         if strict:
-        #             raise Exception(s)
-        #         else:
-        #             print(s)
-
-    def main(self, verbosity=1):
-        # Run all tests using standard unittest (nothing fancy).
-        import unittest
-        loader = unittest.TestLoader()
-        for q,_ in self.questions:
-            import time
-            start = time.time() # A good proxy for setup time is to
-            suite = loader.loadTestsFromTestCase(q)
-            unittest.TextTestRunner(verbosity=verbosity).run(suite)
-            total = time.time()              - start
-            q.time = total
-
-    def _setup_answers(self):
-        self.main()  # Run all tests in class just to get that out of the way...
-        report_cache = {}
-        for q, _ in self.questions:
-            if hasattr(q, '_save_cache'):
-                q()._save_cache()
-                q._cache['time'] = q.time
-                report_cache[q.__qualname__] = q._cache
-            else:
-                report_cache[q.__qualname__] = {'no cache see _setup_answers in unitgrade2.py':True}
-        return report_cache
-
-    def set_payload(self, payloads, strict=False):
-        for q, _ in self.questions:
-            q._cache = payloads[q.__qualname__]
-
-def rm_progress_bar(txt):
-    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.
-    nlines = []
-    for l in txt.splitlines():
-        pct = l.find("%")
-        ql = False
-        if pct > 0:
-            i = l.find("|", pct+1)
-            if i > 0 and l.find("|", i+1) > 0:
-                ql = True
-        if not ql:
-            nlines.append(l)
-    return "\n".join(nlines)
-
-def extract_numbers(txt):
-    # txt = rm_progress_bar(txt)
-    numeric_const_pattern = '[-+]? (?: (?: \d* \. \d+ ) | (?: \d+ \.? ) )(?: [Ee] [+-]? \d+ ) ?'
-    rx = re.compile(numeric_const_pattern, re.VERBOSE)
-    all = rx.findall(txt)
-    all = [float(a) if ('.' in a or "e" in a) else int(a) for a in all]
-    if len(all) > 500:
-        print(txt)
-        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))
-    return all
-
-class ActiveProgress():
-    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):
-        self.t = t
-        self._running = False
-        self.title = title
-        self.dt = 0.1
-        self.n = int(np.round(self.t / self.dt))
-        self.show_progress_bar = show_progress_bar
-
-        # self.pbar = tqdm.tqdm(total=self.n)
-        if start:
-            self.start()
-
-    def start(self):
-        self._running = True
-        if self.show_progress_bar:
-            self.thread = threading.Thread(target=self.run)
-            self.thread.start()
-        self.time_started = time.time()
-
-    def terminate(self):
-        if not self._running:
-            raise Exception("Stopping a stopped progress bar. ")
-        self._running = False
-        if self.show_progress_bar:
-            self.thread.join()
-        if hasattr(self, 'pbar') and self.pbar is not None:
-            self.pbar.update(1)
-            self.pbar.close()
-            self.pbar=None
-
-        sys.stdout.flush()
-        return time.time() - self.time_started
-
-    def run(self):
-        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,
-                              bar_format='{l_bar}{bar}| [{elapsed}<{remaining}]')  # , unit_scale=dt, unit='seconds'):
-
-        for _ in range(self.n-1): # Don't terminate completely; leave bar at 99% done until terminate.
-            if not self._running:
-                self.pbar.close()
-                self.pbar = None
-                break
-
-            time.sleep(self.dt)
-            self.pbar.update(1)
-
-
-
-from unittest.suite import _isnotsuite
-
-# class MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.
-#     raise Exception("no suite")
-#     pass
-
-def instance_call_stack(instance):
-    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))
-    return s
-
-def get_class_that_defined_method(meth):
-    for cls in inspect.getmro(meth.im_class):
-        if meth.__name__ in cls.__dict__:
-            return cls
-    return None
-
-def caller_name(skip=2):
-    """Get a name of a caller in the format module.class.method
-
-       `skip` specifies how many levels of stack to skip while getting caller
-       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.
-
-       An empty string is returned if skipped levels exceed stack height
-    """
-    stack = inspect.stack()
-    start = 0 + skip
-    if len(stack) < start + 1:
-      return ''
-    parentframe = stack[start][0]
-
-    name = []
-    module = inspect.getmodule(parentframe)
-    # `modname` can be None when frame is executed directly in console
-    # TODO(techtonik): consider using __main__
-    if module:
-        name.append(module.__name__)
-    # detect classname
-    if 'self' in parentframe.f_locals:
-        # I don't know any way to detect call from the object method
-        # XXX: there seems to be no way to detect static method call - it will
-        #      be just a function call
-        name.append(parentframe.f_locals['self'].__class__.__name__)
-    codename = parentframe.f_code.co_name
-    if codename != '<module>':  # top level usually
-        name.append( codename ) # function or a method
-
-    ## Avoid circular refs and frame leaks
-    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack
-    del parentframe, stack
-
-    return ".".join(name)
-
-def get_class_from_frame(fr):
-      import inspect
-      args, _, _, value_dict = inspect.getargvalues(fr)
-      # we check the first parameter for the frame function is
-      # named 'self'
-      if len(args) and args[0] == 'self':
-            # in that case, 'self' will be referenced in value_dict
-            instance = value_dict.get('self', None)
-            if instance:
-                  # return its class
-                  # isinstance(instance, Testing) # is the actual class instance.
-
-                  return getattr(instance, '__class__', None)
-      # return None otherwise
-      return None
-
-from typing import Any
-import inspect, gc
-
-def giveupthefunc():
-    frame = inspect.currentframe()
-    code  = frame.f_code
-    globs = frame.f_globals
-    functype = type(lambda: 0)
-    funcs = []
-    for func in gc.get_referrers(code):
-        if type(func) is functype:
-            if getattr(func, "__code__", None) is code:
-                if getattr(func, "__globals__", None) is globs:
-                    funcs.append(func)
-                    if len(funcs) > 1:
-                        return None
-    return funcs[0] if funcs else None
-
-
-from collections import defaultdict
-
-class UTextResult(unittest.TextTestResult):
-    nL = 80
-    number = -1 # HAcky way to set question number.
-    show_progress_bar = True
-    def __init__(self, stream, descriptions, verbosity):
-        super().__init__(stream, descriptions, verbosity)
-        self.successes = []
-
-    def printErrors(self) -> None:
-        # if self.dots or self.showAll:
-        #     self.stream.writeln()
-        # if hasattr(self, 'cc'):
-        #     self.cc.terminate()
-        # self.cc_terminate(success=False)
-        self.printErrorList('ERROR', self.errors)
-        self.printErrorList('FAIL', self.failures)
-
-    def addError(self, test, err):
-        super(unittest.TextTestResult, self).addFailure(test, err)
-        self.cc_terminate(success=False)
-
-    def addFailure(self, test, err):
-        super(unittest.TextTestResult, self).addFailure(test, err)
-        self.cc_terminate(success=False)
-        # if self.showAll:
-        #     self.stream.writeln("FAIL")
-        # elif self.dots:
-        #     self.stream.write('F')
-        #     self.stream.flush()
-
-    def addSuccess(self, test: unittest.case.TestCase) -> None:
-        # super().addSuccess(test)
-        self.successes.append(test)
-        # super().addSuccess(test)
-        #     hidden = issubclass(item.__class__, Hidden)
-        #     # if not hidden:
-        #     #     print(ss, end="")
-        #     # sys.stdout.flush()
-        #     start = time.time()
-        #
-        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)
-        #     q_[j] = {'w': item.weight, 'possible': possible, 'obtained': current, 'hidden': hidden, 'computed': str(item._computed_answer), 'title': item.title}
-        #     tsecs = np.round(time.time()-start, 2)
-        self.cc_terminate()
-
-
-
-    def cc_terminate(self, success=True):
-        if self.show_progress_bar or True:
-            tsecs = np.round(self.cc.terminate(), 2)
-            sys.stdout.flush()
-            ss = self.item_title_print
-            print(self.item_title_print + ('.' * max(0, self.nL - 4 - len(ss))), end="")
-            # current = 1
-            # possible = 1
-            # current == possible
-            ss = "PASS" if success else "FAILED"
-            if tsecs >= 0.1:
-                ss += " (" + str(tsecs) + " seconds)"
-            print(ss)
-
-
-    def startTest(self, test):
-        # super().startTest(test)
-        j =self.testsRun
-        self.testsRun += 1
-        # print("Starting the test...")
-        # show_progress_bar = True
-        n = UTextResult.number
-
-        item_title = self.getDescription(test)
-        # item_title = item_title.split("\n")[0]
-        item_title = test.shortDescription() # Better for printing (get from cache).
-        if item_title == None:
-            # For unittest framework where getDescription may return None.
-            item_title = self.getDescription(test)
-        # test.countTestCases()
-        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)
-        estimated_time = 10
-        nL = 80
-        #
-        if self.show_progress_bar or True:
-            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)
-        else:
-            print(self.item_title_print + ('.' * max(0, nL - 4 - len(self.item_title_print))), end="")
-
-        self._test = test
-
-    def _setupStdout(self):
-        if self._previousTestClass == None:
-            total_estimated_time = 1
-            if hasattr(self.__class__, 'q_title_print'):
-                q_title_print = self.__class__.q_title_print
-            else:
-                q_title_print = "<unnamed test. See unitgrade.py>"
-
-            # q_title_print = "some printed title..."
-            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)
-            self.cc = cc
-
-    def _restoreStdout(self): # Used when setting up the test.
-        if self._previousTestClass == None:
-            q_time = self.cc.terminate()
-            q_time = np.round(q_time, 2)
-            sys.stdout.flush()
-            print(self.cc.title, end="")
-            # start = 10
-            # q_time = np.round(time.time() - start, 2)
-            nL = 80
-            print(" " * max(0, nL - len(self.cc.title)) + (
-                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")
-            # print("=" * nL)
-
-from unittest.runner import _WritelnDecorator
-from io import StringIO
-
-class UTextTestRunner(unittest.TextTestRunner):
-    def __init__(self, *args, **kwargs):
-        from io import StringIO
-        stream = StringIO()
-        super().__init__(*args, stream=stream, **kwargs)
-
-    def _makeResult(self):
-        # stream = self.stream # not you!
-        stream = sys.stdout
-        stream = _WritelnDecorator(stream)
-        return self.resultclass(stream, self.descriptions, self.verbosity)
-
-def wrapper(foo):
-    def magic(self):
-        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))
-        # print(s)
-        foo(self)
-    magic.__doc__ = foo.__doc__
-    return magic
-
-from functools import update_wrapper, _make_key, RLock
-from collections import namedtuple
-_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
-
-def cache(foo, typed=False):
-    """ Magic cache wrapper
-    https://github.com/python/cpython/blob/main/Lib/functools.py
-    """
-    maxsize = None
-    def wrapper(self, *args, **kwargs):
-        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )
-        # key = (self.cache_id(), '@cache')
-        # if self._cache_contains[key]
-
-        if not self._cache_contains(key):
-            value = foo(self, *args, **kwargs)
-            self._cache_put(key, value)
-        else:
-            value = self._cache_get(key)
-        return value
-    return wrapper
-
-
-class UTestCase(unittest.TestCase):
-    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.
-    _cache = None  # Read-only cache. Ensures method always produce same result.
-    _cache2 = None  # User-written cache.
-
-    def capture(self):
-        return Capturing2(stdout=self._stdout)
-
-    @classmethod
-    def question_title(cls):
-        """ Return the question title """
-        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__
-
-    @classmethod
-    def reset(cls):
-        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")
-        cls._outcome = None
-        cls._cache = None
-        cls._cache2 = None
-
-    def _callSetUp(self):
-        self._stdout = sys.stdout
-        import io
-        sys.stdout = io.StringIO()
-        super().setUp()
-        # print("Setting up...")
-
-    def _callTearDown(self):
-        sys.stdout = self._stdout
-        super().tearDown()
-        # print("asdfsfd")
-
-    def shortDescriptionStandard(self):
-        sd = super().shortDescription()
-        if sd == None:
-            sd = self._testMethodName
-        return sd
-
-    def shortDescription(self):
-        # self._testMethodDoc.strip().splitlines()[0].strip()
-        sd = self.shortDescriptionStandard()
-        title = self._cache_get(  (self.cache_id(), 'title'), sd )
-        return title if title != None else sd
-
-    @property
-    def title(self):
-        return self.shortDescription()
-
-    @title.setter
-    def title(self, value):
-        self._cache_put((self.cache_id(), 'title'), value)
-
-    def _get_outcome(self):
-        if not (self.__class__, '_outcome') or self.__class__._outcome == None:
-            self.__class__._outcome = {}
-        return self.__class__._outcome
-
-    def _callTestMethod(self, testMethod):
-        t = time.time()
-        self._ensure_cache_exists() # Make sure cache is there.
-        if self._testMethodDoc != None:
-            # Ensure the cache is eventually updated with the right docstring.
-            self._cache_put((self.cache_id(), 'title'), self.shortDescriptionStandard() )
-        # Fix temp cache here (for using the @cache decorator)
-        self._cache2[ (self.cache_id(), 'assert') ] = {}
-
-        res = testMethod()
-        elapsed = time.time() - t
-        # self._cache_put( (self.cache_id(), 'title'), self.shortDescription() )
-
-        self._get_outcome()[self.cache_id()] = res
-        self._cache_put( (self.cache_id(), "time"), elapsed)
-
-    # This is my base test class. So what is new about it?
-    def cache_id(self):
-        c = self.__class__.__qualname__
-        m = self._testMethodName
-        return (c,m)
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self._load_cache()
-        self._assert_cache_index = 0
-        # self.cache_indexes = defaultdict(lambda: 0)
-
-    def _ensure_cache_exists(self):
-        if not hasattr(self.__class__, '_cache') or self.__class__._cache == None:
-            self.__class__._cache = dict()
-        if not hasattr(self.__class__, '_cache2') or self.__class__._cache2 == None:
-            self.__class__._cache2 = dict()
-
-    def _cache_get(self, key, default=None):
-        self._ensure_cache_exists()
-        return self.__class__._cache.get(key, default)
-
-    def _cache_put(self, key, value):
-        self._ensure_cache_exists()
-        self.__class__._cache2[key] = value
-
-    def _cache_contains(self, key):
-        self._ensure_cache_exists()
-        return key in self.__class__._cache
-
-    def wrap_assert(self, assert_fun, first, *args, **kwargs):
-        key = (self.cache_id(), 'assert')
-        if not self._cache_contains(key):
-            print("Warning, framework missing", key)
-        cache = self._cache_get(key, {})
-        id = self._assert_cache_index
-        if not id in cache:
-            print("Warning, framework missing cache index", key, "id =", id)
-        _expected = cache.get(id, first)
-        assert_fun(first, _expected, *args, **kwargs)
-        cache[id] = first
-        self._cache_put(key, cache)
-        self._assert_cache_index += 1
-
-    def assertEqualC(self, first: Any, msg: Any = ...) -> None:
-        self.wrap_assert(self.assertEqual, first, msg)
-
-    def _cache_file(self):
-        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"
-
-    def _save_cache(self):
-        # get the class name (i.e. what to save to).
-        cfile = self._cache_file()
-        if not os.path.isdir(os.path.dirname(cfile)):
-            os.makedirs(os.path.dirname(cfile))
-
-        if hasattr(self.__class__, '_cache2'):
-            with open(cfile, 'wb') as f:
-                pickle.dump(self.__class__._cache2, f)
-
-    # But you can also set cache explicitly.
-    def _load_cache(self):
-        if self._cache != None: # Cache already loaded. We will not load it twice.
-            return
-            # raise Exception("Loaded cache which was already set. What is going on?!")
-        cfile = self._cache_file()
-        # print("Loading cache from", cfile)
-        if os.path.exists(cfile):
-            with open(cfile, 'rb') as f:
-                data = pickle.load(f)
-                self.__class__._cache = data
-        else:
-            print("Warning! data file not found", cfile)
-
-def hide(func):
-    return func
-
-def makeRegisteringDecorator(foreignDecorator):
-    """
-        Returns a copy of foreignDecorator, which is identical in every
-        way(*), except also appends a .decorator property to the callable it
-        spits out.
-    """
-    def newDecorator(func):
-        # Call to newDecorator(method)
-        # Exactly like old decorator, but output keeps track of what decorated it
-        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done
-        R.decorator = newDecorator  # keep track of decorator
-        # R.original = func         # might as well keep track of everything!
-        return R
-
-    newDecorator.__name__ = foreignDecorator.__name__
-    newDecorator.__doc__ = foreignDecorator.__doc__
-    # (*)We can be somewhat "hygienic", but newDecorator still isn't signature-preserving, i.e. you will not be able to get a runtime list of parameters. For that, you need hackish libraries...but in this case, the only argument is func, so it's not a big issue
-    return newDecorator
-
-hide = makeRegisteringDecorator(hide)
-
-def methodsWithDecorator(cls, decorator):
-    """
-        Returns all methods in CLS with DECORATOR as the
-        outermost decorator.
-
-        DECORATOR must be a "registering decorator"; one
-        can make any decorator "registering" via the
-        makeRegisteringDecorator function.
-
-        import inspect
-        ls = list(methodsWithDecorator(GeneratorQuestion, deco))
-        for f in ls:
-            print(inspect.getsourcelines(f) ) # How to get all hidden questions.
-    """
-    for maybeDecorated in cls.__dict__.values():
-        if hasattr(maybeDecorated, 'decorator'):
-            if maybeDecorated.decorator == decorator:
-                print(maybeDecorated)
-                yield maybeDecorated
-
diff --git a/unitgrade2/version.py b/unitgrade2/version.py
deleted file mode 100644
index acb984f..0000000
--- a/unitgrade2/version.py
+++ /dev/null
@@ -1 +0,0 @@
-__version__ = "0.9.0"
\ No newline at end of file
-- 
GitLab