From acc45dbea61cd2587c5fd4c9db77d036edc61672 Mon Sep 17 00:00:00 2001
From: Tue Herlau <tuhe@dtu.dk>
Date: Thu, 2 Sep 2021 14:40:53 +0200
Subject: [PATCH] Updates

---
 LICENSE                                       |  19 +
 README.md                                     |  40 +-
 autolab/__pycache__/autolab.cpython-38.pyc    | Bin 5899 -> 0 bytes
 autolab/report_autolab.py                     |   0
 build.md                                      |  18 +
 cs202courseware/ascimenu.py                   |  43 ++
 cs202courseware/ug2report1.py                 |  14 +-
 cs202courseware/ug2report1_nohidden.py        |  13 +-
 dist/unitgrade-devel-0.0.1.tar.gz             | Bin 0 -> 17133 bytes
 dist/unitgrade_devel-0.0.1-py3-none-any.whl   | Bin 0 -> 18848 bytes
 .../docker_tango_python/Dockerfile            |   0
 .../docker_tango_python/requirements.txt      |   1 +
 .../unitgrade-docker/Dockerfile               |   4 +-
 .../home/cs103/Report3_handin_5_of_30.token   | Bin 0 -> 113733 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 922 -> 923 bytes
 .../report3_complete_grade.cpython-38.pyc     | Bin 0 -> 50864 bytes
 .../unitgrade-docker/home}/cs103/homework1.py |   0
 .../unitgrade-docker/home}/cs103/report3.py   |   6 +-
 .../home/cs103/report3_complete_grade.py      | 338 ++++++++++++
 .../home/cs103/report3_grade.py               | 340 ++++++++++++
 .../unitgrade-docker/requirements.txt         |   1 +
 .../unitgrade-docker/tmp/cs103/homework1.py   |  21 +
 .../unitgrade-docker/tmp/cs103/report3.py     |  29 +
 .../tmp/cs103/report3_complete_grade.py       | 338 ++++++++++++
 .../tmp/cs103/report3_grade.py                | 340 ++++++++++++
 examples/02471/instructor/02471/report1.py    |   2 +-
 examples/02631/instructor/programs/.coverage  | Bin 0 -> 53248 bytes
 .../__pycache__/looping.cpython-38.pyc        | Bin 0 -> 2019 bytes
 .../__pycache__/report1intro.cpython-38.pyc   | Bin 0 -> 7198 bytes
 examples/02631/instructor/programs/deploy.py  |  62 +++
 examples/02631/instructor/programs/looping.py |  64 +++
 .../02631/instructor/programs/report1intro.py | 139 +++++
 .../instructor/programs/report1intro_grade.py | 337 ++++++++++++
 .../programs/unitgrade/Bacteria.pkl           | Bin 0 -> 2050 bytes
 .../programs/unitgrade/ClusterAnalysis.pkl    | Bin 0 -> 763 bytes
 .../programs/unitgrade/FermentationRate.pkl   | Bin 0 -> 618 bytes
 .../programs/unitgrade/RemoveIncomplete.pkl   | Bin 0 -> 1444 bytes
 examples/02631/students/programs/.coverage    | Bin 0 -> 53248 bytes
 .../__pycache__/looping.cpython-38.pyc        | Bin 0 -> 2019 bytes
 .../__pycache__/report1intro.cpython-38.pyc   | Bin 0 -> 7198 bytes
 examples/02631/students/programs/looping.py   |  62 +++
 .../02631/students/programs/report1intro.py   | 142 +++++
 .../students/programs/report1intro_grade.py   | 339 ++++++++++++
 .../students/programs/unitgrade/Bacteria.pkl  | Bin 0 -> 2050 bytes
 .../programs/unitgrade/ClusterAnalysis.pkl    | Bin 0 -> 763 bytes
 .../programs/unitgrade/FermentationRate.pkl   | Bin 0 -> 618 bytes
 .../programs/unitgrade/RemoveIncomplete.pkl   | Bin 0 -> 1444 bytes
 examples/autolab_example/autolab_example.py   |   4 +-
 examples/autolab_example/tmp/cs101/cs101.yml  |   6 +-
 .../tmp/cs101/src/driver_python.py            |   6 +-
 .../tmp/cs101/src/report1_grade.py            |   2 +-
 .../tmp/cs102/src/driver_python.py            |   4 +-
 .../tmp/cs103/src/driver_python.py            |   4 +-
 .../example_docker/instructor/cs103/.coverage | Bin 0 -> 53248 bytes
 .../cs103/Report3_handin_25_of_30.token       | Bin 0 -> 117485 bytes
 .../cs103/Report3_handin_30_of_30.token       | Bin 0 -> 117467 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 833 -> 833 bytes
 .../cs103/__pycache__/report3.cpython-38.pyc  | Bin 1384 -> 1384 bytes
 .../report3_complete.cpython-38.pyc           | Bin 1748 -> 1737 bytes
 .../example_docker/instructor/cs103/deploy.py |  18 +-
 .../instructor/cs103/report3.py               |   6 +-
 .../instructor/cs103/report3_complete.py      |   4 +-
 .../cs103/report3_complete_grade.py           |  69 ++-
 .../instructor/cs103/report3_grade.py         |  69 ++-
 .../cs103/unitgrade/AutomaticPass.pkl         | Bin 93 -> 4 bytes
 .../instructor/cs103/unitgrade/Week1.pkl      | Bin 87 -> 62 bytes
 .../tmp/cs103/Report3_handin_5_of_30.token    | Bin 128198 -> 0 bytes
 .../tmp/cs103/report3_complete_grade.py       | 345 ------------
 .../tmp/cs103/report3_grade.py                | 347 ------------
 examples/example_docker/run_all_docker.py     |  57 ++
 .../example_docker/students/cs103/.coverage   | Bin 0 -> 53248 bytes
 .../cs103/Report3_handin_10_of_30.token       | Bin 65286 -> 57954 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 992 -> 992 bytes
 .../__pycache__/homework1.cpython-39.pyc      | Bin 833 -> 833 bytes
 .../cs103/__pycache__/report3.cpython-38.pyc  | Bin 1384 -> 1384 bytes
 .../report3_complete.cpython-38.pyc           | Bin 1748 -> 1748 bytes
 .../report3_complete.cpython-39.pyc           | Bin 1246 -> 1764 bytes
 .../report3_complete_grade.cpython-39.pyc}    | Bin 57824 -> 57973 bytes
 .../__pycache__/report3_grade.cpython-38.pyc  | Bin 57968 -> 50620 bytes
 .../example_docker/students/cs103/report3.py  |   6 +-
 .../students/cs103/report3_grade.py           |  69 ++-
 .../cs103/unitgrade/AutomaticPass.pkl         | Bin 93 -> 4 bytes
 .../students/cs103/unitgrade/Week1.pkl        | Bin 87 -> 62 bytes
 .../Report1Flat_handin_10_of_10.token         | Bin 0 -> 65761 bytes
 .../__pycache__/deploy.cpython-38.pyc         | Bin 0 -> 581 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 0 -> 835 bytes
 .../__pycache__/report1flat.cpython-38.pyc    | Bin 0 -> 1204 bytes
 .../instructor/cs101flat/deploy.py            |  15 +
 .../instructor/cs101flat/homework1.py         |  16 +
 .../instructor/cs101flat/report1flat.py       |  24 +
 .../instructor/cs101flat/report1flat_grade.py | 349 ++++++++++++
 .../Report1Flat_handin_0_of_10.token          | Bin 0 -> 65468 bytes
 .../__pycache__/deploy.cpython-38.pyc         | Bin 0 -> 581 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 0 -> 994 bytes
 .../__pycache__/report1flat.cpython-38.pyc    | Bin 0 -> 1204 bytes
 .../report1flat_grade.cpython-38.pyc          | Bin 0 -> 57893 bytes
 .../students/cs101flat/homework1.py           |  21 +
 .../students/cs101flat/report1flat.py         |  27 +
 .../students/cs101flat/report1flat_grade.py   | 351 ++++++++++++
 .../instructor/cs102/.coverage                | Bin 0 -> 53248 bytes
 .../cs102/Report2_handin_10_of_18.token       | Bin 80985 -> 0 bytes
 .../cs102/Report2_handin_13_of_18.token       | Bin 0 -> 60507 bytes
 .../cs102/Report2_handin_18_of_18.token       | Bin 80175 -> 61089 bytes
 .../cs102/Report2_handin_28_of_28.token       | Bin 81409 -> 0 bytes
 .../cs102/Report2_handin_5_of_18.token        | Bin 78385 -> 0 bytes
 .../cs102/Report2_handin_5_of_28.token        | Bin 80005 -> 0 bytes
 .../cs102/__pycache__/deploy.cpython-38.pyc   | Bin 0 -> 760 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 836 -> 836 bytes
 .../__pycache__/report2_grade.cpython-38.pyc  | Bin 65513 -> 59749 bytes
 .../instructor/cs102/deploy.py                |   6 +-
 .../instructor/cs102/report2.py               |  16 +-
 .../instructor/cs102/report2_grade.py         | 182 +------
 .../instructor/cs102/unitgrade/Question2.pkl  | Bin 384 -> 360 bytes
 .../instructor/cs102/unitgrade/Week1.pkl      | Bin 215 -> 101 bytes
 .../students/cs102/.coverage                  | Bin 0 -> 53248 bytes
 .../cs102/Report2_handin_0_of_18.token        | Bin 79868 -> 0 bytes
 .../cs102/__pycache__/deploy.cpython-38.pyc   | Bin 0 -> 760 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 995 -> 836 bytes
 .../cs102/__pycache__/report2.cpython-38.pyc  | Bin 2048 -> 2165 bytes
 .../__pycache__/report2_grade.cpython-38.pyc  | Bin 65631 -> 59749 bytes
 .../students/cs102/report2.py                 |  16 +-
 .../students/cs102/report2_grade.py           | 182 +------
 .../students/cs102/unitgrade/Question2.pkl    | Bin 384 -> 360 bytes
 .../students/cs102/unitgrade/Week1.pkl        | Bin 215 -> 101 bytes
 .../instructor/cs105/.coverage                | Bin 0 -> 53248 bytes
 .../Report1Jupyter_handin_18_of_18.token      | Bin 0 -> 58736 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 0 -> 187 bytes
 .../cs105/__pycache__/report5.cpython-38.pyc  | Bin 0 -> 2312 bytes
 .../cs105/__pycache__/week2.cpython-38.pyc    | Bin 0 -> 466 bytes
 .../instructor/cs105/deploy.py                |  15 +
 .../instructor/cs105/homework1.py             |   1 +
 .../instructor/cs105/report5.py               |  49 ++
 .../instructor/cs105/report5_grade.py         | 336 ++++++++++++
 .../instructor/cs105/unitgrade/Question2.pkl  | Bin 0 -> 58 bytes
 .../instructor/cs105/unitgrade/Week1.pkl      |   1 +
 .../instructor/cs105}/week2.ipynb             |   0
 .../example_jupyter/students/cs105/.coverage  | Bin 0 -> 53248 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 0 -> 187 bytes
 .../cs105/__pycache__/report5.cpython-38.pyc  | Bin 0 -> 2312 bytes
 .../cs105/__pycache__/week2.cpython-38.pyc    | Bin 0 -> 466 bytes
 .../students/cs105/homework1.py               |   4 +
 .../example_jupyter/students/cs105/report5.py |  52 ++
 .../students/cs105/report5_grade.py           | 338 ++++++++++++
 .../students/cs105/unitgrade/Question2.pkl    | Bin 0 -> 58 bytes
 .../students/cs105/unitgrade/Week1.pkl        |   1 +
 .../students/cs105/week2.ipynb                |  69 +++
 .../cs101/Report1_handin_10_of_10.token       | Bin 77365 -> 58016 bytes
 .../cs101/__pycache__/deploy.cpython-38.pyc   | Bin 0 -> 911 bytes
 .../__pycache__/report1_grade.cpython-38.pyc  | Bin 63801 -> 57383 bytes
 .../instructor/cs101/deploy.py                |  17 +-
 .../instructor/cs101/report1.py               |   4 +-
 .../instructor/cs101/report1_grade.py         | 180 +------
 .../cs101/Report1_handin_0_of_10.token        | Bin 77002 -> 0 bytes
 .../cs101/__pycache__/deploy.cpython-38.pyc   | Bin 0 -> 911 bytes
 .../__pycache__/homework1.cpython-38.pyc      | Bin 994 -> 835 bytes
 .../cs101/__pycache__/report1.cpython-38.pyc  | Bin 1209 -> 1228 bytes
 .../__pycache__/report1_grade.cpython-38.pyc  | Bin 63919 -> 57383 bytes
 .../students/cs101/report1.py                 |   5 +-
 .../students/cs101/report1_grade.py           | 180 +------
 pyproject.toml                                |   6 +
 pytransform/__init__.py                       | 454 ----------------
 .../__pycache__/__init__.cpython-36.pyc       | Bin 11679 -> 0 bytes
 .../__pycache__/__init__.cpython-38.pyc       | Bin 11349 -> 0 bytes
 pytransform/_pytransform.dll                  | Bin 1368590 -> 0 bytes
 setup.py                                      |  49 ++
 src/unitgrade_devel.egg-info/PKG-INFO         | 317 +++++++++++
 src/unitgrade_devel.egg-info/SOURCES.txt      |  18 +
 .../dependency_links.txt                      |   1 +
 src/unitgrade_devel.egg-info/requires.txt     |   9 +
 src/unitgrade_devel.egg-info/top_level.txt    |   1 +
 .../unitgrade_private2}/__init__.py           |   1 +
 .../unitgrade_private2/autolab}/__init__.py   |   0
 .../unitgrade_private2/autolab}/autolab.py    |  41 +-
 .../autolab}/lab_template/Makefile            |   0
 .../autolab}/lab_template/autograde-Makefile  |   0
 .../autolab}/lab_template/autograde.tar       | Bin
 .../autolab}/lab_template/hello.rb            |   0
 .../autolab}/lab_template/hello.yml           |   0
 .../autolab}/lab_template/src/Makefile        |   0
 .../lab_template/src/Makefile-handout         |   0
 .../autolab}/lab_template/src/README          |   0
 .../autolab}/lab_template/src/README-handout  |   0
 .../autolab}/lab_template/src/driver.sh       |   0
 .../lab_template/src/driver_python.py         |   4 +-
 .../autolab}/lab_template/src/hello.c         |   0
 .../autolab}/lab_template/src/hello.c-handout |   0
 .../unitgrade_private2}/deployment.py         |   3 +-
 .../unitgrade_private2}/docker_helpers.py     |  83 +--
 .../unitgrade_private2}/example/report0.py    |   0
 .../hidden_create_files.py                    |  18 +-
 .../hidden_gather_upload.py                   |  39 +-
 .../unitgrade_private2}/token_loader.py       |   1 -
 src/unitgrade_private2/version.py             |   1 +
 tutorial/ncode.py                             | 499 ++++++++++++++++++
 tutorial/ncode2.py                            | 363 +++++++++++++
 tutorial/submission_autograder.py             |   5 +
 tutorial/tutorial.token                       |   2 +-
 .../__pycache__/__init__.cpython-36.pyc       | Bin 888 -> 0 bytes
 .../__pycache__/__init__.cpython-38.pyc       | Bin 918 -> 0 bytes
 .../__pycache__/__init__.cpython-39.pyc       | Bin 944 -> 0 bytes
 .../__pycache__/deployment.cpython-38.pyc     | Bin 1392 -> 0 bytes
 .../__pycache__/deployment.cpython-39.pyc     | Bin 1425 -> 0 bytes
 .../__pycache__/docker_helpers.cpython-38.pyc | Bin 3165 -> 0 bytes
 .../__pycache__/docker_helpers.cpython-39.pyc | Bin 3217 -> 0 bytes
 .../hidden_create_files.cpython-36.pyc        | Bin 3954 -> 0 bytes
 .../hidden_create_files.cpython-38.pyc        | Bin 4588 -> 0 bytes
 .../hidden_create_files.cpython-39.pyc        | Bin 4665 -> 0 bytes
 .../hidden_gather_upload.cpython-36.pyc       | Bin 2775 -> 0 bytes
 .../hidden_gather_upload.cpython-38.pyc       | Bin 4107 -> 0 bytes
 .../hidden_gather_upload.cpython-39.pyc       | Bin 4210 -> 0 bytes
 .../__pycache__/token_loader.cpython-38.pyc   | Bin 978 -> 0 bytes
 .../__pycache__/__init__.cpython-38.pyc       | Bin 181 -> 0 bytes
 .../codejudge_example/codejudge_sum.py        |  35 --
 .../codejudge_example/sumfac.py               |   6 -
 214 files changed, 6013 insertions(+), 2128 deletions(-)
 create mode 100644 LICENSE
 delete mode 100644 autolab/__pycache__/autolab.cpython-38.pyc
 delete mode 100644 autolab/report_autolab.py
 create mode 100644 build.md
 create mode 100644 cs202courseware/ascimenu.py
 create mode 100644 dist/unitgrade-devel-0.0.1.tar.gz
 create mode 100644 dist/unitgrade_devel-0.0.1-py3-none-any.whl
 rename {autolab => docker_images}/docker_tango_python/Dockerfile (100%)
 rename {autolab => docker_images}/docker_tango_python/requirements.txt (86%)
 rename {examples/example_docker/instructor => docker_images}/unitgrade-docker/Dockerfile (93%)
 create mode 100644 docker_images/unitgrade-docker/home/cs103/Report3_handin_5_of_30.token
 rename {examples/example_docker/instructor/unitgrade-docker/tmp => docker_images/unitgrade-docker/home}/cs103/__pycache__/homework1.cpython-38.pyc (73%)
 create mode 100644 docker_images/unitgrade-docker/home/cs103/__pycache__/report3_complete_grade.cpython-38.pyc
 rename {examples/example_docker/instructor/unitgrade-docker/tmp => docker_images/unitgrade-docker/home}/cs103/homework1.py (100%)
 rename {examples/example_docker/instructor/unitgrade-docker/tmp => docker_images/unitgrade-docker/home}/cs103/report3.py (74%)
 create mode 100644 docker_images/unitgrade-docker/home/cs103/report3_complete_grade.py
 create mode 100644 docker_images/unitgrade-docker/home/cs103/report3_grade.py
 rename {examples/example_docker/instructor => docker_images}/unitgrade-docker/requirements.txt (86%)
 create mode 100644 docker_images/unitgrade-docker/tmp/cs103/homework1.py
 create mode 100644 docker_images/unitgrade-docker/tmp/cs103/report3.py
 create mode 100644 docker_images/unitgrade-docker/tmp/cs103/report3_complete_grade.py
 create mode 100644 docker_images/unitgrade-docker/tmp/cs103/report3_grade.py
 create mode 100644 examples/02631/instructor/programs/.coverage
 create mode 100644 examples/02631/instructor/programs/__pycache__/looping.cpython-38.pyc
 create mode 100644 examples/02631/instructor/programs/__pycache__/report1intro.cpython-38.pyc
 create mode 100644 examples/02631/instructor/programs/deploy.py
 create mode 100644 examples/02631/instructor/programs/looping.py
 create mode 100644 examples/02631/instructor/programs/report1intro.py
 create mode 100644 examples/02631/instructor/programs/report1intro_grade.py
 create mode 100644 examples/02631/instructor/programs/unitgrade/Bacteria.pkl
 create mode 100644 examples/02631/instructor/programs/unitgrade/ClusterAnalysis.pkl
 create mode 100644 examples/02631/instructor/programs/unitgrade/FermentationRate.pkl
 create mode 100644 examples/02631/instructor/programs/unitgrade/RemoveIncomplete.pkl
 create mode 100644 examples/02631/students/programs/.coverage
 create mode 100644 examples/02631/students/programs/__pycache__/looping.cpython-38.pyc
 create mode 100644 examples/02631/students/programs/__pycache__/report1intro.cpython-38.pyc
 create mode 100644 examples/02631/students/programs/looping.py
 create mode 100644 examples/02631/students/programs/report1intro.py
 create mode 100644 examples/02631/students/programs/report1intro_grade.py
 create mode 100644 examples/02631/students/programs/unitgrade/Bacteria.pkl
 create mode 100644 examples/02631/students/programs/unitgrade/ClusterAnalysis.pkl
 create mode 100644 examples/02631/students/programs/unitgrade/FermentationRate.pkl
 create mode 100644 examples/02631/students/programs/unitgrade/RemoveIncomplete.pkl
 create mode 100644 examples/example_docker/instructor/cs103/.coverage
 create mode 100644 examples/example_docker/instructor/cs103/Report3_handin_25_of_30.token
 create mode 100644 examples/example_docker/instructor/cs103/Report3_handin_30_of_30.token
 delete mode 100644 examples/example_docker/instructor/unitgrade-docker/tmp/cs103/Report3_handin_5_of_30.token
 delete mode 100644 examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3_complete_grade.py
 delete mode 100644 examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3_grade.py
 create mode 100644 examples/example_docker/run_all_docker.py
 create mode 100644 examples/example_docker/students/cs103/.coverage
 rename examples/example_docker/{instructor/unitgrade-docker/tmp/cs103/__pycache__/report3_complete_grade.cpython-38.pyc => students/cs103/__pycache__/report3_complete_grade.cpython-39.pyc} (90%)
 create mode 100644 examples/example_flat/instructor/cs101flat/Report1Flat_handin_10_of_10.token
 create mode 100644 examples/example_flat/instructor/cs101flat/__pycache__/deploy.cpython-38.pyc
 create mode 100644 examples/example_flat/instructor/cs101flat/__pycache__/homework1.cpython-38.pyc
 create mode 100644 examples/example_flat/instructor/cs101flat/__pycache__/report1flat.cpython-38.pyc
 create mode 100644 examples/example_flat/instructor/cs101flat/deploy.py
 create mode 100644 examples/example_flat/instructor/cs101flat/homework1.py
 create mode 100644 examples/example_flat/instructor/cs101flat/report1flat.py
 create mode 100644 examples/example_flat/instructor/cs101flat/report1flat_grade.py
 create mode 100644 examples/example_flat/students/cs101flat/Report1Flat_handin_0_of_10.token
 create mode 100644 examples/example_flat/students/cs101flat/__pycache__/deploy.cpython-38.pyc
 create mode 100644 examples/example_flat/students/cs101flat/__pycache__/homework1.cpython-38.pyc
 create mode 100644 examples/example_flat/students/cs101flat/__pycache__/report1flat.cpython-38.pyc
 create mode 100644 examples/example_flat/students/cs101flat/__pycache__/report1flat_grade.cpython-38.pyc
 create mode 100644 examples/example_flat/students/cs101flat/homework1.py
 create mode 100644 examples/example_flat/students/cs101flat/report1flat.py
 create mode 100644 examples/example_flat/students/cs101flat/report1flat_grade.py
 create mode 100644 examples/example_framework/instructor/cs102/.coverage
 delete mode 100644 examples/example_framework/instructor/cs102/Report2_handin_10_of_18.token
 create mode 100644 examples/example_framework/instructor/cs102/Report2_handin_13_of_18.token
 delete mode 100644 examples/example_framework/instructor/cs102/Report2_handin_28_of_28.token
 delete mode 100644 examples/example_framework/instructor/cs102/Report2_handin_5_of_18.token
 delete mode 100644 examples/example_framework/instructor/cs102/Report2_handin_5_of_28.token
 create mode 100644 examples/example_framework/instructor/cs102/__pycache__/deploy.cpython-38.pyc
 create mode 100644 examples/example_framework/students/cs102/.coverage
 delete mode 100644 examples/example_framework/students/cs102/Report2_handin_0_of_18.token
 create mode 100644 examples/example_framework/students/cs102/__pycache__/deploy.cpython-38.pyc
 create mode 100644 examples/example_jupyter/instructor/cs105/.coverage
 create mode 100644 examples/example_jupyter/instructor/cs105/Report1Jupyter_handin_18_of_18.token
 create mode 100644 examples/example_jupyter/instructor/cs105/__pycache__/homework1.cpython-38.pyc
 create mode 100644 examples/example_jupyter/instructor/cs105/__pycache__/report5.cpython-38.pyc
 create mode 100644 examples/example_jupyter/instructor/cs105/__pycache__/week2.cpython-38.pyc
 create mode 100644 examples/example_jupyter/instructor/cs105/deploy.py
 create mode 100644 examples/example_jupyter/instructor/cs105/homework1.py
 create mode 100644 examples/example_jupyter/instructor/cs105/report5.py
 create mode 100644 examples/example_jupyter/instructor/cs105/report5_grade.py
 create mode 100644 examples/example_jupyter/instructor/cs105/unitgrade/Question2.pkl
 create mode 100644 examples/example_jupyter/instructor/cs105/unitgrade/Week1.pkl
 rename examples/{02471/instructor/02471/week02 => example_jupyter/instructor/cs105}/week2.ipynb (100%)
 create mode 100644 examples/example_jupyter/students/cs105/.coverage
 create mode 100644 examples/example_jupyter/students/cs105/__pycache__/homework1.cpython-38.pyc
 create mode 100644 examples/example_jupyter/students/cs105/__pycache__/report5.cpython-38.pyc
 create mode 100644 examples/example_jupyter/students/cs105/__pycache__/week2.cpython-38.pyc
 create mode 100644 examples/example_jupyter/students/cs105/homework1.py
 create mode 100644 examples/example_jupyter/students/cs105/report5.py
 create mode 100644 examples/example_jupyter/students/cs105/report5_grade.py
 create mode 100644 examples/example_jupyter/students/cs105/unitgrade/Question2.pkl
 create mode 100644 examples/example_jupyter/students/cs105/unitgrade/Week1.pkl
 create mode 100644 examples/example_jupyter/students/cs105/week2.ipynb
 create mode 100644 examples/example_simplest/instructor/cs101/__pycache__/deploy.cpython-38.pyc
 delete mode 100644 examples/example_simplest/students/cs101/Report1_handin_0_of_10.token
 create mode 100644 examples/example_simplest/students/cs101/__pycache__/deploy.cpython-38.pyc
 create mode 100644 pyproject.toml
 delete mode 100644 pytransform/__init__.py
 delete mode 100644 pytransform/__pycache__/__init__.cpython-36.pyc
 delete mode 100644 pytransform/__pycache__/__init__.cpython-38.pyc
 delete mode 100644 pytransform/_pytransform.dll
 create mode 100644 setup.py
 create mode 100644 src/unitgrade_devel.egg-info/PKG-INFO
 create mode 100644 src/unitgrade_devel.egg-info/SOURCES.txt
 create mode 100644 src/unitgrade_devel.egg-info/dependency_links.txt
 create mode 100644 src/unitgrade_devel.egg-info/requires.txt
 create mode 100644 src/unitgrade_devel.egg-info/top_level.txt
 rename {unitgrade_private2 => src/unitgrade_private2}/__init__.py (97%)
 rename {unitgrade_private2/codejudge_example => src/unitgrade_private2/autolab}/__init__.py (100%)
 rename {autolab => src/unitgrade_private2/autolab}/autolab.py (89%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/Makefile (100%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/autograde-Makefile (100%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/autograde.tar (100%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/hello.rb (100%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/hello.yml (100%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/src/Makefile (100%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/src/Makefile-handout (100%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/src/README (100%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/src/README-handout (100%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/src/driver.sh (100%)
 mode change 100755 => 100644
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/src/driver_python.py (96%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/src/hello.c (100%)
 rename {autolab => src/unitgrade_private2/autolab}/lab_template/src/hello.c-handout (100%)
 rename {unitgrade_private2 => src/unitgrade_private2}/deployment.py (94%)
 rename {unitgrade_private2 => src/unitgrade_private2}/docker_helpers.py (58%)
 rename {unitgrade_private2 => src/unitgrade_private2}/example/report0.py (100%)
 rename {unitgrade_private2 => src/unitgrade_private2}/hidden_create_files.py (91%)
 rename {unitgrade_private2 => src/unitgrade_private2}/hidden_gather_upload.py (85%)
 rename {unitgrade_private2 => src/unitgrade_private2}/token_loader.py (99%)
 create mode 100644 src/unitgrade_private2/version.py
 create mode 100644 tutorial/ncode.py
 create mode 100644 tutorial/ncode2.py
 delete mode 100644 unitgrade_private2/__pycache__/__init__.cpython-36.pyc
 delete mode 100644 unitgrade_private2/__pycache__/__init__.cpython-38.pyc
 delete mode 100644 unitgrade_private2/__pycache__/__init__.cpython-39.pyc
 delete mode 100644 unitgrade_private2/__pycache__/deployment.cpython-38.pyc
 delete mode 100644 unitgrade_private2/__pycache__/deployment.cpython-39.pyc
 delete mode 100644 unitgrade_private2/__pycache__/docker_helpers.cpython-38.pyc
 delete mode 100644 unitgrade_private2/__pycache__/docker_helpers.cpython-39.pyc
 delete mode 100644 unitgrade_private2/__pycache__/hidden_create_files.cpython-36.pyc
 delete mode 100644 unitgrade_private2/__pycache__/hidden_create_files.cpython-38.pyc
 delete mode 100644 unitgrade_private2/__pycache__/hidden_create_files.cpython-39.pyc
 delete mode 100644 unitgrade_private2/__pycache__/hidden_gather_upload.cpython-36.pyc
 delete mode 100644 unitgrade_private2/__pycache__/hidden_gather_upload.cpython-38.pyc
 delete mode 100644 unitgrade_private2/__pycache__/hidden_gather_upload.cpython-39.pyc
 delete mode 100644 unitgrade_private2/__pycache__/token_loader.cpython-38.pyc
 delete mode 100644 unitgrade_private2/codejudge_example/__pycache__/__init__.cpython-38.pyc
 delete mode 100644 unitgrade_private2/codejudge_example/codejudge_sum.py
 delete mode 100644 unitgrade_private2/codejudge_example/sumfac.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/README.md b/README.md
index 410439e..577ac9a 100644
--- a/README.md
+++ b/README.md
@@ -55,41 +55,48 @@ if __name__ == "__main__":
 ```
 ### The test: 
 The test consists of individual problems and a report-class. The tests themselves are just regular Unittest (we will see a slightly smarter idea in a moment). For instance:
+
 ```python
-from homework1 import reverse_list, add
+from looping import reverse_list, add
 import unittest
 
+
 class Week1(unittest.TestCase):
     def test_add(self):
-        self.assertEqual(add(2,2), 4)
+        self.assertEqual(add(2, 2), 4)
         self.assertEqual(add(-100, 5), -95)
 
     def test_reverse(self):
-        self.assertEqual(reverse_list([1,2,3]), [3,2,1])
+        self.assertEqual(reverse_list([1, 2, 3]), [3, 2, 1])
 
 ```
 A number of tests can be collected into a `Report`, which will allow us to assign points to the tests and use the more advanced features of the framework later. A complete, minimal example:
 
 ```python
-from unitgrade2.unitgrade2 import Report
-from unitgrade2.unitgrade_helpers2 import evaluate_report_student
-from homework1 import reverse_list, add
+from src.unitgrade2.unitgrade2 import Report
+from src.unitgrade2 import evaluate_report_student
+from looping import reverse_list, add
 import unittest
 
+
 class Week1(unittest.TestCase):
     def test_add(self):
-        self.assertEqual(add(2,2), 4)
+        self.assertEqual(add(2, 2), 4)
         self.assertEqual(add(-100, 5), -95)
 
     def test_reverse(self):
-        self.assertEqual(reverse_list([1,2,3]), [3,2,1])
+        self.assertEqual(reverse_list([1, 2, 3]), [3, 2, 1])
+
 
 import cs101
+
+
 class Report1(Report):
     title = "CS 101 Report 1"
     questions = [(Week1, 10)]  # Include a single question for 10 credits.
     pack_imports = [cs101]
 
+
 if __name__ == "__main__":
     # Uncomment to simply run everything as a unittest:
     # unittest.main(verbosity=2)
@@ -109,7 +116,7 @@ if __name__ == "__main__":
     setup_grade_file_report(Report1, minify=False, obfuscate=False, execute=False)
 
     # Deploy the files using snipper: https://gitlab.compute.dtu.dk/tuhe/snipper
-    snip_dir.snip_dir(source_dir="../cs101", dest_dir="../../students/cs101", clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py'])
+    snip_dir.snip_dir(source_dir="../programs", dest_dir="../../students/programs", clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py'])
 
 ```
  - The first line creates the `report1_grade.py` script and any additional data files needed by the tests (none in this case)
@@ -193,15 +200,18 @@ also that the students implementations didn't just detect what input was being u
 return the correct answer. To do that you need hidden tests and external validation.
 
 Our new testclass looks like this:
+
 ```python
-from unitgrade2.unitgrade2 import UTestCase, Report, hide
-from unitgrade2.unitgrade_helpers2 import evaluate_report_student
+from src.unitgrade2.unitgrade2 import UTestCase, Report, hide
+from src.unitgrade2 import evaluate_report_student
+
 
 class Week1(UTestCase):
     """ The first question for week 1. """
+
     def test_add(self):
         from cs103.homework1 import add
-        self.assertEqualC(add(2,2))
+        self.assertEqualC(add(2, 2))
         self.assertEqualC(add(-100, 5))
 
     @hide
@@ -209,14 +219,18 @@ class Week1(UTestCase):
         # This is a hidden test. The @hide-decorator will allow unitgrade to remove the test.
         # See the output in the student directory for more information.
         from cs103.homework1 import add
-        self.assertEqualC(add(2,2))
+        self.assertEqualC(add(2, 2))
+
 
 import cs103
+
+
 class Report3(Report):
     title = "CS 101 Report 3"
     questions = [(Week1, 20)]  # Include a single question for 10 credits.
     pack_imports = [cs103]
 
+
 if __name__ == "__main__":
     evaluate_report_student(Report3())
 ```
diff --git a/autolab/__pycache__/autolab.cpython-38.pyc b/autolab/__pycache__/autolab.cpython-38.pyc
deleted file mode 100644
index 86ad4a1d06d4f3267ad22b37b7839b186984db04..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 5899
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
J-Gq$O_iw`C6yE><

diff --git a/autolab/report_autolab.py b/autolab/report_autolab.py
deleted file mode 100644
index e69de29..0000000
diff --git a/build.md b/build.md
new file mode 100644
index 0000000..4ba0737
--- /dev/null
+++ b/build.md
@@ -0,0 +1,18 @@
+# Unitgrade build info
+
+See https://packaging.python.org/tutorials/packaging-projects/
+
+- Build the distribution package using:
+```
+py -m pip install --upgrade build && py -m build
+```
+- Upload to test repo
+```
+py -m pip install --upgrade twine && py -m twine upload --repository testpypi dist/*
+```
+
+### build and upload (to actual pypi; remember the .pypi token. you can find it in personal dtu repo)
+```
+rm -f dists/* && py -m build &&  twine upload dist/*
+```
+
diff --git a/cs202courseware/ascimenu.py b/cs202courseware/ascimenu.py
new file mode 100644
index 0000000..c5f1561
--- /dev/null
+++ b/cs202courseware/ascimenu.py
@@ -0,0 +1,43 @@
+from prompt_toolkit.application import Application
+from prompt_toolkit.application.current import get_app
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.key_binding.bindings.focus import focus_next, focus_previous
+from prompt_toolkit.layout import Dimension, HSplit, Layout, ScrollablePane
+from prompt_toolkit.widgets import Frame, Label, TextArea
+
+print("hello")
+
+z = 234
+def main():
+    # Create a big layout of many text areas, then wrap them in a `ScrollablePane`.
+    root_container = Frame(
+        ScrollablePane(
+            HSplit(
+                [
+                    Frame(TextArea(text=f"label-{i}"), width=Dimension())
+                    for i in range(20)
+                ]
+            )
+        )
+        # ScrollablePane(HSplit([TextArea(text=f"label-{i}") for i in range(20)]))
+    )
+
+    layout = Layout(container=root_container)
+
+    # Key bindings.
+    kb = KeyBindings()
+
+    @kb.add("c-c")
+    def exit(event) -> None:
+        get_app().exit()
+
+    kb.add("down")(focus_next)
+    kb.add("up")(focus_previous)
+
+    # Create and run application.
+    application = Application(layout=layout, key_bindings=kb, full_screen=True)
+    application.run()
+
+
+if __name__ == "__main__":
+    main()
\ No newline at end of file
diff --git a/cs202courseware/ug2report1.py b/cs202courseware/ug2report1.py
index 586a004..e0e7e05 100644
--- a/cs202courseware/ug2report1.py
+++ b/cs202courseware/ug2report1.py
@@ -1,16 +1,13 @@
 # from unitgrade.unitgrade import QuestionGroup, Report, QPrintItem
 # from unitgrade.unitgrade_helpers import evaluate_report_student
 
-from cs202courseware import homework1
-import unittest
-
-from unitgrade2.unitgrade2 import wrapper, UTestCase, cache
+from src.unitgrade2.unitgrade2 import UTestCase, cache
 from unittest import TestCase
 # from unitgrade2.unitgrade2 import cache
-from unitgrade2.unitgrade2 import methodsWithDecorator, hide
+from src.unitgrade2.unitgrade2 import hide
 
 import random
-from cs202courseware.homework1 import reverse_list, my_sum
+from cs202courseware.homework1 import my_sum
 
 class TestPartial(TestCase):
     def test_a(self):
@@ -83,7 +80,7 @@ class ListQuestion(UTestCase):
         """ ccc test_integers-short """
         self.assertEqual(2,2)
 
-from unitgrade2.unitgrade2 import Report
+from src.unitgrade2.unitgrade2 import Report
 
 class Report1(Report):
     title = "CS 202 Report 1"
@@ -97,7 +94,6 @@ class Report1(Report):
     pack_imports = [cs202courseware]  # Include this file in .token file
     a = 234
 
-import coverage
 
 if __name__ == "__main__":
     """
@@ -113,7 +109,7 @@ if __name__ == "__main__":
     #     print(inspect.getsourcelines(f) ) # How to get all hidden questions.
 
 
-    from unitgrade2.unitgrade_helpers2 import evaluate_report_student
+    from src.unitgrade2 import evaluate_report_student
     # cov = coverage.Coverage()
     # cov.start()
 
diff --git a/cs202courseware/ug2report1_nohidden.py b/cs202courseware/ug2report1_nohidden.py
index 180417c..3e94a57 100644
--- a/cs202courseware/ug2report1_nohidden.py
+++ b/cs202courseware/ug2report1_nohidden.py
@@ -1,17 +1,14 @@
 # from unitgrade.unitgrade import QuestionGroup, Report, QPrintItem
 # from unitgrade.unitgrade_helpers import evaluate_report_student
 
-from cs202courseware import homework1
-import unittest
-
-from unitgrade2.unitgrade2 import wrapper, UTestCase, cache
+from src.unitgrade2.unitgrade2 import UTestCase, cache
 # from unitgrade2.unitgrade2 import cache
-from unitgrade2.unitgrade2 import methodsWithDecorator, hide
+from src.unitgrade2.unitgrade2 import methodsWithDecorator, hide
 
 
 
 import random
-from cs101courseware_example.homework1 import reverse_list, my_sum
+from cs101courseware_example.homework1 import my_sum
 
 class GeneratorQuestion(UTestCase):
     def genTest(self, n):
@@ -57,7 +54,7 @@ class ListQuestion(UTestCase):
         """ ccc test_integers-short """
         self.assertEqual(2,2)
 
-from unitgrade2.unitgrade2 import Report
+from src.unitgrade2.unitgrade2 import Report
 
 class Report1(Report):
     title = "CS 202 Report 1"
@@ -103,7 +100,7 @@ if __name__ == "__main__":
     for f in ls:
         print(inspect.getsourcelines(f) ) # How to get all hidden questions.
 
-    from unitgrade2.unitgrade_helpers2 import evaluate_report_student
+    from src.unitgrade2 import evaluate_report_student
 
     evaluate_report_student( Report1() )
 
diff --git a/dist/unitgrade-devel-0.0.1.tar.gz b/dist/unitgrade-devel-0.0.1.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..9a8b82a9d4e5c3c61bd6ced6cace4b2a6bfb40b9
GIT binary patch
literal 17133
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

literal 0
HcmV?d00001

diff --git a/dist/unitgrade_devel-0.0.1-py3-none-any.whl b/dist/unitgrade_devel-0.0.1-py3-none-any.whl
new file mode 100644
index 0000000000000000000000000000000000000000..6e566dfa026e00890940fe2102371f73794be2be
GIT binary patch
literal 18848
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
L0c&9fR}c>XfkJ0l

literal 0
HcmV?d00001

diff --git a/autolab/docker_tango_python/Dockerfile b/docker_images/docker_tango_python/Dockerfile
similarity index 100%
rename from autolab/docker_tango_python/Dockerfile
rename to docker_images/docker_tango_python/Dockerfile
diff --git a/autolab/docker_tango_python/requirements.txt b/docker_images/docker_tango_python/requirements.txt
similarity index 86%
rename from autolab/docker_tango_python/requirements.txt
rename to docker_images/docker_tango_python/requirements.txt
index 9db6120..0a73d68 100644
--- a/autolab/docker_tango_python/requirements.txt
+++ b/docker_images/docker_tango_python/requirements.txt
@@ -4,3 +4,4 @@ jinja2
 tabulate
 compress_pickle
 pyfiglet
+colorama
\ No newline at end of file
diff --git a/examples/example_docker/instructor/unitgrade-docker/Dockerfile b/docker_images/unitgrade-docker/Dockerfile
similarity index 93%
rename from examples/example_docker/instructor/unitgrade-docker/Dockerfile
rename to docker_images/unitgrade-docker/Dockerfile
index 08764b5..98a4007 100644
--- a/examples/example_docker/instructor/unitgrade-docker/Dockerfile
+++ b/docker_images/unitgrade-docker/Dockerfile
@@ -5,7 +5,7 @@ FROM python:3.8-slim-buster
 RUN apt-get -y update
 RUN apt-get -y install git
 
-WORKDIR /app
+WORKDIR /home
 
 # Remember to include requirements.
 COPY requirements.txt requirements.txt
@@ -16,6 +16,6 @@ RUN pip3 install -r requirements.txt
 
 COPY . .
 
-ADD . /app
+ADD . /home
 
 # CMD [ "python3", "app.py"]
diff --git a/docker_images/unitgrade-docker/home/cs103/Report3_handin_5_of_30.token b/docker_images/unitgrade-docker/home/cs103/Report3_handin_5_of_30.token
new file mode 100644
index 0000000000000000000000000000000000000000..a861bfbfbcc029d09e49a0a278598a0e2355ee66
GIT binary patch
literal 113733
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

literal 0
HcmV?d00001

diff --git a/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/__pycache__/homework1.cpython-38.pyc b/docker_images/unitgrade-docker/home/cs103/__pycache__/homework1.cpython-38.pyc
similarity index 73%
rename from examples/example_docker/instructor/unitgrade-docker/tmp/cs103/__pycache__/homework1.cpython-38.pyc
rename to docker_images/unitgrade-docker/home/cs103/__pycache__/homework1.cpython-38.pyc
index 6403436716a672ff6c51a7026fc0edf847aa3213..d57142a7eeb21f6b172586b47613efbfeadc1082 100644
GIT binary patch
delta 32
mcmbQmKAW98l$V!_0SNr&8f@f#&B!L9pOK%Ny7@Qbd`19y%m~l`

delta 31
lcmbQuK8u|@l$V!_0SHY0>1^bF&B!XQpIA_^`48iKMgVn_2&(`9

diff --git a/docker_images/unitgrade-docker/home/cs103/__pycache__/report3_complete_grade.cpython-38.pyc b/docker_images/unitgrade-docker/home/cs103/__pycache__/report3_complete_grade.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..aa3a3187faae8d51a53e55a82bd75e0521299a19
GIT binary patch
literal 50864
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

literal 0
HcmV?d00001

diff --git a/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/homework1.py b/docker_images/unitgrade-docker/home/cs103/homework1.py
similarity index 100%
rename from examples/example_docker/instructor/unitgrade-docker/tmp/cs103/homework1.py
rename to docker_images/unitgrade-docker/home/cs103/homework1.py
diff --git a/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3.py b/docker_images/unitgrade-docker/home/cs103/report3.py
similarity index 74%
rename from examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3.py
rename to docker_images/unitgrade-docker/home/cs103/report3.py
index c97b5a4..f83bb53 100644
--- a/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3.py
+++ b/docker_images/unitgrade-docker/home/cs103/report3.py
@@ -1,8 +1,8 @@
 """
 Example student code. This file is automatically generated from the files in the instructor-directory
 """
-from unitgrade2.unitgrade2 import UTestCase, Report, hide
-from unitgrade2.unitgrade_helpers2 import evaluate_report_student
+from src.unitgrade2.unitgrade2 import UTestCase, Report
+from src.unitgrade2 import evaluate_report_student
 
 class Week1(UTestCase):
     """ The first question for week 1. """
@@ -24,4 +24,6 @@ class Report3(Report):
     pack_imports = [cs103]
 
 if __name__ == "__main__":
+    # from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
+    # gather_upload_to_campusnet(Report3())
     evaluate_report_student(Report3())
diff --git a/docker_images/unitgrade-docker/home/cs103/report3_complete_grade.py b/docker_images/unitgrade-docker/home/cs103/report3_complete_grade.py
new file mode 100644
index 0000000..8ea5f2e
--- /dev/null
+++ b/docker_images/unitgrade-docker/home/cs103/report3_complete_grade.py
@@ -0,0 +1,338 @@
+
+import numpy as np
+from tabulate import tabulate
+from datetime import datetime
+import pyfiglet
+import unittest
+import inspect
+import os
+import argparse
+import time
+
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
+To run all tests in a report: 
+
+> python assignment1_dp.py
+
+To run only question 2 or question 2.1
+
+> python assignment1_dp.py -q 2
+> python assignment1_dp.py -q 2.1
+
+Note this scripts does not grade your report. To grade your report, use:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
+parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
+parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
+parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
+parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
+
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+    args = parser.parse_args()
+    if question is None and args.q is not None:
+        question = args.q
+        if "." in question:
+            question, qitem = [int(v) for v in question.split(".")]
+        else:
+            question = int(question)
+
+    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
+        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
+
+    if unmute is None:
+        unmute = args.unmute
+    if passall is None:
+        passall = args.passall
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+                                          show_tol_err=show_tol_err)
+
+
+    if question is None:
+        print("Provisional evaluation")
+        tabulate(table_data)
+        table = table_data
+        print(tabulate(table))
+        print(" ")
+
+    fr = inspect.getouterframes(inspect.currentframe())[1].filename
+    gfile = os.path.basename(fr)[:-3] + "_grade.py"
+    if os.path.exists(gfile):
+        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
+        print(">>>", gfile)
+        print("In the same manner as you ran this file.")
+
+
+    return results
+
+
+def upack(q):
+    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
+    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
+    h = np.asarray(h)
+    return h[:,0], h[:,1], h[:,2],
+
+class UnitgradeTextRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+class SequentialTestLoader(unittest.TestLoader):
+    def getTestCaseNames(self, testCaseClass):
+        test_names = super().getTestCaseNames(testCaseClass)
+        # testcase_methods = list(testCaseClass.__dict__.keys())
+        ls = []
+        for C in testCaseClass.mro():
+            if issubclass(C, unittest.TestCase):
+                ls = list(C.__dict__.keys()) + ls
+        testcase_methods = ls
+        test_names.sort(key=testcase_methods.index)
+        return test_names
+
+def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
+                    show_progress_bar=True,
+                    show_tol_err=False,
+                    big_header=True):
+
+    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"
+    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
+    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(s, "(use --help for options)" if show_help_flag else "")
+    # print(f"Loaded answers from: ", report.computed_answers_file, "\n")
+    table_data = []
+    t_start = time.time()
+    score = {}
+    loader = SequentialTestLoader()
+
+    for n, (q, w) in enumerate(report.questions):
+        if question is not None and n+1 != question:
+            continue
+        suite = loader.loadTestsFromTestCase(q)
+        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
+        q_title_print = "Question %i: %s"%(n+1, qtitle)
+        print(q_title_print, end="")
+        q.possible = 0
+        q.obtained = 0
+        q_ = {} # Gather score in this class.
+        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)
+
+        possible = res.testsRun
+        obtained = len(res.successes)
+
+        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun
+
+        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0
+        score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle}
+        q.obtained = obtained
+        q.possible = possible
+
+        s1 = f" * q{n+1})   Total"
+        s2 = f" {q.obtained}/{w}"
+        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )
+        print(" ")
+        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])
+
+    ws, possible, obtained = upack(score)
+    possible = int( msum(possible) )
+    obtained = int( msum(obtained) ) # Cast to python int
+    report.possible = possible
+    report.obtained = obtained
+    now = datetime.now()
+    dt_string = now.strftime("%H:%M:%S")
+
+    dt = int(time.time()-t_start)
+    minutes = dt//60
+    seconds = dt - minutes*60
+    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")
+
+    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
+
+
+from tabulate import tabulate
+from datetime import datetime
+import inspect
+import json
+import os
+import bz2
+import pickle
+import os
+
+def bzwrite(json_str, token): # to get around obfuscation issues
+    with getattr(bz2, 'open')(token, "wt") as f:
+        f.write(json_str)
+
+def gather_imports(imp):
+    resources = {}
+    m = imp
+    # for m in pack_imports:
+    # print(f"*** {m.__name__}")
+    f = m.__file__
+    # dn = os.path.dirname(f)
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
+        top_package = os.path.dirname(m.__file__)
+        module_import = True
+    else:
+        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
+        module_import = False
+
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = os.path.dirname(top_package)
+    import zipfile
+    # import strea
+    # zipfile.ZipFile
+    import io
+    # file_like_object = io.BytesIO(my_zip_data)
+    zip_buffer = io.BytesIO()
+    with zipfile.ZipFile(zip_buffer, 'w') as zip:
+        # zip.write()
+        for root, dirs, files in os.walk(top_package):
+            for file in files:
+                if file.endswith(".py"):
+                    fpath = os.path.join(root, file)
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
+                    zip.write(fpath, v)
+
+    resources['zipfile'] = zip_buffer.getvalue()
+    resources['top_package'] = top_package
+    resources['module_import'] = module_import
+    return resources, top_package
+
+    if f.endswith("__init__.py"):
+        for root, dirs, files in os.walk(os.path.dirname(f)):
+            for file in files:
+                if file.endswith(".py"):
+                    # print(file)
+                    # print()
+                    v = os.path.relpath(os.path.join(root, file), top_package)
+                    with open(os.path.join(root, file), 'r') as ff:
+                        resources[v] = ff.read()
+    else:
+        v = os.path.relpath(f, top_package)
+        with open(f, 'r') as ff:
+            resources[v] = ff.read()
+    return resources
+
+import argparse
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
+parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
+
+def gather_upload_to_campusnet(report, output_dir=None):
+    n = report.nL
+    args = parser.parse_args()
+    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
+                                          show_progress_bar=not args.noprogress,
+                                          big_header=not args.autolab)
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
+    # also load the source code of missing files...
+
+    sources = {}
+    print("")
+    if not args.autolab:
+        if len(report.individual_imports) > 0:
+            print("By uploading the .token file, you verify the files:")
+            for m in report.individual_imports:
+                print(">", m.__file__)
+            print("Are created/modified individually by you in agreement with DTUs exam rules")
+            report.pack_imports += report.individual_imports
+
+        if len(report.pack_imports) > 0:
+            print("Including files in upload...")
+            for k, m in enumerate(report.pack_imports):
+                nimp, top_package = gather_imports(m)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
+                nimp['name'] = m.__name__
+                sources[k] = nimp
+                # if len([k for k in nimp if k not in sources]) > 0:
+                print(f" * {m.__name__}")
+                # sources = {**sources, **nimp}
+    results['sources'] = sources
+
+    if output_dir is None:
+        output_dir = os.getcwd()
+
+    payload_out_base = report.__class__.__name__ + "_handin"
+
+    obtain, possible = results['total']
+    vstring = "_v"+report.version if report.version is not None else ""
+
+    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
+    token = os.path.normpath(os.path.join(output_dir, token))
+
+
+    with open(token, 'wb') as f:
+        pickle.dump(results, f)
+
+    if not args.autolab:
+        print(" ")
+        print("To get credit for your results, please upload the single unmodified file: ")
+        print(">", token)
+        # print("To campusnet without any modifications.")
+
+        # print("Now time for some autolab fun")
+
+def source_instantiate(name, report1_source, payload):
+    eval("exec")(report1_source, globals())
+    pl = pickle.loads(bytes.fromhex(payload))
+    report = eval(name)(payload=pl, strict=True)
+    # report.set_payload(pl)
+    return report
+
+
+
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            # print(self.questions)\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                print("q is", q())\n                q()._cache_put(\'time\', q.time) # = q.time\n                report_cache[q.__qualname__] = q._cache2\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            # self._stdout = sys.stdout\n            # sys._stdout = io.StringIO()\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f" * q{n+1})   Total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.normpath(os.path.join(output_dir, token))\n\n\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n    @hide\n    def test_add_hidden(self):\n        # This is a hidden test. The @hide-decorator will allow unitgrade to remove the test.\n        # See the output in the student directory for more information.\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n    @hide\n    def test_hidden_fail(self):\n        self.assertEqual(2,3)\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
+report1_payload = '80049589000000000000007d94288c055765656b31947d942868018c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b047568018c0f746573745f6164645f68696464656e948694680586947d944b004b04738c0474696d6594473fe3b8a400000000758c0d4175746f6d6174696350617373947d94680c473fc45a520000000073752e'
+name="Report3"
+
+report = source_instantiate(name, report1_source, report1_payload)
+output_dir = os.path.dirname(__file__)
+gather_upload_to_campusnet(report, output_dir)
\ No newline at end of file
diff --git a/docker_images/unitgrade-docker/home/cs103/report3_grade.py b/docker_images/unitgrade-docker/home/cs103/report3_grade.py
new file mode 100644
index 0000000..3c64c04
--- /dev/null
+++ b/docker_images/unitgrade-docker/home/cs103/report3_grade.py
@@ -0,0 +1,340 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+import numpy as np
+from tabulate import tabulate
+from datetime import datetime
+import pyfiglet
+import unittest
+import inspect
+import os
+import argparse
+import time
+
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
+To run all tests in a report: 
+
+> python assignment1_dp.py
+
+To run only question 2 or question 2.1
+
+> python assignment1_dp.py -q 2
+> python assignment1_dp.py -q 2.1
+
+Note this scripts does not grade your report. To grade your report, use:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
+parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
+parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
+parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
+parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
+
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+    args = parser.parse_args()
+    if question is None and args.q is not None:
+        question = args.q
+        if "." in question:
+            question, qitem = [int(v) for v in question.split(".")]
+        else:
+            question = int(question)
+
+    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
+        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
+
+    if unmute is None:
+        unmute = args.unmute
+    if passall is None:
+        passall = args.passall
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+                                          show_tol_err=show_tol_err)
+
+
+    if question is None:
+        print("Provisional evaluation")
+        tabulate(table_data)
+        table = table_data
+        print(tabulate(table))
+        print(" ")
+
+    fr = inspect.getouterframes(inspect.currentframe())[1].filename
+    gfile = os.path.basename(fr)[:-3] + "_grade.py"
+    if os.path.exists(gfile):
+        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
+        print(">>>", gfile)
+        print("In the same manner as you ran this file.")
+
+
+    return results
+
+
+def upack(q):
+    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
+    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
+    h = np.asarray(h)
+    return h[:,0], h[:,1], h[:,2],
+
+class UnitgradeTextRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+class SequentialTestLoader(unittest.TestLoader):
+    def getTestCaseNames(self, testCaseClass):
+        test_names = super().getTestCaseNames(testCaseClass)
+        # testcase_methods = list(testCaseClass.__dict__.keys())
+        ls = []
+        for C in testCaseClass.mro():
+            if issubclass(C, unittest.TestCase):
+                ls = list(C.__dict__.keys()) + ls
+        testcase_methods = ls
+        test_names.sort(key=testcase_methods.index)
+        return test_names
+
+def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
+                    show_progress_bar=True,
+                    show_tol_err=False,
+                    big_header=True):
+
+    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"
+    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
+    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(s, "(use --help for options)" if show_help_flag else "")
+    # print(f"Loaded answers from: ", report.computed_answers_file, "\n")
+    table_data = []
+    t_start = time.time()
+    score = {}
+    loader = SequentialTestLoader()
+
+    for n, (q, w) in enumerate(report.questions):
+        if question is not None and n+1 != question:
+            continue
+        suite = loader.loadTestsFromTestCase(q)
+        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
+        q_title_print = "Question %i: %s"%(n+1, qtitle)
+        print(q_title_print, end="")
+        q.possible = 0
+        q.obtained = 0
+        q_ = {} # Gather score in this class.
+        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)
+
+        possible = res.testsRun
+        obtained = len(res.successes)
+
+        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun
+
+        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0
+        score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle}
+        q.obtained = obtained
+        q.possible = possible
+
+        s1 = f" * q{n+1})   Total"
+        s2 = f" {q.obtained}/{w}"
+        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )
+        print(" ")
+        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])
+
+    ws, possible, obtained = upack(score)
+    possible = int( msum(possible) )
+    obtained = int( msum(obtained) ) # Cast to python int
+    report.possible = possible
+    report.obtained = obtained
+    now = datetime.now()
+    dt_string = now.strftime("%H:%M:%S")
+
+    dt = int(time.time()-t_start)
+    minutes = dt//60
+    seconds = dt - minutes*60
+    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")
+
+    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
+
+
+from tabulate import tabulate
+from datetime import datetime
+import inspect
+import json
+import os
+import bz2
+import pickle
+import os
+
+def bzwrite(json_str, token): # to get around obfuscation issues
+    with getattr(bz2, 'open')(token, "wt") as f:
+        f.write(json_str)
+
+def gather_imports(imp):
+    resources = {}
+    m = imp
+    # for m in pack_imports:
+    # print(f"*** {m.__name__}")
+    f = m.__file__
+    # dn = os.path.dirname(f)
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
+        top_package = os.path.dirname(m.__file__)
+        module_import = True
+    else:
+        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
+        module_import = False
+
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = os.path.dirname(top_package)
+    import zipfile
+    # import strea
+    # zipfile.ZipFile
+    import io
+    # file_like_object = io.BytesIO(my_zip_data)
+    zip_buffer = io.BytesIO()
+    with zipfile.ZipFile(zip_buffer, 'w') as zip:
+        # zip.write()
+        for root, dirs, files in os.walk(top_package):
+            for file in files:
+                if file.endswith(".py"):
+                    fpath = os.path.join(root, file)
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
+                    zip.write(fpath, v)
+
+    resources['zipfile'] = zip_buffer.getvalue()
+    resources['top_package'] = top_package
+    resources['module_import'] = module_import
+    return resources, top_package
+
+    if f.endswith("__init__.py"):
+        for root, dirs, files in os.walk(os.path.dirname(f)):
+            for file in files:
+                if file.endswith(".py"):
+                    # print(file)
+                    # print()
+                    v = os.path.relpath(os.path.join(root, file), top_package)
+                    with open(os.path.join(root, file), 'r') as ff:
+                        resources[v] = ff.read()
+    else:
+        v = os.path.relpath(f, top_package)
+        with open(f, 'r') as ff:
+            resources[v] = ff.read()
+    return resources
+
+import argparse
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
+parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
+
+def gather_upload_to_campusnet(report, output_dir=None):
+    n = report.nL
+    args = parser.parse_args()
+    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
+                                          show_progress_bar=not args.noprogress,
+                                          big_header=not args.autolab)
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
+    # also load the source code of missing files...
+
+    sources = {}
+    print("")
+    if not args.autolab:
+        if len(report.individual_imports) > 0:
+            print("By uploading the .token file, you verify the files:")
+            for m in report.individual_imports:
+                print(">", m.__file__)
+            print("Are created/modified individually by you in agreement with DTUs exam rules")
+            report.pack_imports += report.individual_imports
+
+        if len(report.pack_imports) > 0:
+            print("Including files in upload...")
+            for k, m in enumerate(report.pack_imports):
+                nimp, top_package = gather_imports(m)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
+                nimp['name'] = m.__name__
+                sources[k] = nimp
+                # if len([k for k in nimp if k not in sources]) > 0:
+                print(f" * {m.__name__}")
+                # sources = {**sources, **nimp}
+    results['sources'] = sources
+
+    if output_dir is None:
+        output_dir = os.getcwd()
+
+    payload_out_base = report.__class__.__name__ + "_handin"
+
+    obtain, possible = results['total']
+    vstring = "_v"+report.version if report.version is not None else ""
+
+    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
+    token = os.path.normpath(os.path.join(output_dir, token))
+
+
+    with open(token, 'wb') as f:
+        pickle.dump(results, f)
+
+    if not args.autolab:
+        print(" ")
+        print("To get credit for your results, please upload the single unmodified file: ")
+        print(">", token)
+        # print("To campusnet without any modifications.")
+
+        # print("Now time for some autolab fun")
+
+def source_instantiate(name, report1_source, payload):
+    eval("exec")(report1_source, globals())
+    pl = pickle.loads(bytes.fromhex(payload))
+    report = eval(name)(payload=pl, strict=True)
+    # report.set_payload(pl)
+    return report
+
+
+
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            # print(self.questions)\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                print("q is", q())\n                q()._cache_put(\'time\', q.time) # = q.time\n                report_cache[q.__qualname__] = q._cache2\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            # self._stdout = sys.stdout\n            # sys._stdout = io.StringIO()\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f" * q{n+1})   Total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.normpath(os.path.join(output_dir, token))\n\n\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
+report1_payload = '80049568000000000000007d94288c055765656b31947d942868018c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b04758c0474696d6594473fb71ac800000000758c0d4175746f6d6174696350617373947d946808473fb127100000000073752e'
+name="Report3"
+
+report = source_instantiate(name, report1_source, report1_payload)
+output_dir = os.path.dirname(__file__)
+gather_upload_to_campusnet(report, output_dir)
diff --git a/examples/example_docker/instructor/unitgrade-docker/requirements.txt b/docker_images/unitgrade-docker/requirements.txt
similarity index 86%
rename from examples/example_docker/instructor/unitgrade-docker/requirements.txt
rename to docker_images/unitgrade-docker/requirements.txt
index 9db6120..0a73d68 100644
--- a/examples/example_docker/instructor/unitgrade-docker/requirements.txt
+++ b/docker_images/unitgrade-docker/requirements.txt
@@ -4,3 +4,4 @@ jinja2
 tabulate
 compress_pickle
 pyfiglet
+colorama
\ No newline at end of file
diff --git a/docker_images/unitgrade-docker/tmp/cs103/homework1.py b/docker_images/unitgrade-docker/tmp/cs103/homework1.py
new file mode 100644
index 0000000..3543f1b
--- /dev/null
+++ b/docker_images/unitgrade-docker/tmp/cs103/homework1.py
@@ -0,0 +1,21 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+def reverse_list(mylist): 
+    """
+    Given a list 'mylist' returns a list consisting of the same elements in reverse order. E.g.
+    reverse_list([1,2,3]) should return [3,2,1] (as a list).
+    """
+    # TODO: 1 lines missing.
+    raise NotImplementedError("Implement function body")
+
+def add(a,b): 
+    """ Given two numbers `a` and `b` this function should simply return their sum:
+    > add(a,b) = a+b """
+    # TODO: 1 lines missing.
+    raise NotImplementedError("Implement function body")
+
+if __name__ == "__main__":
+    # Problem 1: Write a function which add two numbers
+    print(f"Your result of 2 + 2 = {add(2,2)}")
+    print(f"Reversing a small list", reverse_list([2,3,5,7]))
diff --git a/docker_images/unitgrade-docker/tmp/cs103/report3.py b/docker_images/unitgrade-docker/tmp/cs103/report3.py
new file mode 100644
index 0000000..f83bb53
--- /dev/null
+++ b/docker_images/unitgrade-docker/tmp/cs103/report3.py
@@ -0,0 +1,29 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+from src.unitgrade2.unitgrade2 import UTestCase, Report
+from src.unitgrade2 import evaluate_report_student
+
+class Week1(UTestCase):
+    """ The first question for week 1. """
+    def test_add(self):
+        from cs103.homework1 import add
+        self.assertEqualC(add(2,2))
+        self.assertEqualC(add(-100, 5))
+
+
+class AutomaticPass(UTestCase):
+    def test_student_passed(self):
+        self.assertEqual(2,2)
+
+
+import cs103
+class Report3(Report):
+    title = "CS 101 Report 3"
+    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.
+    pack_imports = [cs103]
+
+if __name__ == "__main__":
+    # from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
+    # gather_upload_to_campusnet(Report3())
+    evaluate_report_student(Report3())
diff --git a/docker_images/unitgrade-docker/tmp/cs103/report3_complete_grade.py b/docker_images/unitgrade-docker/tmp/cs103/report3_complete_grade.py
new file mode 100644
index 0000000..1101b26
--- /dev/null
+++ b/docker_images/unitgrade-docker/tmp/cs103/report3_complete_grade.py
@@ -0,0 +1,338 @@
+
+import numpy as np
+from tabulate import tabulate
+from datetime import datetime
+import pyfiglet
+import unittest
+import inspect
+import os
+import argparse
+import time
+
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
+To run all tests in a report: 
+
+> python assignment1_dp.py
+
+To run only question 2 or question 2.1
+
+> python assignment1_dp.py -q 2
+> python assignment1_dp.py -q 2.1
+
+Note this scripts does not grade your report. To grade your report, use:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
+parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
+parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
+parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
+parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
+
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+    args = parser.parse_args()
+    if question is None and args.q is not None:
+        question = args.q
+        if "." in question:
+            question, qitem = [int(v) for v in question.split(".")]
+        else:
+            question = int(question)
+
+    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
+        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
+
+    if unmute is None:
+        unmute = args.unmute
+    if passall is None:
+        passall = args.passall
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+                                          show_tol_err=show_tol_err)
+
+
+    if question is None:
+        print("Provisional evaluation")
+        tabulate(table_data)
+        table = table_data
+        print(tabulate(table))
+        print(" ")
+
+    fr = inspect.getouterframes(inspect.currentframe())[1].filename
+    gfile = os.path.basename(fr)[:-3] + "_grade.py"
+    if os.path.exists(gfile):
+        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
+        print(">>>", gfile)
+        print("In the same manner as you ran this file.")
+
+
+    return results
+
+
+def upack(q):
+    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
+    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
+    h = np.asarray(h)
+    return h[:,0], h[:,1], h[:,2],
+
+class UnitgradeTextRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+class SequentialTestLoader(unittest.TestLoader):
+    def getTestCaseNames(self, testCaseClass):
+        test_names = super().getTestCaseNames(testCaseClass)
+        # testcase_methods = list(testCaseClass.__dict__.keys())
+        ls = []
+        for C in testCaseClass.mro():
+            if issubclass(C, unittest.TestCase):
+                ls = list(C.__dict__.keys()) + ls
+        testcase_methods = ls
+        test_names.sort(key=testcase_methods.index)
+        return test_names
+
+def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
+                    show_progress_bar=True,
+                    show_tol_err=False,
+                    big_header=True):
+
+    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"
+    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
+    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(s, "(use --help for options)" if show_help_flag else "")
+    # print(f"Loaded answers from: ", report.computed_answers_file, "\n")
+    table_data = []
+    t_start = time.time()
+    score = {}
+    loader = SequentialTestLoader()
+
+    for n, (q, w) in enumerate(report.questions):
+        if question is not None and n+1 != question:
+            continue
+        suite = loader.loadTestsFromTestCase(q)
+        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
+        q_title_print = "Question %i: %s"%(n+1, qtitle)
+        print(q_title_print, end="")
+        q.possible = 0
+        q.obtained = 0
+        q_ = {} # Gather score in this class.
+        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)
+
+        possible = res.testsRun
+        obtained = len(res.successes)
+
+        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun
+
+        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0
+        score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle}
+        q.obtained = obtained
+        q.possible = possible
+
+        s1 = f" * q{n+1})   Total"
+        s2 = f" {q.obtained}/{w}"
+        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )
+        print(" ")
+        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])
+
+    ws, possible, obtained = upack(score)
+    possible = int( msum(possible) )
+    obtained = int( msum(obtained) ) # Cast to python int
+    report.possible = possible
+    report.obtained = obtained
+    now = datetime.now()
+    dt_string = now.strftime("%H:%M:%S")
+
+    dt = int(time.time()-t_start)
+    minutes = dt//60
+    seconds = dt - minutes*60
+    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")
+
+    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
+
+
+from tabulate import tabulate
+from datetime import datetime
+import inspect
+import json
+import os
+import bz2
+import pickle
+import os
+
+def bzwrite(json_str, token): # to get around obfuscation issues
+    with getattr(bz2, 'open')(token, "wt") as f:
+        f.write(json_str)
+
+def gather_imports(imp):
+    resources = {}
+    m = imp
+    # for m in pack_imports:
+    # print(f"*** {m.__name__}")
+    f = m.__file__
+    # dn = os.path.dirname(f)
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
+        top_package = os.path.dirname(m.__file__)
+        module_import = True
+    else:
+        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
+        module_import = False
+
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = os.path.dirname(top_package)
+    import zipfile
+    # import strea
+    # zipfile.ZipFile
+    import io
+    # file_like_object = io.BytesIO(my_zip_data)
+    zip_buffer = io.BytesIO()
+    with zipfile.ZipFile(zip_buffer, 'w') as zip:
+        # zip.write()
+        for root, dirs, files in os.walk(top_package):
+            for file in files:
+                if file.endswith(".py"):
+                    fpath = os.path.join(root, file)
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
+                    zip.write(fpath, v)
+
+    resources['zipfile'] = zip_buffer.getvalue()
+    resources['top_package'] = top_package
+    resources['module_import'] = module_import
+    return resources, top_package
+
+    if f.endswith("__init__.py"):
+        for root, dirs, files in os.walk(os.path.dirname(f)):
+            for file in files:
+                if file.endswith(".py"):
+                    # print(file)
+                    # print()
+                    v = os.path.relpath(os.path.join(root, file), top_package)
+                    with open(os.path.join(root, file), 'r') as ff:
+                        resources[v] = ff.read()
+    else:
+        v = os.path.relpath(f, top_package)
+        with open(f, 'r') as ff:
+            resources[v] = ff.read()
+    return resources
+
+import argparse
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
+parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
+
+def gather_upload_to_campusnet(report, output_dir=None):
+    n = report.nL
+    args = parser.parse_args()
+    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
+                                          show_progress_bar=not args.noprogress,
+                                          big_header=not args.autolab)
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
+    # also load the source code of missing files...
+
+    sources = {}
+    print("")
+    if not args.autolab:
+        if len(report.individual_imports) > 0:
+            print("By uploading the .token file, you verify the files:")
+            for m in report.individual_imports:
+                print(">", m.__file__)
+            print("Are created/modified individually by you in agreement with DTUs exam rules")
+            report.pack_imports += report.individual_imports
+
+        if len(report.pack_imports) > 0:
+            print("Including files in upload...")
+            for k, m in enumerate(report.pack_imports):
+                nimp, top_package = gather_imports(m)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
+                nimp['name'] = m.__name__
+                sources[k] = nimp
+                # if len([k for k in nimp if k not in sources]) > 0:
+                print(f" * {m.__name__}")
+                # sources = {**sources, **nimp}
+    results['sources'] = sources
+
+    if output_dir is None:
+        output_dir = os.getcwd()
+
+    payload_out_base = report.__class__.__name__ + "_handin"
+
+    obtain, possible = results['total']
+    vstring = "_v"+report.version if report.version is not None else ""
+
+    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
+    token = os.path.normpath(os.path.join(output_dir, token))
+
+
+    with open(token, 'wb') as f:
+        pickle.dump(results, f)
+
+    if not args.autolab:
+        print(" ")
+        print("To get credit for your results, please upload the single unmodified file: ")
+        print(">", token)
+        # print("To campusnet without any modifications.")
+
+        # print("Now time for some autolab fun")
+
+def source_instantiate(name, report1_source, payload):
+    eval("exec")(report1_source, globals())
+    pl = pickle.loads(bytes.fromhex(payload))
+    report = eval(name)(payload=pl, strict=True)
+    # report.set_payload(pl)
+    return report
+
+
+
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            # print(self.questions)\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                print("q is", q())\n                q()._cache_put(\'time\', q.time) # = q.time\n                report_cache[q.__qualname__] = q._cache2\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            # self._stdout = sys.stdout\n            # sys._stdout = io.StringIO()\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f" * q{n+1})   Total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.normpath(os.path.join(output_dir, token))\n\n\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n    @hide\n    def test_add_hidden(self):\n        # This is a hidden test. The @hide-decorator will allow unitgrade to remove the test.\n        # See the output in the student directory for more information.\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n    @hide\n    def test_hidden_fail(self):\n        self.assertEqual(2,3)\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
+report1_payload = '80049589000000000000007d94288c055765656b31947d942868018c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b047568018c0f746573745f6164645f68696464656e948694680586947d944b004b04738c0474696d6594473fda6e8700000000758c0d4175746f6d6174696350617373947d94680c473fb8d5140000000073752e'
+name="Report3"
+
+report = source_instantiate(name, report1_source, report1_payload)
+output_dir = os.path.dirname(__file__)
+gather_upload_to_campusnet(report, output_dir)
\ No newline at end of file
diff --git a/docker_images/unitgrade-docker/tmp/cs103/report3_grade.py b/docker_images/unitgrade-docker/tmp/cs103/report3_grade.py
new file mode 100644
index 0000000..85573c9
--- /dev/null
+++ b/docker_images/unitgrade-docker/tmp/cs103/report3_grade.py
@@ -0,0 +1,340 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+import numpy as np
+from tabulate import tabulate
+from datetime import datetime
+import pyfiglet
+import unittest
+import inspect
+import os
+import argparse
+import time
+
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
+To run all tests in a report: 
+
+> python assignment1_dp.py
+
+To run only question 2 or question 2.1
+
+> python assignment1_dp.py -q 2
+> python assignment1_dp.py -q 2.1
+
+Note this scripts does not grade your report. To grade your report, use:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
+parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
+parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
+parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
+parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
+
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+    args = parser.parse_args()
+    if question is None and args.q is not None:
+        question = args.q
+        if "." in question:
+            question, qitem = [int(v) for v in question.split(".")]
+        else:
+            question = int(question)
+
+    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
+        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
+
+    if unmute is None:
+        unmute = args.unmute
+    if passall is None:
+        passall = args.passall
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+                                          show_tol_err=show_tol_err)
+
+
+    if question is None:
+        print("Provisional evaluation")
+        tabulate(table_data)
+        table = table_data
+        print(tabulate(table))
+        print(" ")
+
+    fr = inspect.getouterframes(inspect.currentframe())[1].filename
+    gfile = os.path.basename(fr)[:-3] + "_grade.py"
+    if os.path.exists(gfile):
+        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
+        print(">>>", gfile)
+        print("In the same manner as you ran this file.")
+
+
+    return results
+
+
+def upack(q):
+    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
+    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
+    h = np.asarray(h)
+    return h[:,0], h[:,1], h[:,2],
+
+class UnitgradeTextRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+class SequentialTestLoader(unittest.TestLoader):
+    def getTestCaseNames(self, testCaseClass):
+        test_names = super().getTestCaseNames(testCaseClass)
+        # testcase_methods = list(testCaseClass.__dict__.keys())
+        ls = []
+        for C in testCaseClass.mro():
+            if issubclass(C, unittest.TestCase):
+                ls = list(C.__dict__.keys()) + ls
+        testcase_methods = ls
+        test_names.sort(key=testcase_methods.index)
+        return test_names
+
+def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
+                    show_progress_bar=True,
+                    show_tol_err=False,
+                    big_header=True):
+
+    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"
+    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
+    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(s, "(use --help for options)" if show_help_flag else "")
+    # print(f"Loaded answers from: ", report.computed_answers_file, "\n")
+    table_data = []
+    t_start = time.time()
+    score = {}
+    loader = SequentialTestLoader()
+
+    for n, (q, w) in enumerate(report.questions):
+        if question is not None and n+1 != question:
+            continue
+        suite = loader.loadTestsFromTestCase(q)
+        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
+        q_title_print = "Question %i: %s"%(n+1, qtitle)
+        print(q_title_print, end="")
+        q.possible = 0
+        q.obtained = 0
+        q_ = {} # Gather score in this class.
+        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)
+
+        possible = res.testsRun
+        obtained = len(res.successes)
+
+        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun
+
+        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0
+        score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle}
+        q.obtained = obtained
+        q.possible = possible
+
+        s1 = f" * q{n+1})   Total"
+        s2 = f" {q.obtained}/{w}"
+        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )
+        print(" ")
+        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])
+
+    ws, possible, obtained = upack(score)
+    possible = int( msum(possible) )
+    obtained = int( msum(obtained) ) # Cast to python int
+    report.possible = possible
+    report.obtained = obtained
+    now = datetime.now()
+    dt_string = now.strftime("%H:%M:%S")
+
+    dt = int(time.time()-t_start)
+    minutes = dt//60
+    seconds = dt - minutes*60
+    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")
+
+    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
+
+
+from tabulate import tabulate
+from datetime import datetime
+import inspect
+import json
+import os
+import bz2
+import pickle
+import os
+
+def bzwrite(json_str, token): # to get around obfuscation issues
+    with getattr(bz2, 'open')(token, "wt") as f:
+        f.write(json_str)
+
+def gather_imports(imp):
+    resources = {}
+    m = imp
+    # for m in pack_imports:
+    # print(f"*** {m.__name__}")
+    f = m.__file__
+    # dn = os.path.dirname(f)
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
+        top_package = os.path.dirname(m.__file__)
+        module_import = True
+    else:
+        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
+        module_import = False
+
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = os.path.dirname(top_package)
+    import zipfile
+    # import strea
+    # zipfile.ZipFile
+    import io
+    # file_like_object = io.BytesIO(my_zip_data)
+    zip_buffer = io.BytesIO()
+    with zipfile.ZipFile(zip_buffer, 'w') as zip:
+        # zip.write()
+        for root, dirs, files in os.walk(top_package):
+            for file in files:
+                if file.endswith(".py"):
+                    fpath = os.path.join(root, file)
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
+                    zip.write(fpath, v)
+
+    resources['zipfile'] = zip_buffer.getvalue()
+    resources['top_package'] = top_package
+    resources['module_import'] = module_import
+    return resources, top_package
+
+    if f.endswith("__init__.py"):
+        for root, dirs, files in os.walk(os.path.dirname(f)):
+            for file in files:
+                if file.endswith(".py"):
+                    # print(file)
+                    # print()
+                    v = os.path.relpath(os.path.join(root, file), top_package)
+                    with open(os.path.join(root, file), 'r') as ff:
+                        resources[v] = ff.read()
+    else:
+        v = os.path.relpath(f, top_package)
+        with open(f, 'r') as ff:
+            resources[v] = ff.read()
+    return resources
+
+import argparse
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
+parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
+
+def gather_upload_to_campusnet(report, output_dir=None):
+    n = report.nL
+    args = parser.parse_args()
+    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
+                                          show_progress_bar=not args.noprogress,
+                                          big_header=not args.autolab)
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
+    # also load the source code of missing files...
+
+    sources = {}
+    print("")
+    if not args.autolab:
+        if len(report.individual_imports) > 0:
+            print("By uploading the .token file, you verify the files:")
+            for m in report.individual_imports:
+                print(">", m.__file__)
+            print("Are created/modified individually by you in agreement with DTUs exam rules")
+            report.pack_imports += report.individual_imports
+
+        if len(report.pack_imports) > 0:
+            print("Including files in upload...")
+            for k, m in enumerate(report.pack_imports):
+                nimp, top_package = gather_imports(m)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
+                nimp['name'] = m.__name__
+                sources[k] = nimp
+                # if len([k for k in nimp if k not in sources]) > 0:
+                print(f" * {m.__name__}")
+                # sources = {**sources, **nimp}
+    results['sources'] = sources
+
+    if output_dir is None:
+        output_dir = os.getcwd()
+
+    payload_out_base = report.__class__.__name__ + "_handin"
+
+    obtain, possible = results['total']
+    vstring = "_v"+report.version if report.version is not None else ""
+
+    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
+    token = os.path.normpath(os.path.join(output_dir, token))
+
+
+    with open(token, 'wb') as f:
+        pickle.dump(results, f)
+
+    if not args.autolab:
+        print(" ")
+        print("To get credit for your results, please upload the single unmodified file: ")
+        print(">", token)
+        # print("To campusnet without any modifications.")
+
+        # print("Now time for some autolab fun")
+
+def source_instantiate(name, report1_source, payload):
+    eval("exec")(report1_source, globals())
+    pl = pickle.loads(bytes.fromhex(payload))
+    report = eval(name)(payload=pl, strict=True)
+    # report.set_payload(pl)
+    return report
+
+
+
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            # print(self.questions)\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                print("q is", q())\n                q()._cache_put(\'time\', q.time) # = q.time\n                report_cache[q.__qualname__] = q._cache2\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            # self._stdout = sys.stdout\n            # sys._stdout = io.StringIO()\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f" * q{n+1})   Total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.normpath(os.path.join(output_dir, token))\n\n\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
+report1_payload = '80049568000000000000007d94288c055765656b31947d942868018c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b04758c0474696d6594473fb1eb1c00000000758c0d4175746f6d6174696350617373947d946808473fa78d300000000073752e'
+name="Report3"
+
+report = source_instantiate(name, report1_source, report1_payload)
+output_dir = os.path.dirname(__file__)
+gather_upload_to_campusnet(report, output_dir)
diff --git a/examples/02471/instructor/02471/report1.py b/examples/02471/instructor/02471/report1.py
index 1ed131f..96bb952 100644
--- a/examples/02471/instructor/02471/report1.py
+++ b/examples/02471/instructor/02471/report1.py
@@ -114,7 +114,7 @@ if __name__ == "__main__":
 
     # from week02 import Week_2_sol
     import importnb
-    file = "week02/week2.ipynb"
+    file = "../../../example_jupyter/instructor/cs105/week2.ipynb"
     file2 = 'week02/Week_2_sol.ipynb'
     m = importnb.Notebook.load(file)
     # importnb.Notebook.l
diff --git a/examples/02631/instructor/programs/.coverage b/examples/02631/instructor/programs/.coverage
new file mode 100644
index 0000000000000000000000000000000000000000..11b2ec620c9b142ae8ee79c7a6f5afa297121530
GIT binary patch
literal 53248
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

literal 0
HcmV?d00001

diff --git a/examples/02631/instructor/programs/__pycache__/looping.cpython-38.pyc b/examples/02631/instructor/programs/__pycache__/looping.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..fa302e5a102c505ba4b62aa5eab3205ca2683298
GIT binary patch
literal 2019
zcmZux&2Jk;6rY)0+Z)GiLL1Vg6c~vj)fEa!TOm|cA&{z2weo>dAz5y%$<EkWykD7F
zw@I}=xhMe%32u~AbL^Ra1O9<IAR$gUaNx>`_ja8&u6V0`Gw;oN^YPyAz5Az5)d|qw
ze|#wBYlQrT!bxg?umQi>0w#&1A!*ZMWNjvybe@v7BVAd6(UnzMgRvq#IRj%=)nt9Z
z^h4#TilWbF<g9GSQ}VQ&lk@Tod8Y3jQh8P`jGZy1u=hREeDes-AuZp<VL}xctMG5a
zZ*Bq0N$w0>-9V3wJg0}`CV6ma<Vu!P_({&*B1>d}oCC`RGCH<jpk!x#XCVi>a|F(E
zp8Q$oK${};hoQ(6&w@ztVVnga-x7YNbRc+NCy%pju6BK;ByVw(37rLTpZ9bUalz9h
zMdu)idD7$Y>Pyd+V)N}F&dl{<if3KseiEBNDh;M5v?5Hm1z+c-?s_V;h`^$BoQQ?Z
zl;+Nq)S5_IWkVg8f~F9!BV<ixX99RqmL#FE6+eM@HY=9JtF}_?Z0Q|KTb5=oh(=KS
z`}OAa&V8e_>14xg)w!AY!$`qvI>R`~`dUcUO?B`H0@qQyB1%JLI;&Scy1Ld0Vw35i
zpC!7J>I6(9(+QI#g|Mxpd-n8ka6d0%i@7$ZfsuwsUD}{a)T33Z5qmyf{g}|ugTDa6
z&oIH{=j4!%aK<txCu0hbqKibb0UJ?Vhu;NA&^fXUmd6s#`wTo;M!u<lwwfcn$+sxi
zdTbd$gtJnI@)CF;;C}$v!`@Ej<xWlqY)tj{J3r>mi0*KNUjZ$*b;RI)8d;NCSL_C+
zIRn8?ZA}=Vwb-*&$Z_0P)(KT?-AIWTRsAT4ts}OKt;Omw`hgUNO}9O(RWDS2CSqT;
z+3ht;qqcK<ty?6kWV3Lbo%6$?fkb~Ai*U~bW(kyL9vGo@y2vilk0Hbi1H246-@%m$
z;T)?CM{^z+25_J3(;k!Xw5MJUm4+e4>S;~o249M<XVLW%us)RC13sb$5PKJP91wls
zfC6`87YfnM=}&COy;owbxIQ41t*lzAUocw_lgCPb1|XHTK1|ce{KPZsH^RVVeiEhY
z@8g*W*(zc1)k%Xqx!6-0(OOjImw?fg8)4#$(5%Dc*s;m<9Jpz`bkk`!APHuul|*~}
zHm<yb47b)7kQD)*e|_usV98(r2-6(+RA8oJ+JaS#X$jgs0f<7s8dK<BA9UD=eMd59
zpY#C2ucAGs(t$3znA7L(0e}#Kw^-~^=D~fk&cAroWG?fs#6WSuq22~uWIWqe(7cNB
z<Uu?UmG%Rp$__Pk+o?3-TZ%L;VJYQw4Ez9Y3%8k0A3)rJD?m6AG?wnZpq4&*l`Q=(
zsMp{(*vBzT^N=B}qU4df9b*nd_5T?<!tgaKWttGgc1Fd}hBRjA49Zmj=!j+0u`G~n
zCy-Yx4a%c2FO!tLe%57JGT2~<TZf)APtQY9Xw+J-+l@pJcf0*xo&hai+vxxP8_?aW
z8>QyiKcDok7IbB!ocsz)J)~O?kBz|#cPHf9#t~xd2#c**w-va3x>vpj-&S<Fq7n<}
zyu3mzBGv8M3Ut^wgAR=?qkL6?#)1`S^ln6n9ENHgJ7v*EJ?b%U!JGAJUc+<$1EnzH
AG5`Po

literal 0
HcmV?d00001

diff --git a/examples/02631/instructor/programs/__pycache__/report1intro.cpython-38.pyc b/examples/02631/instructor/programs/__pycache__/report1intro.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ddadca6243eeebd021c63d8d875e9092033e1190
GIT binary patch
literal 7198
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
VDuv%8Mk<jzm3sp9WX?{R{{s&mC>a0%

literal 0
HcmV?d00001

diff --git a/examples/02631/instructor/programs/deploy.py b/examples/02631/instructor/programs/deploy.py
new file mode 100644
index 0000000..6099792
--- /dev/null
+++ b/examples/02631/instructor/programs/deploy.py
@@ -0,0 +1,62 @@
+from report1intro import Report1Flat
+from unitgrade_private2.hidden_create_files import setup_grade_file_report
+from snipper import snip_dir
+
+if __name__ == "__main__":
+    setup_grade_file_report(Report1Flat, minify=False, obfuscate=False, execute=False, with_coverage=True)
+
+    # from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
+    # gather_upload_to_campusnet((Report1Flat()))
+
+    # Deploy the files using snipper: https://gitlab.compute.dtu.dk/tuhe/snipper
+    snip_dir.snip_dir(source_dir="", dest_dir="../../students/programs", clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py'])
+
+    import os
+    os.system("python report1intro_grade.py")
+
+
+"""
+from coverage import CoverageData
+import coverage
+cov2 = coverage.Coverage()
+
+    def setUp(self):
+        import trace
+        self.cov = cov2
+        self.cov.start()
+
+
+
+        # self.tracer.start()
+
+        # using obj_to_trace
+
+    def tearDown(self) -> None:
+
+        self.cov.stop()
+        print()
+
+        data = CoverageData()
+
+        # data.measured_files()
+        # data.lines()
+        data = self.cov.get_data()
+        # data.
+        for file in data.measured_files():
+            print(file)
+            print(data.lines(file))
+            print(data.arcs(file))
+            print(        data.contexts_by_lineno(file))
+
+            # print(data[file])
+
+
+
+- Idea: Measure coverage in setup/teardown. This gives a handful of covered lines. 
+- During setup, supply a dicionary to UTestCase of files, along with the lines that are removed. 
+- When running setup: Take the coverage report, and compare against files. Write functions/lines encountered to the cache dictionary. Rquires you to 
+- inspect the functions that are edited to figure out what is removed. This can probably be done by going upwars towards the first sensible class or function definition (which has not been removed).
+- Supply a dictionary to UTestCase of files, along with the lines edited. Allow UTestCase to write this information to the 
+  cache dictionary (i.e. lines removed). Then use this information when displaying helpful hints later. 
+
+"""
\ No newline at end of file
diff --git a/examples/02631/instructor/programs/looping.py b/examples/02631/instructor/programs/looping.py
new file mode 100644
index 0000000..59a1485
--- /dev/null
+++ b/examples/02631/instructor/programs/looping.py
@@ -0,0 +1,64 @@
+import numpy as np
+import itertools
+
+def bacteriaGrowth(n0, alpha, K, N): #!f
+    """
+    Calculate time until bacteria growth exceed N starting from a population of n0 bacteria.
+    hints:
+        * consider n0
+        * alpha > 0
+    :param n0:
+    :param alpha:
+    :param K:
+    :param N:
+    :return:
+    """
+    if n0 > N:
+        return 0
+    for t in itertools.count():
+        n0 = (1 + alpha * (1-n0 / K) ) * n0
+        if n0 > N:
+            break
+    return t+1
+
+def clusterAnalysis(reflectance):
+    reflectance = np.asarray(reflectance)
+    I1 = np.arange(len(reflectance)) % 2 == 1
+    while True:
+        m = np.asarray( [np.mean( reflectance[~I1] ),  np.mean( reflectance[I1] ) ] )
+        I1_ = np.argmin( np.abs( reflectance[:, np.newaxis] - m[np.newaxis, :] ), axis=1) == 1
+        if all(I1_ == I1):
+            break
+        I1 = I1_
+    return I1 + 1
+
+def fermentationRate(measuredRate, lowerBound, upperBound):
+    # Insert your code here
+    return np.mean( [r for r in measuredRate if lowerBound < r < upperBound] )
+
+
+
+
+def removeIncomplete(id):
+    """ Hints:
+    * Take a look at the example in the exercise.
+    """
+    id = np.asarray(id)
+    id2 = []
+    for i, v in enumerate(id):
+        if len( [x for x in id if int(x) == int(v) ] ) == 3:
+            id2.append(v)
+    return np.asarray(id2)
+
+
+if __name__ == "__main__":
+    # I = clusterAnalysis([1.7, 1.6, 1.3, 1.3, 2.8, 1.4, 2.8, 2.6, 1.6, 2.7])
+    # print(I)
+
+    print(fermentationRate(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 15, 25))
+
+
+    # print(removeIncomplete(np.array([1.3, 2.2, 2.3, 4.2, 5.1, 3.2, 5.3, 3.3, 2.1, 1.1, 5.2, 3.1])))
+
+    # Problem 1: Write a function which add two numbers
+    # clusterAnalysis([2, 1, 2, 4, 5])
\ No newline at end of file
diff --git a/examples/02631/instructor/programs/report1intro.py b/examples/02631/instructor/programs/report1intro.py
new file mode 100644
index 0000000..10b1898
--- /dev/null
+++ b/examples/02631/instructor/programs/report1intro.py
@@ -0,0 +1,139 @@
+from src.unitgrade2.unitgrade2 import Report, UTestCase, cache
+from src.unitgrade2 import evaluate_report_student
+import numpy as np
+import looping
+from looping import bacteriaGrowth, clusterAnalysis, removeIncomplete, fermentationRate
+
+def trlist(x):
+    s = str(list(x))
+    if len(s) > 30:
+        s = s[:30] + "...]"
+    return s
+
+class Bacteria(UTestCase):
+    """ Bacteria growth rates """
+
+    def stest(self, n0, alpha, K, N):
+        g = bacteriaGrowth(n0=n0, alpha=alpha, K=K, N=N)
+        self.title = f"bacteriaGrowth({n0}, {alpha}, {K}, {N}) = {g} ?"
+        self.assertEqualC(g)
+
+    def test_growth1(self):
+        """ Hints:
+        * Make sure to frobulate the frobulator.
+        """
+        self.stest(100, 0.4, 1000, 500)
+
+    def test_growth2(self):
+        self.stest(10, 0.4, 1000, 500)
+
+    def test_growth3(self):
+        self.stest(100, 1.4, 1000, 500)
+
+    def test_growth4(self):
+        self.stest(100, 0.0004, 1000, 500)
+
+    def test_growth5(self):
+        """
+        hints:
+        * What happens when n0 > N? (in this case return t=0) """
+        self.stest(100, 0.4, 1000, 99)
+
+class ClusterAnalysis(UTestCase):
+    """ Test the cluster analysis method """
+
+    def stest(self, n, seed):
+        np.random.seed(seed)
+        x = np.round(np.random.rand(n), 1)
+        I = clusterAnalysis(x)
+        self.title = f"clusterAnalysis({list(x)}) = {list(I)} ?"
+        self.assertEqualC(list(I))
+
+    def test_cluster1(self):
+        """ Hints:
+        * Make sure to frobulate the frobulator.
+        * Just try harder
+        """
+        self.stest(3, 10)
+
+    def test_cluster2(self):
+        self.stest(4, 146)
+
+    def test_cluster3(self):
+        self.stest(5, 12)
+
+    def test_cluster4(self):
+        """
+        Cluster analysis for tied lists
+        Hints:
+        * It may be that an observations has the same distance to the two clusters. Where do you assign it in this case?
+        """
+        x = np.array([10.0, 12.0, 10.0, 12.0, 9.0, 11.0, 11.0, 13.0])
+        self.assertEqualC(list(clusterAnalysis(x) ) )
+
+
+class RemoveIncomplete(UTestCase):
+    """ Remove incomplete IDs """
+
+    def stest(self, x):
+        I = list( removeIncomplete(x) )
+        self.title = f"removeId({trlist(x)}) = {trlist(I)} ?"
+        self.assertEqualC(I)
+
+    @cache
+    def rseq(self, max, n):
+        np.random.seed(42)
+        return np.random.randint(max, size=(n,) ) + (np.random.randint(2, size=(n,) )+1)/10
+
+    def test_incomplete1(self):
+        self.stest( np.array([1.3, 2.2, 2.3, 4.2, 5.1, 3.2, 5.3, 3.3, 2.1, 1.1, 5.2, 3.1]) )
+
+    def test_incomplete2(self):
+        self.stest( np.array([1.1, 1.2, 1.3, 2.1, 2.2, 2.3]) )
+
+    def test_incomplete3(self):
+        self.stest(np.array([5.1, 5.2, 4.1, 4.3, 4.2, 8.1, 8.2, 8.3]) )
+
+    def test_incomplete4(self):
+        self.stest(np.array([1.1, 1.3, 2.1, 2.2, 3.1, 3.3, 4.1, 4.2, 4.3]) )
+
+    def test_incomplete5(self):
+        self.stest(self.rseq(10, 40))
+
+
+class FermentationRate(UTestCase):
+    """ Test the fermentation rate question """
+
+    def stest(self, x, lower, upper):
+        I =  fermentationRate(x, lower, upper)
+        s = trlist(x)
+        self.title = f"fermentationRate({s}, {lower}, {upper}) = {I:.3f} ?"
+        self.assertEqualC(I)
+
+    @cache
+    def rseq(self, max, n):
+        np.random.seed(42)
+        return np.random.randint(max, size=(n,) ) + (np.random.randint(3, size=(n,) )+1)/n
+
+    def test_rate1(self):
+        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 15, 25)
+
+    def test_rate2(self):
+        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 1, 200)
+
+    def test_rate3(self):
+        self.stest(np.array([1.75]), 1, 2)
+
+    def test_rate4(self):
+        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 18.2, 20)
+
+
+class Report1Flat(Report):
+    title = "Week 4: Looping"
+    questions = [(ClusterAnalysis, 10), (RemoveIncomplete, 10), (Bacteria, 10),  (FermentationRate, 10),]
+    pack_imports = [looping]
+
+if __name__ == "__main__":
+    # Uncomment to simply run everything as a unittest:
+    # unittest.main(verbosity=2)
+    evaluate_report_student(Report1Flat())
diff --git a/examples/02631/instructor/programs/report1intro_grade.py b/examples/02631/instructor/programs/report1intro_grade.py
new file mode 100644
index 0000000..4381d55
--- /dev/null
+++ b/examples/02631/instructor/programs/report1intro_grade.py
@@ -0,0 +1,337 @@
+
+import numpy as np
+from tabulate import tabulate
+from datetime import datetime
+import pyfiglet
+import unittest
+import inspect
+import os
+import argparse
+import time
+
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
+To run all tests in a report: 
+
+> python assignment1_dp.py
+
+To run only question 2 or question 2.1
+
+> python assignment1_dp.py -q 2
+> python assignment1_dp.py -q 2.1
+
+Note this scripts does not grade your report. To grade your report, use:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
+parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
+parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
+parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
+parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
+
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+    args = parser.parse_args()
+    if question is None and args.q is not None:
+        question = args.q
+        if "." in question:
+            question, qitem = [int(v) for v in question.split(".")]
+        else:
+            question = int(question)
+
+    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
+        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
+
+    if unmute is None:
+        unmute = args.unmute
+    if passall is None:
+        passall = args.passall
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+                                          show_tol_err=show_tol_err)
+
+
+    if question is None:
+        print("Provisional evaluation")
+        tabulate(table_data)
+        table = table_data
+        print(tabulate(table))
+        print(" ")
+
+    fr = inspect.getouterframes(inspect.currentframe())[1].filename
+    gfile = os.path.basename(fr)[:-3] + "_grade.py"
+    if os.path.exists(gfile):
+        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
+        print(">>>", gfile)
+        print("In the same manner as you ran this file.")
+
+
+    return results
+
+
+def upack(q):
+    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
+    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
+    h = np.asarray(h)
+    return h[:,0], h[:,1], h[:,2],
+
+class UnitgradeTextRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+class SequentialTestLoader(unittest.TestLoader):
+    def getTestCaseNames(self, testCaseClass):
+        test_names = super().getTestCaseNames(testCaseClass)
+        # testcase_methods = list(testCaseClass.__dict__.keys())
+        ls = []
+        for C in testCaseClass.mro():
+            if issubclass(C, unittest.TestCase):
+                ls = list(C.__dict__.keys()) + ls
+        testcase_methods = ls
+        test_names.sort(key=testcase_methods.index)
+        return test_names
+
+def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
+                    show_progress_bar=True,
+                    show_tol_err=False,
+                    big_header=True):
+
+    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"
+    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
+    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(s, "(use --help for options)" if show_help_flag else "")
+    # print(f"Loaded answers from: ", report.computed_answers_file, "\n")
+    table_data = []
+    # nL =
+    t_start = time.time()
+    score = {}
+    loader = SequentialTestLoader()
+
+    for n, (q, w) in enumerate(report.questions):
+        if question is not None and n+1 != question:
+            continue
+        suite = loader.loadTestsFromTestCase(q)
+        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
+        q_title_print = "Question %i: %s"%(n+1, qtitle)
+        print(q_title_print, end="")
+        q.possible = 0
+        q.obtained = 0
+        q_ = {} # Gather score in this class.
+        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)
+
+        possible = res.testsRun
+        obtained = len(res.successes)
+
+        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun
+
+        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0
+        score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle}
+        q.obtained = obtained
+        q.possible = possible
+
+        s1 = f"Question {n+1} total"
+        s2 = f" {q.obtained}/{w}"
+        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )
+        print(" ")
+        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])
+
+    ws, possible, obtained = upack(score)
+    possible = int( msum(possible) )
+    obtained = int( msum(obtained) ) # Cast to python int
+    report.possible = possible
+    report.obtained = obtained
+    now = datetime.now()
+    dt_string = now.strftime("%H:%M:%S")
+
+    dt = int(time.time()-t_start)
+    minutes = dt//60
+    seconds = dt - minutes*60
+    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")
+
+    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
+
+
+from tabulate import tabulate
+from datetime import datetime
+import inspect
+import json
+import os
+import bz2
+import pickle
+import os
+
+def bzwrite(json_str, token): # to get around obfuscation issues
+    with getattr(bz2, 'open')(token, "wt") as f:
+        f.write(json_str)
+
+def gather_imports(imp):
+    resources = {}
+    m = imp
+    # for m in pack_imports:
+    # print(f"*** {m.__name__}")
+    f = m.__file__
+    # dn = os.path.dirname(f)
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
+        top_package = os.path.dirname(m.__file__)
+        module_import = True
+    else:
+        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
+        module_import = False
+
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = os.path.dirname(top_package)
+    import zipfile
+    # import strea
+    # zipfile.ZipFile
+    import io
+    # file_like_object = io.BytesIO(my_zip_data)
+    zip_buffer = io.BytesIO()
+    with zipfile.ZipFile(zip_buffer, 'w') as zip:
+        # zip.write()
+        for root, dirs, files in os.walk(top_package):
+            for file in files:
+                if file.endswith(".py"):
+                    fpath = os.path.join(root, file)
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
+                    zip.write(fpath, v)
+
+    resources['zipfile'] = zip_buffer.getvalue()
+    resources['top_package'] = top_package
+    resources['module_import'] = module_import
+    return resources, top_package
+
+    if f.endswith("__init__.py"):
+        for root, dirs, files in os.walk(os.path.dirname(f)):
+            for file in files:
+                if file.endswith(".py"):
+                    # print(file)
+                    # print()
+                    v = os.path.relpath(os.path.join(root, file), top_package)
+                    with open(os.path.join(root, file), 'r') as ff:
+                        resources[v] = ff.read()
+    else:
+        v = os.path.relpath(f, top_package)
+        with open(f, 'r') as ff:
+            resources[v] = ff.read()
+    return resources
+
+import argparse
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
+parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
+
+def gather_upload_to_campusnet(report, output_dir=None):
+    n = report.nL
+    args = parser.parse_args()
+    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
+                                          show_progress_bar=not args.noprogress,
+                                          big_header=not args.autolab)
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
+    # also load the source code of missing files...
+
+    sources = {}
+    print("")
+    if not args.autolab:
+        if len(report.individual_imports) > 0:
+            print("By uploading the .token file, you verify the files:")
+            for m in report.individual_imports:
+                print(">", m.__file__)
+            print("Are created/modified individually by you in agreement with DTUs exam rules")
+            report.pack_imports += report.individual_imports
+
+        if len(report.pack_imports) > 0:
+            print("Including files in upload...")
+            for k, m in enumerate(report.pack_imports):
+                nimp, top_package = gather_imports(m)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
+                nimp['name'] = m.__name__
+                sources[k] = nimp
+                # if len([k for k in nimp if k not in sources]) > 0:
+                print(f" * {m.__name__}")
+                # sources = {**sources, **nimp}
+    results['sources'] = sources
+
+    if output_dir is None:
+        output_dir = os.getcwd()
+
+    payload_out_base = report.__class__.__name__ + "_handin"
+
+    obtain, possible = results['total']
+    vstring = "_v"+report.version if report.version is not None else ""
+
+    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
+    token = os.path.join(output_dir, token)
+    with open(token, 'wb') as f:
+        pickle.dump(results, f)
+
+    if not args.autolab:
+        print(" ")
+        print("To get credit for your results, please upload the single unmodified file: ")
+        print(">", token)
+        # print("To campusnet without any modifications.")
+
+        # print("Now time for some autolab fun")
+
+def source_instantiate(name, report1_source, payload):
+    eval("exec")(report1_source, globals())
+    pl = pickle.loads(bytes.fromhex(payload))
+    report = eval(name)(payload=pl, strict=True)
+    # report.set_payload(pl)
+    return report
+
+
+
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        return Capturing2(stdout=self._stdout)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    # nL =\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"Question {n+1} total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nimport numpy as np\nimport looping\nfrom looping import bacteriaGrowth, clusterAnalysis, removeIncomplete, fermentationRate\n\ndef trlist(x):\n    s = str(list(x))\n    if len(s) > 30:\n        s = s[:30] + "...]"\n    return s\n\nclass Bacteria(UTestCase):\n    """ Bacteria growth rates """\n\n    def stest(self, n0, alpha, K, N):\n        g = bacteriaGrowth(n0=n0, alpha=alpha, K=K, N=N)\n        self.title = f"bacteriaGrowth({n0}, {alpha}, {K}, {N}) = {g} ?"\n        self.assertEqualC(g)\n\n    def test_growth1(self):\n        """ Hints:\n        * Make sure to frobulate the frobulator.\n        """\n        self.stest(100, 0.4, 1000, 500)\n\n    def test_growth2(self):\n        self.stest(10, 0.4, 1000, 500)\n\n    def test_growth3(self):\n        self.stest(100, 1.4, 1000, 500)\n\n    def test_growth4(self):\n        self.stest(100, 0.0004, 1000, 500)\n\n    def test_growth5(self):\n        """\n        hints:\n        * What happens when n0 > N? (in this case return t=0) """\n        self.stest(100, 0.4, 1000, 99)\n\nclass ClusterAnalysis(UTestCase):\n    """ Test the cluster analysis method """\n\n    def stest(self, n, seed):\n        np.random.seed(seed)\n        x = np.round(np.random.rand(n), 1)\n        I = clusterAnalysis(x)\n        self.title = f"clusterAnalysis({list(x)}) = {list(I)} ?"\n        self.assertEqualC(list(I))\n\n    def test_cluster1(self):\n        """ Hints:\n        * Make sure to frobulate the frobulator.\n        * Just try harder\n        """\n        self.stest(3, 10)\n\n    def test_cluster2(self):\n        self.stest(4, 146)\n\n    def test_cluster3(self):\n        self.stest(5, 12)\n\n    def test_cluster4(self):\n        """\n        Cluster analysis for tied lists\n        Hints:\n        * It may be that an observations has the same distance to the two clusters. Where do you assign it in this case?\n        """\n        x = np.array([10.0, 12.0, 10.0, 12.0, 9.0, 11.0, 11.0, 13.0])\n        self.assertEqualC(list(clusterAnalysis(x) ) )\n\n\nclass RemoveIncomplete(UTestCase):\n    """ Remove incomplete IDs """\n\n    def stest(self, x):\n        I = list( removeIncomplete(x) )\n        self.title = f"removeId({trlist(x)}) = {trlist(I)} ?"\n        self.assertEqualC(I)\n\n    @cache\n    def rseq(self, max, n):\n        np.random.seed(42)\n        return np.random.randint(max, size=(n,) ) + (np.random.randint(2, size=(n,) )+1)/10\n\n    def test_incomplete1(self):\n        self.stest( np.array([1.3, 2.2, 2.3, 4.2, 5.1, 3.2, 5.3, 3.3, 2.1, 1.1, 5.2, 3.1]) )\n\n    def test_incomplete2(self):\n        self.stest( np.array([1.1, 1.2, 1.3, 2.1, 2.2, 2.3]) )\n\n    def test_incomplete3(self):\n        self.stest(np.array([5.1, 5.2, 4.1, 4.3, 4.2, 8.1, 8.2, 8.3]) )\n\n    def test_incomplete4(self):\n        self.stest(np.array([1.1, 1.3, 2.1, 2.2, 3.1, 3.3, 4.1, 4.2, 4.3]) )\n\n    def test_incomplete5(self):\n        self.stest(self.rseq(10, 40))\n\n\nclass FermentationRate(UTestCase):\n    """ Test the fermentation rate question """\n\n    def stest(self, x, lower, upper):\n        I =  fermentationRate(x, lower, upper)\n        s = trlist(x)\n        self.title = f"fermentationRate({s}, {lower}, {upper}) = {I:.3f} ?"\n        self.assertEqualC(I)\n\n    @cache\n    def rseq(self, max, n):\n        np.random.seed(42)\n        return np.random.randint(max, size=(n,) ) + (np.random.randint(3, size=(n,) )+1)/n\n\n    def test_rate1(self):\n        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 15, 25)\n\n    def test_rate2(self):\n        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 1, 200)\n\n    def test_rate3(self):\n        self.stest(np.array([1.75]), 1, 2)\n\n    def test_rate4(self):\n        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 18.2, 20)\n\n\nclass Report1Flat(Report):\n    title = "Week 4: Looping"\n    questions = [(ClusterAnalysis, 10), (RemoveIncomplete, 10), (Bacteria, 10),  (FermentationRate, 10),]\n    pack_imports = [looping]'
+report1_payload = '80049592150000000000007d94288c0f436c7573746572416e616c79736973947d94288c0f436c7573746572416e616c79736973948c0d746573745f636c7573746572319486948c057469746c659486948c2e636c7573746572416e616c79736973285b302e382c20302e302c20302e365d29203d205b312c20322c20315d203f946803680486948c066173736572749486947d944b005d94288c156e756d70792e636f72652e6d756c74696172726179948c067363616c61729493948c056e756d7079948c0564747970659493948c02693494898887945294284b038c013c944e4e4e4affffffff4affffffff4b007494624304010000009486945294681068164304020000009486945294681068164304010000009486945294657368038c0d746573745f636c757374657232948694680686948c36636c7573746572416e616c79736973285b302e352c20302e362c20302e332c20302e335d29203d205b322c20322c20312c20315d203f94680368228694680a86947d944b005d9428681068164304020000009486945294681068164304020000009486945294681068164304010000009486945294681068164304010000009486945294657368038c0d746573745f636c757374657233948694680686948c3e636c7573746572416e616c79736973285b302e322c20302e372c20302e332c20302e352c20302e305d29203d205b312c20322c20312c20322c20315d203f94680368368694680a86947d944b005d9428681068164304010000009486945294681068164304020000009486945294681068164304010000009486945294681068164304020000009486945294681068164304010000009486945294657368038c0d746573745f636c757374657234948694680a86947d944b005d942868106816430401000000948694529468106816430402000000948694529468106816430401000000948694529468106816430402000000948694529468106816430401000000948694529468106816430401000000948694529468106816430401000000948694529468106816430402000000948694529465738c0474696d6594473fdf6c8500000000758c1052656d6f7665496e636f6d706c657465947d94288c1052656d6f7665496e636f6d706c657465948c10746573745f696e636f6d706c657465319486948c057469746c659486948c5372656d6f76654964285b312e332c20322e322c20322e332c20342e322c20352e312c20332e322c2e2e2e5d29203d205b322e322c20322e332c20352e312c20332e322c20352e332c20332e332c2e2e2e5d203f94686d686e86948c066173736572749486947d944b005d9428681068138c02663894898887945294284b0368174e4e4e4affffffff4affffffff4b0074946243089a9999999999014094869452946810687a4308666666666666024094869452946810687a4308666666666666144094869452946810687a43089a9999999999094094869452946810687a4308333333333333154094869452946810687a43086666666666660a4094869452946810687a4308cdcccccccccc004094869452946810687a4308cdcccccccccc144094869452946810687a4308cdcccccccccc084094869452946573686d8c10746573745f696e636f6d706c65746532948694687086948c4b72656d6f76654964285b312e312c20312e322c20312e332c20322e312c20322e322c20322e335d29203d205b312e312c20312e322c20312e332c20322e312c20322e322c20322e335d203f94686d68978694687486947d944b005d94286810687a43089a9999999999f13f94869452946810687a4308333333333333f33f94869452946810687a4308cdccccccccccf43f94869452946810687a4308cdcccccccccc004094869452946810687a43089a9999999999014094869452946810687a4308666666666666024094869452946573686d8c10746573745f696e636f6d706c65746533948694687086948c4f72656d6f76654964285b352e312c20352e322c20342e312c20342e332c20342e322c20382e312c2e2e2e5d29203d205b342e312c20342e332c20342e322c20382e312c20382e322c20382e335d203f94686d68b18694687486947d944b005d94286810687a4308666666666666104094869452946810687a4308333333333333114094869452946810687a4308cdcccccccccc104094869452946810687a4308333333333333204094869452946810687a4308666666666666204094869452946810687a43089a9999999999204094869452946573686d8c10746573745f696e636f6d706c65746534948694687086948c4072656d6f76654964285b312e312c20312e332c20322e312c20322e322c20332e312c20332e332c2e2e2e5d29203d205b342e312c20342e322c20342e335d203f94686d68cb8694687486947d944b005d94286810687a4308666666666666104094869452946810687a4308cdcccccccccc104094869452946810687a4308333333333333114094869452946573686d8c10746573745f696e636f6d706c657465359486948c06406361636865948c0472736571948c0966756e63746f6f6c73948c0a5f486173686564536571949394298194284b0a4b28654e7d948c096861736876616c7565948a0884d8ef03874d7f467386946287948694680e8c0c5f7265636f6e73747275637494939468118c076e6461727261799493944b0085944301629487945294284b014b28859468138c02663894898887945294284b0368174e4e4e4affffffff4affffffff4b0074946289424001000066666666666618409a99999999990940cdcccccccccc1c40cdcccccccccc1040cdcccccccccc184033333333333322409a999999999901406666666666661840cdcccccccccc1c40cdcccccccccc10409a999999999909406666666666661c40cdcccccccccc1c40cdcccccccccc0040cdcccccccccc14406666666666661040333333333333f33f6666666666661c406666666666661440333333333333f33f66666666666610409a9999999999c93f6666666666662240cdcccccccccc144066666666666620409a9999999999c93f66666666666622409a99999999990140cdcccccccccc18409a9999999999094066666666666620409a999999999901406666666666661040cdcccccccccc0040cdcccccccccc1840cdcccccccccc10406666666666662040cdcccccccccc1840333333333333f33f9a9999999999094094749462686d68dc8694687086948c5372656d6f76654964285b362e312c20332e322c20372e322c20342e322c20362e322c20392e312c2e2e2e5d29203d205b392e312c20352e322c20312e322c20352e312c20312e322c20392e322c2e2e2e5d203f94686d68dc8694687486947d944b005d94286810687a4308333333333333224094869452946810687a4308cdcccccccccc144094869452946810687a4308333333333333f33f94869452946810687a4308666666666666144094869452946810687a4308333333333333f33f94869452946810687a4308666666666666224094869452946810687a4308cdcccccccccc144094869452946810687a4308666666666666204094869452946810687a4308666666666666224094869452946810687a4308666666666666204094869452946810687a4308666666666666204094869452946810687a4308333333333333f33f94869452946573686a473fcf9dc400000000758c084261637465726961947d94288c084261637465726961948c0c746573745f67726f777468319486948c057469746c659486948c29626163746572696147726f777468283130302c20302e342c20313030302c2035303029203d2037203f946a250100006a2601000086948c066173736572749486947d944b004b07736a250100006a2601000086948c08636f7665726167659486947d94286a250100006a2601000086947d948c0a6c6f6f70696e672e7079947d948c2564656620626163746572696147726f777468286e302c20616c7068612c204b2c204e293a20944b158ce72222220a2020202043616c63756c6174652074696d6520756e74696c2062616374657269612067726f77746820657863656564204e207374617274696e672066726f6d206120706f70756c6174696f6e206f66206e302062616374657269612e0a2020202068696e74733a0a20202020202020202a20636f6e7369646572206e300a20202020202020202a20616c706861203e20300a202020203a706172616d206e303a0a202020203a706172616d20616c7068613a0a202020203a706172616d204b3a0a202020203a706172616d204e3a0a202020203a72657475726e3a0a2020202022222294869473736a250100008c0c746573745f67726f777468329486947d948c0a6c6f6f70696e672e7079947d948c2564656620626163746572696147726f777468286e302c20616c7068612c204b2c204e293a20944b158ce72222220a2020202043616c63756c6174652074696d6520756e74696c2062616374657269612067726f77746820657863656564204e207374617274696e672066726f6d206120706f70756c6174696f6e206f66206e302062616374657269612e0a2020202068696e74733a0a20202020202020202a20636f6e7369646572206e300a20202020202020202a20616c706861203e20300a202020203a706172616d206e303a0a202020203a706172616d20616c7068613a0a202020203a706172616d204b3a0a202020203a706172616d204e3a0a202020203a72657475726e3a0a2020202022222294869473736a250100008c0c746573745f67726f777468339486947d948c0a6c6f6f70696e672e7079947d948c2564656620626163746572696147726f777468286e302c20616c7068612c204b2c204e293a20944b158ce72222220a2020202043616c63756c6174652074696d6520756e74696c2062616374657269612067726f77746820657863656564204e207374617274696e672066726f6d206120706f70756c6174696f6e206f66206e302062616374657269612e0a2020202068696e74733a0a20202020202020202a20636f6e7369646572206e300a20202020202020202a20616c706861203e20300a202020203a706172616d206e303a0a202020203a706172616d20616c7068613a0a202020203a706172616d204b3a0a202020203a706172616d204e3a0a202020203a72657475726e3a0a2020202022222294869473736a250100008c0c746573745f67726f777468349486947d948c0a6c6f6f70696e672e7079947d948c2564656620626163746572696147726f777468286e302c20616c7068612c204b2c204e293a20944b158ce72222220a2020202043616c63756c6174652074696d6520756e74696c2062616374657269612067726f77746820657863656564204e207374617274696e672066726f6d206120706f70756c6174696f6e206f66206e302062616374657269612e0a2020202068696e74733a0a20202020202020202a20636f6e7369646572206e300a20202020202020202a20616c706861203e20300a202020203a706172616d206e303a0a202020203a706172616d20616c7068613a0a202020203a706172616d204b3a0a202020203a706172616d204e3a0a202020203a72657475726e3a0a2020202022222294869473736a250100008c0c746573745f67726f777468359486947d948c0a6c6f6f70696e672e7079947d948c2564656620626163746572696147726f777468286e302c20616c7068612c204b2c204e293a20944b118ce72222220a2020202043616c63756c6174652074696d6520756e74696c2062616374657269612067726f77746820657863656564204e207374617274696e672066726f6d206120706f70756c6174696f6e206f66206e302062616374657269612e0a2020202068696e74733a0a20202020202020202a20636f6e7369646572206e300a20202020202020202a20616c706861203e20300a202020203a706172616d206e303a0a202020203a706172616d20616c7068613a0a202020203a706172616d204b3a0a202020203a706172616d204e3a0a202020203a72657475726e3a0a202020202222229486947373756a250100006a3a01000086946a2801000086948c29626163746572696147726f7774682831302c20302e342c20313030302c2035303029203d203134203f946a250100006a3a01000086946a2c01000086947d944b004b0e736a250100006a3a01000086946a3001000086946a320100006a250100006a4201000086946a2801000086948c29626163746572696147726f777468283130302c20312e342c20313030302c2035303029203d2033203f946a250100006a4201000086946a2c01000086947d944b004b03736a250100006a4201000086946a3001000086946a320100006a250100006a4a01000086946a2801000086948c2f626163746572696147726f777468283130302c20302e303030342c20313030302c2035303029203d2035343934203f946a250100006a4a01000086946a2c01000086947d944b004d7615736a250100006a4a01000086946a3001000086946a320100006a250100006a5201000086946a2801000086948c28626163746572696147726f777468283130302c20302e342c20313030302c20393929203d2030203f946a250100006a5201000086946a2c01000086947d944b004b00736a250100006a5201000086946a3001000086946a32010000686a473fcf9d9a00000000758c104665726d656e746174696f6e52617465947d94288c104665726d656e746174696f6e52617465948c0a746573745f72617465319486948c057469746c659486948c476665726d656e746174696f6e52617465285b32302e312c2031392e332c20312e312c2031382e322c2031392e372c202e2e2e5d2c2031352c20323529203d2031392e363030203f946a7c0100006a7d01000086948c066173736572749486947d944b006810687a43089a999999999933409486945294736a7c0100008c0a746573745f72617465329486946a7f01000086948c476665726d656e746174696f6e52617465285b32302e312c2031392e332c20312e312c2031382e322c2031392e372c202e2e2e5d2c20312c2032303029203d2032392e393735203f946a7c0100006a8901000086946a8301000086947d944b006810687a43089899999999f93d409486945294736a7c0100008c0a746573745f72617465339486946a7f01000086948c286665726d656e746174696f6e52617465285b312e37355d2c20312c203229203d20312e373530203f946a7c0100006a9301000086946a8301000086947d944b006810687a4308000000000000fc3f9486945294736a7c0100008c0a746573745f72617465349486946a7f01000086948c496665726d656e746174696f6e52617465285b32302e312c2031392e332c20312e312c2031382e322c2031392e372c202e2e2e5d2c2031382e322c20323029203d2031392e353030203f946a7c0100006a9d01000086946a8301000086947d944b006810687a43080000000000803340948694529473686a473fc74c0a0000000075752e'
+name="Report1Flat"
+
+report = source_instantiate(name, report1_source, report1_payload)
+output_dir = os.path.dirname(__file__)
+gather_upload_to_campusnet(report, output_dir)
\ No newline at end of file
diff --git a/examples/02631/instructor/programs/unitgrade/Bacteria.pkl b/examples/02631/instructor/programs/unitgrade/Bacteria.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..b246df45c63387d95bc69cc26deba7770d8249c5
GIT binary patch
literal 2050
zcmeHIO-sW-5Ut;(h~PnwG8B|nN=&syT2Mg`9)kS~vZmW6kY>YXQ}s~r<SEDXH~JI2
zI+JXRt@U6%+CX6DW#60Kmyq|e{`Rp|$gYvDq{VCIDlUDd({06Lb>ElbQF(R!s?!bS
ztAJBgeK4zTv!|81ZP&oI8a2QQ%cgBt;R4R#N_#8bDl#@%9CN9VJkn0V*@_Kbbj6TM
z)+bq<pQ9t4mI5InKkQr4GveuCm-k?1Xo!PY5P7TyP7ONMHfU!reJ_{GCBW;31#S{B
z#X<Q44oRr|U?Ktev4B6hoOhuEv0_r;Jm^U=00xnWi0q3HL=QrH!n87R&kt4H&Ptkf
z46X=czsn^q{eouOgG<P<cEltb;EJ4R+HB1f;!JfN(@Cxp8RiY15&eqM#HqJ*nwhxt
z4#0T(3-8XB-YxvyHJ08j>|OIu-tGRc|6PLlu>Y#P^|=`|FM{fgJcEc;G~u&D;X}YS
z-aA+y{3wYLQ~wrgXSpP?#*%9!Nx)e0$Vi^dgqBH4Ov%}>Y&KeEuf#RNcf&nWCS<H^
c8Rg1+<%w*oMG<W0dnM9%uLV*hAX7}NPbL6<qW}N^

literal 0
HcmV?d00001

diff --git a/examples/02631/instructor/programs/unitgrade/ClusterAnalysis.pkl b/examples/02631/instructor/programs/unitgrade/ClusterAnalysis.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..36635371f6e86d5f841a3827696a5909e766532b
GIT binary patch
literal 763
zcma)(Jx_!{5QYKK*r<*6TVg^saEGUbA2D>2P+WT<25}Qexbwm;1;r&+ek61^{!jmb
z&Vq-6XxL(4XWyN9-q}a}?Oju<wF09&aMPR%mR&ExwBQMca!)WWZlgMF!xNO-A`vN*
zfAlN8Q5!Rho|(j=mJE~Nm|T#VZIY2m?0{TBti~E%+X*>mnZODw@RR`C9xd|uvY^pJ
z#^^jxMG|INSfG+eVH#$z#;%nFzxSe8GMUj52VP&EVG4$~RjTLU`~J-bt}1wnfIC-L
z(Hb_ILcAXzy1KObW80iE9;<DuBb3ED(oT9zo>cy17+0ZoiZ-RwZ?gnT>^3fY3H}1A
z#sBb)H++{pe28Ju(}u6YwOY^7dK9OJvuWLnJ@EARSRIMooyovzLr6NMI@@O2jOX+d
D%KPtw

literal 0
HcmV?d00001

diff --git a/examples/02631/instructor/programs/unitgrade/FermentationRate.pkl b/examples/02631/instructor/programs/unitgrade/FermentationRate.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..9f5cea13c96d67ff2704de398cd66b78a2db463b
GIT binary patch
literal 618
zcmZo*nHtZ;00y;FG<pQwQj2m^^GXs+GV}9-5=&C2^l+7=7MH{q0ojIA+NSidmSmRX
zq=H!PX=rLSqKypn40RL?E%l6nB$#QTX9N~7*HO^Z(~AYNO?4EEOf?m3LCVYw3>56A
zWH4qh0nKAeEG|whDghc@JH?x!M>MZAx1drlIlm}XFSj(OBr~z7D6tZ#tT;I_C$VVC
zWT0EXN`Q1qNo7GQNQ5cPVoGO6`;?$58s5x3j5bsJ{QSKB0|A)uW+<7G<jgT^CI}ci
z0Bs7IQk=nv<V7Q(SOyFEo&);LzyRbqBTGF?b5n@tB!OmfKzx<Kn<4DXF#}}(Pg`sb
zForom12c3D^~_B{Aqcbt9DYD9H29R!ZGgn+AA2lbG=bURiD?5d@du7kBd{ldF=z^l
OL0zm)Xn=)ssU83q4$F!F

literal 0
HcmV?d00001

diff --git a/examples/02631/instructor/programs/unitgrade/RemoveIncomplete.pkl b/examples/02631/instructor/programs/unitgrade/RemoveIncomplete.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..30edf2db7bc0e41f0ada9c1c7443ac1d487a6d9a
GIT binary patch
literal 1444
zcma)6O-sW-5N)fK>Om^hd+=1DETm~`3yOj#jZ~<|A`;szDfEkEtMpLt<OlTTdeGmb
zKSuPfvpY$;p<8qh$?VJ9&AfTDd$;=Xnoh_u<@s5*LHolSdNODY`=cIZl+Ut^`s}J3
zAtt})vo!0n9u?7rhb!9orb(=VQ6xq2fT$#*GBFE=1rZ_Sa@RO8nsY+*4Oqap;2~JX
zA$OB*3ie)ee4ly@elz8E;u7-P9*p~=326;IO8Vm->pGt2On~XPoSx(HXGl#_;N51E
z5fw<PQ{_*O54^$i_R1`|&+GO2=?@I~uoH}5A7|cP#Yi5(&l=p_baTg<jvT2)D5pZW
za9xEgIkr^@_u5dQk9RQ=i%@KPWMz;=eK)yaND)$YSD{?CY6X<t6b1yQz%(p8+F%M}
zmNC$RBJ7)qYL7KRwV#JdnNaPQ3SrXUi%?AMUnSS7wL-P$bG5RO%0g{Ps47L>SA}WR
zc$#lURV=C!D`>hijbd~ztJ;K$w^RrfYgmTL!o6Y;79oJNic6v5qq*Y1J$c?jYb`u#
zc!=at3lz(`gc3Xdlekn*pjw-0Im}eK6e^e%<gkYZK~xb@P4z}h;1&Q_wxl#vMm50Z
qm%^<kc{F23Ei)z`J4Tu&MKk`#`fGcQu?WQ$E@j0!B9<!k$K)5^Qt5yI

literal 0
HcmV?d00001

diff --git a/examples/02631/students/programs/.coverage b/examples/02631/students/programs/.coverage
new file mode 100644
index 0000000000000000000000000000000000000000..11b2ec620c9b142ae8ee79c7a6f5afa297121530
GIT binary patch
literal 53248
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

literal 0
HcmV?d00001

diff --git a/examples/02631/students/programs/__pycache__/looping.cpython-38.pyc b/examples/02631/students/programs/__pycache__/looping.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..fa302e5a102c505ba4b62aa5eab3205ca2683298
GIT binary patch
literal 2019
zcmZux&2Jk;6rY)0+Z)GiLL1Vg6c~vj)fEa!TOm|cA&{z2weo>dAz5y%$<EkWykD7F
zw@I}=xhMe%32u~AbL^Ra1O9<IAR$gUaNx>`_ja8&u6V0`Gw;oN^YPyAz5Az5)d|qw
ze|#wBYlQrT!bxg?umQi>0w#&1A!*ZMWNjvybe@v7BVAd6(UnzMgRvq#IRj%=)nt9Z
z^h4#TilWbF<g9GSQ}VQ&lk@Tod8Y3jQh8P`jGZy1u=hREeDes-AuZp<VL}xctMG5a
zZ*Bq0N$w0>-9V3wJg0}`CV6ma<Vu!P_({&*B1>d}oCC`RGCH<jpk!x#XCVi>a|F(E
zp8Q$oK${};hoQ(6&w@ztVVnga-x7YNbRc+NCy%pju6BK;ByVw(37rLTpZ9bUalz9h
zMdu)idD7$Y>Pyd+V)N}F&dl{<if3KseiEBNDh;M5v?5Hm1z+c-?s_V;h`^$BoQQ?Z
zl;+Nq)S5_IWkVg8f~F9!BV<ixX99RqmL#FE6+eM@HY=9JtF}_?Z0Q|KTb5=oh(=KS
z`}OAa&V8e_>14xg)w!AY!$`qvI>R`~`dUcUO?B`H0@qQyB1%JLI;&Scy1Ld0Vw35i
zpC!7J>I6(9(+QI#g|Mxpd-n8ka6d0%i@7$ZfsuwsUD}{a)T33Z5qmyf{g}|ugTDa6
z&oIH{=j4!%aK<txCu0hbqKibb0UJ?Vhu;NA&^fXUmd6s#`wTo;M!u<lwwfcn$+sxi
zdTbd$gtJnI@)CF;;C}$v!`@Ej<xWlqY)tj{J3r>mi0*KNUjZ$*b;RI)8d;NCSL_C+
zIRn8?ZA}=Vwb-*&$Z_0P)(KT?-AIWTRsAT4ts}OKt;Omw`hgUNO}9O(RWDS2CSqT;
z+3ht;qqcK<ty?6kWV3Lbo%6$?fkb~Ai*U~bW(kyL9vGo@y2vilk0Hbi1H246-@%m$
z;T)?CM{^z+25_J3(;k!Xw5MJUm4+e4>S;~o249M<XVLW%us)RC13sb$5PKJP91wls
zfC6`87YfnM=}&COy;owbxIQ41t*lzAUocw_lgCPb1|XHTK1|ce{KPZsH^RVVeiEhY
z@8g*W*(zc1)k%Xqx!6-0(OOjImw?fg8)4#$(5%Dc*s;m<9Jpz`bkk`!APHuul|*~}
zHm<yb47b)7kQD)*e|_usV98(r2-6(+RA8oJ+JaS#X$jgs0f<7s8dK<BA9UD=eMd59
zpY#C2ucAGs(t$3znA7L(0e}#Kw^-~^=D~fk&cAroWG?fs#6WSuq22~uWIWqe(7cNB
z<Uu?UmG%Rp$__Pk+o?3-TZ%L;VJYQw4Ez9Y3%8k0A3)rJD?m6AG?wnZpq4&*l`Q=(
zsMp{(*vBzT^N=B}qU4df9b*nd_5T?<!tgaKWttGgc1Fd}hBRjA49Zmj=!j+0u`G~n
zCy-Yx4a%c2FO!tLe%57JGT2~<TZf)APtQY9Xw+J-+l@pJcf0*xo&hai+vxxP8_?aW
z8>QyiKcDok7IbB!ocsz)J)~O?kBz|#cPHf9#t~xd2#c**w-va3x>vpj-&S<Fq7n<}
zyu3mzBGv8M3Ut^wgAR=?qkL6?#)1`S^ln6n9ENHgJ7v*EJ?b%U!JGAJUc+<$1EnzH
AG5`Po

literal 0
HcmV?d00001

diff --git a/examples/02631/students/programs/__pycache__/report1intro.cpython-38.pyc b/examples/02631/students/programs/__pycache__/report1intro.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ddadca6243eeebd021c63d8d875e9092033e1190
GIT binary patch
literal 7198
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
VDuv%8Mk<jzm3sp9WX?{R{{s&mC>a0%

literal 0
HcmV?d00001

diff --git a/examples/02631/students/programs/looping.py b/examples/02631/students/programs/looping.py
new file mode 100644
index 0000000..34517b1
--- /dev/null
+++ b/examples/02631/students/programs/looping.py
@@ -0,0 +1,62 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+import numpy as np
+import itertools
+
+def bacteriaGrowth(n0, alpha, K, N): 
+    """
+    Calculate time until bacteria growth exceed N starting from a population of n0 bacteria.
+    hints:
+        * consider n0
+        * alpha > 0
+    :param n0:
+    :param alpha:
+    :param K:
+    :param N:
+    :return:
+    """
+    # TODO: 7 lines missing.
+    raise NotImplementedError("Implement function body")
+
+def clusterAnalysis(reflectance):
+    reflectance = np.asarray(reflectance)
+    I1 = np.arange(len(reflectance)) % 2 == 1
+    while True:
+        m = np.asarray( [np.mean( reflectance[~I1] ),  np.mean( reflectance[I1] ) ] )
+        I1_ = np.argmin( np.abs( reflectance[:, np.newaxis] - m[np.newaxis, :] ), axis=1) == 1
+        if all(I1_ == I1):
+            break
+        I1 = I1_
+    return I1 + 1
+
+def fermentationRate(measuredRate, lowerBound, upperBound):
+    # Insert your code here
+    return np.mean( [r for r in measuredRate if lowerBound < r < upperBound] )
+
+
+
+
+def removeIncomplete(id):
+    """ Hints:
+    * Take a look at the example in the exercise.
+    """
+    id = np.asarray(id)
+    id2 = []
+    for i, v in enumerate(id):
+        if len( [x for x in id if int(x) == int(v) ] ) == 3:
+            id2.append(v)
+    return np.asarray(id2)
+
+
+if __name__ == "__main__":
+    # I = clusterAnalysis([1.7, 1.6, 1.3, 1.3, 2.8, 1.4, 2.8, 2.6, 1.6, 2.7])
+    # print(I)
+
+    print(fermentationRate(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 15, 25))
+
+
+    # print(removeIncomplete(np.array([1.3, 2.2, 2.3, 4.2, 5.1, 3.2, 5.3, 3.3, 2.1, 1.1, 5.2, 3.1])))
+
+    # Problem 1: Write a function which add two numbers
+    # clusterAnalysis([2, 1, 2, 4, 5])
diff --git a/examples/02631/students/programs/report1intro.py b/examples/02631/students/programs/report1intro.py
new file mode 100644
index 0000000..587129b
--- /dev/null
+++ b/examples/02631/students/programs/report1intro.py
@@ -0,0 +1,142 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+from src.unitgrade2.unitgrade2 import Report, UTestCase, cache
+from src.unitgrade2 import evaluate_report_student
+import numpy as np
+import looping
+from looping import bacteriaGrowth, clusterAnalysis, removeIncomplete, fermentationRate
+
+def trlist(x):
+    s = str(list(x))
+    if len(s) > 30:
+        s = s[:30] + "...]"
+    return s
+
+class Bacteria(UTestCase):
+    """ Bacteria growth rates """
+
+    def stest(self, n0, alpha, K, N):
+        g = bacteriaGrowth(n0=n0, alpha=alpha, K=K, N=N)
+        self.title = f"bacteriaGrowth({n0}, {alpha}, {K}, {N}) = {g} ?"
+        self.assertEqualC(g)
+
+    def test_growth1(self):
+        """ Hints:
+        * Make sure to frobulate the frobulator.
+        """
+        self.stest(100, 0.4, 1000, 500)
+
+    def test_growth2(self):
+        self.stest(10, 0.4, 1000, 500)
+
+    def test_growth3(self):
+        self.stest(100, 1.4, 1000, 500)
+
+    def test_growth4(self):
+        self.stest(100, 0.0004, 1000, 500)
+
+    def test_growth5(self):
+        """
+        hints:
+        * What happens when n0 > N? (in this case return t=0) """
+        self.stest(100, 0.4, 1000, 99)
+
+class ClusterAnalysis(UTestCase):
+    """ Test the cluster analysis method """
+
+    def stest(self, n, seed):
+        np.random.seed(seed)
+        x = np.round(np.random.rand(n), 1)
+        I = clusterAnalysis(x)
+        self.title = f"clusterAnalysis({list(x)}) = {list(I)} ?"
+        self.assertEqualC(list(I))
+
+    def test_cluster1(self):
+        """ Hints:
+        * Make sure to frobulate the frobulator.
+        * Just try harder
+        """
+        self.stest(3, 10)
+
+    def test_cluster2(self):
+        self.stest(4, 146)
+
+    def test_cluster3(self):
+        self.stest(5, 12)
+
+    def test_cluster4(self):
+        """
+        Cluster analysis for tied lists
+        Hints:
+        * It may be that an observations has the same distance to the two clusters. Where do you assign it in this case?
+        """
+        x = np.array([10.0, 12.0, 10.0, 12.0, 9.0, 11.0, 11.0, 13.0])
+        self.assertEqualC(list(clusterAnalysis(x) ) )
+
+
+class RemoveIncomplete(UTestCase):
+    """ Remove incomplete IDs """
+
+    def stest(self, x):
+        I = list( removeIncomplete(x) )
+        self.title = f"removeId({trlist(x)}) = {trlist(I)} ?"
+        self.assertEqualC(I)
+
+    @cache
+    def rseq(self, max, n):
+        np.random.seed(42)
+        return np.random.randint(max, size=(n,) ) + (np.random.randint(2, size=(n,) )+1)/10
+
+    def test_incomplete1(self):
+        self.stest( np.array([1.3, 2.2, 2.3, 4.2, 5.1, 3.2, 5.3, 3.3, 2.1, 1.1, 5.2, 3.1]) )
+
+    def test_incomplete2(self):
+        self.stest( np.array([1.1, 1.2, 1.3, 2.1, 2.2, 2.3]) )
+
+    def test_incomplete3(self):
+        self.stest(np.array([5.1, 5.2, 4.1, 4.3, 4.2, 8.1, 8.2, 8.3]) )
+
+    def test_incomplete4(self):
+        self.stest(np.array([1.1, 1.3, 2.1, 2.2, 3.1, 3.3, 4.1, 4.2, 4.3]) )
+
+    def test_incomplete5(self):
+        self.stest(self.rseq(10, 40))
+
+
+class FermentationRate(UTestCase):
+    """ Test the fermentation rate question """
+
+    def stest(self, x, lower, upper):
+        I =  fermentationRate(x, lower, upper)
+        s = trlist(x)
+        self.title = f"fermentationRate({s}, {lower}, {upper}) = {I:.3f} ?"
+        self.assertEqualC(I)
+
+    @cache
+    def rseq(self, max, n):
+        np.random.seed(42)
+        return np.random.randint(max, size=(n,) ) + (np.random.randint(3, size=(n,) )+1)/n
+
+    def test_rate1(self):
+        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 15, 25)
+
+    def test_rate2(self):
+        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 1, 200)
+
+    def test_rate3(self):
+        self.stest(np.array([1.75]), 1, 2)
+
+    def test_rate4(self):
+        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 18.2, 20)
+
+
+class Report1Flat(Report):
+    title = "Week 4: Looping"
+    questions = [(ClusterAnalysis, 10), (RemoveIncomplete, 10), (Bacteria, 10),  (FermentationRate, 10),]
+    pack_imports = [looping]
+
+if __name__ == "__main__":
+    # Uncomment to simply run everything as a unittest:
+    # unittest.main(verbosity=2)
+    evaluate_report_student(Report1Flat())
diff --git a/examples/02631/students/programs/report1intro_grade.py b/examples/02631/students/programs/report1intro_grade.py
new file mode 100644
index 0000000..e7ffde8
--- /dev/null
+++ b/examples/02631/students/programs/report1intro_grade.py
@@ -0,0 +1,339 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+import numpy as np
+from tabulate import tabulate
+from datetime import datetime
+import pyfiglet
+import unittest
+import inspect
+import os
+import argparse
+import time
+
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
+To run all tests in a report: 
+
+> python assignment1_dp.py
+
+To run only question 2 or question 2.1
+
+> python assignment1_dp.py -q 2
+> python assignment1_dp.py -q 2.1
+
+Note this scripts does not grade your report. To grade your report, use:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
+parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
+parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
+parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
+parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
+
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+    args = parser.parse_args()
+    if question is None and args.q is not None:
+        question = args.q
+        if "." in question:
+            question, qitem = [int(v) for v in question.split(".")]
+        else:
+            question = int(question)
+
+    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
+        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
+
+    if unmute is None:
+        unmute = args.unmute
+    if passall is None:
+        passall = args.passall
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+                                          show_tol_err=show_tol_err)
+
+
+    if question is None:
+        print("Provisional evaluation")
+        tabulate(table_data)
+        table = table_data
+        print(tabulate(table))
+        print(" ")
+
+    fr = inspect.getouterframes(inspect.currentframe())[1].filename
+    gfile = os.path.basename(fr)[:-3] + "_grade.py"
+    if os.path.exists(gfile):
+        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
+        print(">>>", gfile)
+        print("In the same manner as you ran this file.")
+
+
+    return results
+
+
+def upack(q):
+    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
+    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
+    h = np.asarray(h)
+    return h[:,0], h[:,1], h[:,2],
+
+class UnitgradeTextRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+class SequentialTestLoader(unittest.TestLoader):
+    def getTestCaseNames(self, testCaseClass):
+        test_names = super().getTestCaseNames(testCaseClass)
+        # testcase_methods = list(testCaseClass.__dict__.keys())
+        ls = []
+        for C in testCaseClass.mro():
+            if issubclass(C, unittest.TestCase):
+                ls = list(C.__dict__.keys()) + ls
+        testcase_methods = ls
+        test_names.sort(key=testcase_methods.index)
+        return test_names
+
+def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
+                    show_progress_bar=True,
+                    show_tol_err=False,
+                    big_header=True):
+
+    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"
+    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
+    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(s, "(use --help for options)" if show_help_flag else "")
+    # print(f"Loaded answers from: ", report.computed_answers_file, "\n")
+    table_data = []
+    # nL =
+    t_start = time.time()
+    score = {}
+    loader = SequentialTestLoader()
+
+    for n, (q, w) in enumerate(report.questions):
+        if question is not None and n+1 != question:
+            continue
+        suite = loader.loadTestsFromTestCase(q)
+        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
+        q_title_print = "Question %i: %s"%(n+1, qtitle)
+        print(q_title_print, end="")
+        q.possible = 0
+        q.obtained = 0
+        q_ = {} # Gather score in this class.
+        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)
+
+        possible = res.testsRun
+        obtained = len(res.successes)
+
+        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun
+
+        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0
+        score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle}
+        q.obtained = obtained
+        q.possible = possible
+
+        s1 = f"Question {n+1} total"
+        s2 = f" {q.obtained}/{w}"
+        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )
+        print(" ")
+        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])
+
+    ws, possible, obtained = upack(score)
+    possible = int( msum(possible) )
+    obtained = int( msum(obtained) ) # Cast to python int
+    report.possible = possible
+    report.obtained = obtained
+    now = datetime.now()
+    dt_string = now.strftime("%H:%M:%S")
+
+    dt = int(time.time()-t_start)
+    minutes = dt//60
+    seconds = dt - minutes*60
+    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")
+
+    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
+
+
+from tabulate import tabulate
+from datetime import datetime
+import inspect
+import json
+import os
+import bz2
+import pickle
+import os
+
+def bzwrite(json_str, token): # to get around obfuscation issues
+    with getattr(bz2, 'open')(token, "wt") as f:
+        f.write(json_str)
+
+def gather_imports(imp):
+    resources = {}
+    m = imp
+    # for m in pack_imports:
+    # print(f"*** {m.__name__}")
+    f = m.__file__
+    # dn = os.path.dirname(f)
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
+        top_package = os.path.dirname(m.__file__)
+        module_import = True
+    else:
+        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
+        module_import = False
+
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = os.path.dirname(top_package)
+    import zipfile
+    # import strea
+    # zipfile.ZipFile
+    import io
+    # file_like_object = io.BytesIO(my_zip_data)
+    zip_buffer = io.BytesIO()
+    with zipfile.ZipFile(zip_buffer, 'w') as zip:
+        # zip.write()
+        for root, dirs, files in os.walk(top_package):
+            for file in files:
+                if file.endswith(".py"):
+                    fpath = os.path.join(root, file)
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
+                    zip.write(fpath, v)
+
+    resources['zipfile'] = zip_buffer.getvalue()
+    resources['top_package'] = top_package
+    resources['module_import'] = module_import
+    return resources, top_package
+
+    if f.endswith("__init__.py"):
+        for root, dirs, files in os.walk(os.path.dirname(f)):
+            for file in files:
+                if file.endswith(".py"):
+                    # print(file)
+                    # print()
+                    v = os.path.relpath(os.path.join(root, file), top_package)
+                    with open(os.path.join(root, file), 'r') as ff:
+                        resources[v] = ff.read()
+    else:
+        v = os.path.relpath(f, top_package)
+        with open(f, 'r') as ff:
+            resources[v] = ff.read()
+    return resources
+
+import argparse
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
+parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
+
+def gather_upload_to_campusnet(report, output_dir=None):
+    n = report.nL
+    args = parser.parse_args()
+    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
+                                          show_progress_bar=not args.noprogress,
+                                          big_header=not args.autolab)
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
+    # also load the source code of missing files...
+
+    sources = {}
+    print("")
+    if not args.autolab:
+        if len(report.individual_imports) > 0:
+            print("By uploading the .token file, you verify the files:")
+            for m in report.individual_imports:
+                print(">", m.__file__)
+            print("Are created/modified individually by you in agreement with DTUs exam rules")
+            report.pack_imports += report.individual_imports
+
+        if len(report.pack_imports) > 0:
+            print("Including files in upload...")
+            for k, m in enumerate(report.pack_imports):
+                nimp, top_package = gather_imports(m)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
+                nimp['name'] = m.__name__
+                sources[k] = nimp
+                # if len([k for k in nimp if k not in sources]) > 0:
+                print(f" * {m.__name__}")
+                # sources = {**sources, **nimp}
+    results['sources'] = sources
+
+    if output_dir is None:
+        output_dir = os.getcwd()
+
+    payload_out_base = report.__class__.__name__ + "_handin"
+
+    obtain, possible = results['total']
+    vstring = "_v"+report.version if report.version is not None else ""
+
+    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
+    token = os.path.join(output_dir, token)
+    with open(token, 'wb') as f:
+        pickle.dump(results, f)
+
+    if not args.autolab:
+        print(" ")
+        print("To get credit for your results, please upload the single unmodified file: ")
+        print(">", token)
+        # print("To campusnet without any modifications.")
+
+        # print("Now time for some autolab fun")
+
+def source_instantiate(name, report1_source, payload):
+    eval("exec")(report1_source, globals())
+    pl = pickle.loads(bytes.fromhex(payload))
+    report = eval(name)(payload=pl, strict=True)
+    # report.set_payload(pl)
+    return report
+
+
+
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        return Capturing2(stdout=self._stdout)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    # nL =\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"Question {n+1} total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nimport numpy as np\nimport looping\nfrom looping import bacteriaGrowth, clusterAnalysis, removeIncomplete, fermentationRate\n\ndef trlist(x):\n    s = str(list(x))\n    if len(s) > 30:\n        s = s[:30] + "...]"\n    return s\n\nclass Bacteria(UTestCase):\n    """ Bacteria growth rates """\n\n    def stest(self, n0, alpha, K, N):\n        g = bacteriaGrowth(n0=n0, alpha=alpha, K=K, N=N)\n        self.title = f"bacteriaGrowth({n0}, {alpha}, {K}, {N}) = {g} ?"\n        self.assertEqualC(g)\n\n    def test_growth1(self):\n        """ Hints:\n        * Make sure to frobulate the frobulator.\n        """\n        self.stest(100, 0.4, 1000, 500)\n\n    def test_growth2(self):\n        self.stest(10, 0.4, 1000, 500)\n\n    def test_growth3(self):\n        self.stest(100, 1.4, 1000, 500)\n\n    def test_growth4(self):\n        self.stest(100, 0.0004, 1000, 500)\n\n    def test_growth5(self):\n        """\n        hints:\n        * What happens when n0 > N? (in this case return t=0) """\n        self.stest(100, 0.4, 1000, 99)\n\nclass ClusterAnalysis(UTestCase):\n    """ Test the cluster analysis method """\n\n    def stest(self, n, seed):\n        np.random.seed(seed)\n        x = np.round(np.random.rand(n), 1)\n        I = clusterAnalysis(x)\n        self.title = f"clusterAnalysis({list(x)}) = {list(I)} ?"\n        self.assertEqualC(list(I))\n\n    def test_cluster1(self):\n        """ Hints:\n        * Make sure to frobulate the frobulator.\n        * Just try harder\n        """\n        self.stest(3, 10)\n\n    def test_cluster2(self):\n        self.stest(4, 146)\n\n    def test_cluster3(self):\n        self.stest(5, 12)\n\n    def test_cluster4(self):\n        """\n        Cluster analysis for tied lists\n        Hints:\n        * It may be that an observations has the same distance to the two clusters. Where do you assign it in this case?\n        """\n        x = np.array([10.0, 12.0, 10.0, 12.0, 9.0, 11.0, 11.0, 13.0])\n        self.assertEqualC(list(clusterAnalysis(x) ) )\n\n\nclass RemoveIncomplete(UTestCase):\n    """ Remove incomplete IDs """\n\n    def stest(self, x):\n        I = list( removeIncomplete(x) )\n        self.title = f"removeId({trlist(x)}) = {trlist(I)} ?"\n        self.assertEqualC(I)\n\n    @cache\n    def rseq(self, max, n):\n        np.random.seed(42)\n        return np.random.randint(max, size=(n,) ) + (np.random.randint(2, size=(n,) )+1)/10\n\n    def test_incomplete1(self):\n        self.stest( np.array([1.3, 2.2, 2.3, 4.2, 5.1, 3.2, 5.3, 3.3, 2.1, 1.1, 5.2, 3.1]) )\n\n    def test_incomplete2(self):\n        self.stest( np.array([1.1, 1.2, 1.3, 2.1, 2.2, 2.3]) )\n\n    def test_incomplete3(self):\n        self.stest(np.array([5.1, 5.2, 4.1, 4.3, 4.2, 8.1, 8.2, 8.3]) )\n\n    def test_incomplete4(self):\n        self.stest(np.array([1.1, 1.3, 2.1, 2.2, 3.1, 3.3, 4.1, 4.2, 4.3]) )\n\n    def test_incomplete5(self):\n        self.stest(self.rseq(10, 40))\n\n\nclass FermentationRate(UTestCase):\n    """ Test the fermentation rate question """\n\n    def stest(self, x, lower, upper):\n        I =  fermentationRate(x, lower, upper)\n        s = trlist(x)\n        self.title = f"fermentationRate({s}, {lower}, {upper}) = {I:.3f} ?"\n        self.assertEqualC(I)\n\n    @cache\n    def rseq(self, max, n):\n        np.random.seed(42)\n        return np.random.randint(max, size=(n,) ) + (np.random.randint(3, size=(n,) )+1)/n\n\n    def test_rate1(self):\n        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 15, 25)\n\n    def test_rate2(self):\n        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 1, 200)\n\n    def test_rate3(self):\n        self.stest(np.array([1.75]), 1, 2)\n\n    def test_rate4(self):\n        self.stest(np.array([20.1, 19.3, 1.1, 18.2, 19.7, 121.1, 20.3, 20.0]), 18.2, 20)\n\n\nclass Report1Flat(Report):\n    title = "Week 4: Looping"\n    questions = [(ClusterAnalysis, 10), (RemoveIncomplete, 10), (Bacteria, 10),  (FermentationRate, 10),]\n    pack_imports = [looping]'
+report1_payload = '80049592150000000000007d94288c0f436c7573746572416e616c79736973947d94288c0f436c7573746572416e616c79736973948c0d746573745f636c7573746572319486948c057469746c659486948c2e636c7573746572416e616c79736973285b302e382c20302e302c20302e365d29203d205b312c20322c20315d203f946803680486948c066173736572749486947d944b005d94288c156e756d70792e636f72652e6d756c74696172726179948c067363616c61729493948c056e756d7079948c0564747970659493948c02693494898887945294284b038c013c944e4e4e4affffffff4affffffff4b007494624304010000009486945294681068164304020000009486945294681068164304010000009486945294657368038c0d746573745f636c757374657232948694680686948c36636c7573746572416e616c79736973285b302e352c20302e362c20302e332c20302e335d29203d205b322c20322c20312c20315d203f94680368228694680a86947d944b005d9428681068164304020000009486945294681068164304020000009486945294681068164304010000009486945294681068164304010000009486945294657368038c0d746573745f636c757374657233948694680686948c3e636c7573746572416e616c79736973285b302e322c20302e372c20302e332c20302e352c20302e305d29203d205b312c20322c20312c20322c20315d203f94680368368694680a86947d944b005d9428681068164304010000009486945294681068164304020000009486945294681068164304010000009486945294681068164304020000009486945294681068164304010000009486945294657368038c0d746573745f636c757374657234948694680a86947d944b005d942868106816430401000000948694529468106816430402000000948694529468106816430401000000948694529468106816430402000000948694529468106816430401000000948694529468106816430401000000948694529468106816430401000000948694529468106816430402000000948694529465738c0474696d6594473fdf6c8500000000758c1052656d6f7665496e636f6d706c657465947d94288c1052656d6f7665496e636f6d706c657465948c10746573745f696e636f6d706c657465319486948c057469746c659486948c5372656d6f76654964285b312e332c20322e322c20322e332c20342e322c20352e312c20332e322c2e2e2e5d29203d205b322e322c20322e332c20352e312c20332e322c20352e332c20332e332c2e2e2e5d203f94686d686e86948c066173736572749486947d944b005d9428681068138c02663894898887945294284b0368174e4e4e4affffffff4affffffff4b0074946243089a9999999999014094869452946810687a4308666666666666024094869452946810687a4308666666666666144094869452946810687a43089a9999999999094094869452946810687a4308333333333333154094869452946810687a43086666666666660a4094869452946810687a4308cdcccccccccc004094869452946810687a4308cdcccccccccc144094869452946810687a4308cdcccccccccc084094869452946573686d8c10746573745f696e636f6d706c65746532948694687086948c4b72656d6f76654964285b312e312c20312e322c20312e332c20322e312c20322e322c20322e335d29203d205b312e312c20312e322c20312e332c20322e312c20322e322c20322e335d203f94686d68978694687486947d944b005d94286810687a43089a9999999999f13f94869452946810687a4308333333333333f33f94869452946810687a4308cdccccccccccf43f94869452946810687a4308cdcccccccccc004094869452946810687a43089a9999999999014094869452946810687a4308666666666666024094869452946573686d8c10746573745f696e636f6d706c65746533948694687086948c4f72656d6f76654964285b352e312c20352e322c20342e312c20342e332c20342e322c20382e312c2e2e2e5d29203d205b342e312c20342e332c20342e322c20382e312c20382e322c20382e335d203f94686d68b18694687486947d944b005d94286810687a4308666666666666104094869452946810687a4308333333333333114094869452946810687a4308cdcccccccccc104094869452946810687a4308333333333333204094869452946810687a4308666666666666204094869452946810687a43089a9999999999204094869452946573686d8c10746573745f696e636f6d706c65746534948694687086948c4072656d6f76654964285b312e312c20312e332c20322e312c20322e322c20332e312c20332e332c2e2e2e5d29203d205b342e312c20342e322c20342e335d203f94686d68cb8694687486947d944b005d94286810687a4308666666666666104094869452946810687a4308cdcccccccccc104094869452946810687a4308333333333333114094869452946573686d8c10746573745f696e636f6d706c657465359486948c06406361636865948c0472736571948c0966756e63746f6f6c73948c0a5f486173686564536571949394298194284b0a4b28654e7d948c096861736876616c7565948a0884d8ef03874d7f467386946287948694680e8c0c5f7265636f6e73747275637494939468118c076e6461727261799493944b0085944301629487945294284b014b28859468138c02663894898887945294284b0368174e4e4e4affffffff4affffffff4b0074946289424001000066666666666618409a99999999990940cdcccccccccc1c40cdcccccccccc1040cdcccccccccc184033333333333322409a999999999901406666666666661840cdcccccccccc1c40cdcccccccccc10409a999999999909406666666666661c40cdcccccccccc1c40cdcccccccccc0040cdcccccccccc14406666666666661040333333333333f33f6666666666661c406666666666661440333333333333f33f66666666666610409a9999999999c93f6666666666662240cdcccccccccc144066666666666620409a9999999999c93f66666666666622409a99999999990140cdcccccccccc18409a9999999999094066666666666620409a999999999901406666666666661040cdcccccccccc0040cdcccccccccc1840cdcccccccccc10406666666666662040cdcccccccccc1840333333333333f33f9a9999999999094094749462686d68dc8694687086948c5372656d6f76654964285b362e312c20332e322c20372e322c20342e322c20362e322c20392e312c2e2e2e5d29203d205b392e312c20352e322c20312e322c20352e312c20312e322c20392e322c2e2e2e5d203f94686d68dc8694687486947d944b005d94286810687a4308333333333333224094869452946810687a4308cdcccccccccc144094869452946810687a4308333333333333f33f94869452946810687a4308666666666666144094869452946810687a4308333333333333f33f94869452946810687a4308666666666666224094869452946810687a4308cdcccccccccc144094869452946810687a4308666666666666204094869452946810687a4308666666666666224094869452946810687a4308666666666666204094869452946810687a4308666666666666204094869452946810687a4308333333333333f33f94869452946573686a473fcf9dc400000000758c084261637465726961947d94288c084261637465726961948c0c746573745f67726f777468319486948c057469746c659486948c29626163746572696147726f777468283130302c20302e342c20313030302c2035303029203d2037203f946a250100006a2601000086948c066173736572749486947d944b004b07736a250100006a2601000086948c08636f7665726167659486947d94286a250100006a2601000086947d948c0a6c6f6f70696e672e7079947d948c2564656620626163746572696147726f777468286e302c20616c7068612c204b2c204e293a20944b158ce72222220a2020202043616c63756c6174652074696d6520756e74696c2062616374657269612067726f77746820657863656564204e207374617274696e672066726f6d206120706f70756c6174696f6e206f66206e302062616374657269612e0a2020202068696e74733a0a20202020202020202a20636f6e7369646572206e300a20202020202020202a20616c706861203e20300a202020203a706172616d206e303a0a202020203a706172616d20616c7068613a0a202020203a706172616d204b3a0a202020203a706172616d204e3a0a202020203a72657475726e3a0a2020202022222294869473736a250100008c0c746573745f67726f777468329486947d948c0a6c6f6f70696e672e7079947d948c2564656620626163746572696147726f777468286e302c20616c7068612c204b2c204e293a20944b158ce72222220a2020202043616c63756c6174652074696d6520756e74696c2062616374657269612067726f77746820657863656564204e207374617274696e672066726f6d206120706f70756c6174696f6e206f66206e302062616374657269612e0a2020202068696e74733a0a20202020202020202a20636f6e7369646572206e300a20202020202020202a20616c706861203e20300a202020203a706172616d206e303a0a202020203a706172616d20616c7068613a0a202020203a706172616d204b3a0a202020203a706172616d204e3a0a202020203a72657475726e3a0a2020202022222294869473736a250100008c0c746573745f67726f777468339486947d948c0a6c6f6f70696e672e7079947d948c2564656620626163746572696147726f777468286e302c20616c7068612c204b2c204e293a20944b158ce72222220a2020202043616c63756c6174652074696d6520756e74696c2062616374657269612067726f77746820657863656564204e207374617274696e672066726f6d206120706f70756c6174696f6e206f66206e302062616374657269612e0a2020202068696e74733a0a20202020202020202a20636f6e7369646572206e300a20202020202020202a20616c706861203e20300a202020203a706172616d206e303a0a202020203a706172616d20616c7068613a0a202020203a706172616d204b3a0a202020203a706172616d204e3a0a202020203a72657475726e3a0a2020202022222294869473736a250100008c0c746573745f67726f777468349486947d948c0a6c6f6f70696e672e7079947d948c2564656620626163746572696147726f777468286e302c20616c7068612c204b2c204e293a20944b158ce72222220a2020202043616c63756c6174652074696d6520756e74696c2062616374657269612067726f77746820657863656564204e207374617274696e672066726f6d206120706f70756c6174696f6e206f66206e302062616374657269612e0a2020202068696e74733a0a20202020202020202a20636f6e7369646572206e300a20202020202020202a20616c706861203e20300a202020203a706172616d206e303a0a202020203a706172616d20616c7068613a0a202020203a706172616d204b3a0a202020203a706172616d204e3a0a202020203a72657475726e3a0a2020202022222294869473736a250100008c0c746573745f67726f777468359486947d948c0a6c6f6f70696e672e7079947d948c2564656620626163746572696147726f777468286e302c20616c7068612c204b2c204e293a20944b118ce72222220a2020202043616c63756c6174652074696d6520756e74696c2062616374657269612067726f77746820657863656564204e207374617274696e672066726f6d206120706f70756c6174696f6e206f66206e302062616374657269612e0a2020202068696e74733a0a20202020202020202a20636f6e7369646572206e300a20202020202020202a20616c706861203e20300a202020203a706172616d206e303a0a202020203a706172616d20616c7068613a0a202020203a706172616d204b3a0a202020203a706172616d204e3a0a202020203a72657475726e3a0a202020202222229486947373756a250100006a3a01000086946a2801000086948c29626163746572696147726f7774682831302c20302e342c20313030302c2035303029203d203134203f946a250100006a3a01000086946a2c01000086947d944b004b0e736a250100006a3a01000086946a3001000086946a320100006a250100006a4201000086946a2801000086948c29626163746572696147726f777468283130302c20312e342c20313030302c2035303029203d2033203f946a250100006a4201000086946a2c01000086947d944b004b03736a250100006a4201000086946a3001000086946a320100006a250100006a4a01000086946a2801000086948c2f626163746572696147726f777468283130302c20302e303030342c20313030302c2035303029203d2035343934203f946a250100006a4a01000086946a2c01000086947d944b004d7615736a250100006a4a01000086946a3001000086946a320100006a250100006a5201000086946a2801000086948c28626163746572696147726f777468283130302c20302e342c20313030302c20393929203d2030203f946a250100006a5201000086946a2c01000086947d944b004b00736a250100006a5201000086946a3001000086946a32010000686a473fcf9d9a00000000758c104665726d656e746174696f6e52617465947d94288c104665726d656e746174696f6e52617465948c0a746573745f72617465319486948c057469746c659486948c476665726d656e746174696f6e52617465285b32302e312c2031392e332c20312e312c2031382e322c2031392e372c202e2e2e5d2c2031352c20323529203d2031392e363030203f946a7c0100006a7d01000086948c066173736572749486947d944b006810687a43089a999999999933409486945294736a7c0100008c0a746573745f72617465329486946a7f01000086948c476665726d656e746174696f6e52617465285b32302e312c2031392e332c20312e312c2031382e322c2031392e372c202e2e2e5d2c20312c2032303029203d2032392e393735203f946a7c0100006a8901000086946a8301000086947d944b006810687a43089899999999f93d409486945294736a7c0100008c0a746573745f72617465339486946a7f01000086948c286665726d656e746174696f6e52617465285b312e37355d2c20312c203229203d20312e373530203f946a7c0100006a9301000086946a8301000086947d944b006810687a4308000000000000fc3f9486945294736a7c0100008c0a746573745f72617465349486946a7f01000086948c496665726d656e746174696f6e52617465285b32302e312c2031392e332c20312e312c2031382e322c2031392e372c202e2e2e5d2c2031382e322c20323029203d2031392e353030203f946a7c0100006a9d01000086946a8301000086947d944b006810687a43080000000000803340948694529473686a473fc74c0a0000000075752e'
+name="Report1Flat"
+
+report = source_instantiate(name, report1_source, report1_payload)
+output_dir = os.path.dirname(__file__)
+gather_upload_to_campusnet(report, output_dir)
diff --git a/examples/02631/students/programs/unitgrade/Bacteria.pkl b/examples/02631/students/programs/unitgrade/Bacteria.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..b246df45c63387d95bc69cc26deba7770d8249c5
GIT binary patch
literal 2050
zcmeHIO-sW-5Ut;(h~PnwG8B|nN=&syT2Mg`9)kS~vZmW6kY>YXQ}s~r<SEDXH~JI2
zI+JXRt@U6%+CX6DW#60Kmyq|e{`Rp|$gYvDq{VCIDlUDd({06Lb>ElbQF(R!s?!bS
ztAJBgeK4zTv!|81ZP&oI8a2QQ%cgBt;R4R#N_#8bDl#@%9CN9VJkn0V*@_Kbbj6TM
z)+bq<pQ9t4mI5InKkQr4GveuCm-k?1Xo!PY5P7TyP7ONMHfU!reJ_{GCBW;31#S{B
z#X<Q44oRr|U?Ktev4B6hoOhuEv0_r;Jm^U=00xnWi0q3HL=QrH!n87R&kt4H&Ptkf
z46X=czsn^q{eouOgG<P<cEltb;EJ4R+HB1f;!JfN(@Cxp8RiY15&eqM#HqJ*nwhxt
z4#0T(3-8XB-YxvyHJ08j>|OIu-tGRc|6PLlu>Y#P^|=`|FM{fgJcEc;G~u&D;X}YS
z-aA+y{3wYLQ~wrgXSpP?#*%9!Nx)e0$Vi^dgqBH4Ov%}>Y&KeEuf#RNcf&nWCS<H^
c8Rg1+<%w*oMG<W0dnM9%uLV*hAX7}NPbL6<qW}N^

literal 0
HcmV?d00001

diff --git a/examples/02631/students/programs/unitgrade/ClusterAnalysis.pkl b/examples/02631/students/programs/unitgrade/ClusterAnalysis.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..36635371f6e86d5f841a3827696a5909e766532b
GIT binary patch
literal 763
zcma)(Jx_!{5QYKK*r<*6TVg^saEGUbA2D>2P+WT<25}Qexbwm;1;r&+ek61^{!jmb
z&Vq-6XxL(4XWyN9-q}a}?Oju<wF09&aMPR%mR&ExwBQMca!)WWZlgMF!xNO-A`vN*
zfAlN8Q5!Rho|(j=mJE~Nm|T#VZIY2m?0{TBti~E%+X*>mnZODw@RR`C9xd|uvY^pJ
z#^^jxMG|INSfG+eVH#$z#;%nFzxSe8GMUj52VP&EVG4$~RjTLU`~J-bt}1wnfIC-L
z(Hb_ILcAXzy1KObW80iE9;<DuBb3ED(oT9zo>cy17+0ZoiZ-RwZ?gnT>^3fY3H}1A
z#sBb)H++{pe28Ju(}u6YwOY^7dK9OJvuWLnJ@EARSRIMooyovzLr6NMI@@O2jOX+d
D%KPtw

literal 0
HcmV?d00001

diff --git a/examples/02631/students/programs/unitgrade/FermentationRate.pkl b/examples/02631/students/programs/unitgrade/FermentationRate.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..9f5cea13c96d67ff2704de398cd66b78a2db463b
GIT binary patch
literal 618
zcmZo*nHtZ;00y;FG<pQwQj2m^^GXs+GV}9-5=&C2^l+7=7MH{q0ojIA+NSidmSmRX
zq=H!PX=rLSqKypn40RL?E%l6nB$#QTX9N~7*HO^Z(~AYNO?4EEOf?m3LCVYw3>56A
zWH4qh0nKAeEG|whDghc@JH?x!M>MZAx1drlIlm}XFSj(OBr~z7D6tZ#tT;I_C$VVC
zWT0EXN`Q1qNo7GQNQ5cPVoGO6`;?$58s5x3j5bsJ{QSKB0|A)uW+<7G<jgT^CI}ci
z0Bs7IQk=nv<V7Q(SOyFEo&);LzyRbqBTGF?b5n@tB!OmfKzx<Kn<4DXF#}}(Pg`sb
zForom12c3D^~_B{Aqcbt9DYD9H29R!ZGgn+AA2lbG=bURiD?5d@du7kBd{ldF=z^l
OL0zm)Xn=)ssU83q4$F!F

literal 0
HcmV?d00001

diff --git a/examples/02631/students/programs/unitgrade/RemoveIncomplete.pkl b/examples/02631/students/programs/unitgrade/RemoveIncomplete.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..30edf2db7bc0e41f0ada9c1c7443ac1d487a6d9a
GIT binary patch
literal 1444
zcma)6O-sW-5N)fK>Om^hd+=1DETm~`3yOj#jZ~<|A`;szDfEkEtMpLt<OlTTdeGmb
zKSuPfvpY$;p<8qh$?VJ9&AfTDd$;=Xnoh_u<@s5*LHolSdNODY`=cIZl+Ut^`s}J3
zAtt})vo!0n9u?7rhb!9orb(=VQ6xq2fT$#*GBFE=1rZ_Sa@RO8nsY+*4Oqap;2~JX
zA$OB*3ie)ee4ly@elz8E;u7-P9*p~=326;IO8Vm->pGt2On~XPoSx(HXGl#_;N51E
z5fw<PQ{_*O54^$i_R1`|&+GO2=?@I~uoH}5A7|cP#Yi5(&l=p_baTg<jvT2)D5pZW
za9xEgIkr^@_u5dQk9RQ=i%@KPWMz;=eK)yaND)$YSD{?CY6X<t6b1yQz%(p8+F%M}
zmNC$RBJ7)qYL7KRwV#JdnNaPQ3SrXUi%?AMUnSS7wL-P$bG5RO%0g{Ps47L>SA}WR
zc$#lURV=C!D`>hijbd~ztJ;K$w^RrfYgmTL!o6Y;79oJNic6v5qq*Y1J$c?jYb`u#
zc!=at3lz(`gc3Xdlekn*pjw-0Im}eK6e^e%<gkYZK~xb@P4z}h;1&Q_wxl#vMm50Z
qm%^<kc{F23Ei)z`J4Tu&MKk`#`fGcQu?WQ$E@j0!B9<!k$K)5^Qt5yI

literal 0
HcmV?d00001

diff --git a/examples/autolab_example/autolab_example.py b/examples/autolab_example/autolab_example.py
index 6cdf58a..a4bdf62 100644
--- a/examples/autolab_example/autolab_example.py
+++ b/examples/autolab_example/autolab_example.py
@@ -1,9 +1,9 @@
 import os
-from autolab.autolab import deploy_assignment
+from unitgrade_private2.autolab.autolab import deploy_assignment
 
 if __name__ == "__main__":
     wdir = os.getcwd()
-    args = [('example_simplest', 'cs101', 'report1_grade.py', 'report1_grade.py'),
+    args = [('example_simplest', 'programs', 'report1_grade.py', 'report1_grade.py'),
             ('example_framework', 'cs102', 'report2_grade.py', 'report2_grade.py'),
             ('example_docker', 'cs103', 'report3_complete_grade.py', 'report3_grade.py'),
             ]
diff --git a/examples/autolab_example/tmp/cs101/cs101.yml b/examples/autolab_example/tmp/cs101/cs101.yml
index 7631a7f..6dc13d8 100644
--- a/examples/autolab_example/tmp/cs101/cs101.yml
+++ b/examples/autolab_example/tmp/cs101/cs101.yml
@@ -1,14 +1,14 @@
 ---
 
 general:
-  name: cs101
+  name: programs
   description: ''
   display_name: CS 101 Report 1
   handin_filename: Report1_handin.token
   handin_directory: handin
   max_grace_days: 0
-  handout: cs101-handout.tar
-  writeup: writeup/cs101.html
+  handout: programs-handout.tar
+  writeup: writeup/programs.html
   max_submissions: -1
   disable_handins: false
   max_size: 2
diff --git a/examples/autolab_example/tmp/cs101/src/driver_python.py b/examples/autolab_example/tmp/cs101/src/driver_python.py
index 9b3e081..074cc75 100644
--- a/examples/autolab_example/tmp/cs101/src/driver_python.py
+++ b/examples/autolab_example/tmp/cs101/src/driver_python.py
@@ -25,7 +25,7 @@ def pfiles():
 
 student_token_file = 'Report1_handin.token'
 instructor_grade_script = 'report1_grade.py'
-grade_file_relative_destination = "cs101\report1_grade.py"
+grade_file_relative_destination = "programs\report1_grade.py"
 with open(student_token_file, 'rb') as f:
     results = pickle.load(f)
 sources = results['sources'][0]
@@ -55,8 +55,8 @@ def rcom(cm):
 start = time.time()
 rcom(command)
 # pfiles()
-# for f in glob.glob(host_tmp_dir + "/cs101/*"):
-#     print("cs101/", f)
+# for f in glob.glob(host_tmp_dir + "/programs/*"):
+#     print("programs/", f)
 # print("---")
 ls = glob.glob(token)
 # print(ls)
diff --git a/examples/autolab_example/tmp/cs101/src/report1_grade.py b/examples/autolab_example/tmp/cs101/src/report1_grade.py
index 8972ab5..fbbeabf 100644
--- a/examples/autolab_example/tmp/cs101/src/report1_grade.py
+++ b/examples/autolab_example/tmp/cs101/src/report1_grade.py
@@ -453,7 +453,7 @@ def source_instantiate(name, report1_source, payload):
 
 
 
-report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, unmute=False, **kwargs):\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n            # for item in q.items:\n            #     if q.name not in payloads or item.name not in payloads[q.name]:\n            #         s = f"> Broken resource dictionary submitted to unitgrade for question {q.name} and subquestion {item.name}. Framework will not work."\n            #         if strict:\n            #             raise Exception(s)\n            #         else:\n            #             print(s)\n            #     else:\n            #         item._correct_answer_payload = payloads[q.name][item.name][\'payload\']\n            #         item.estimated_time = payloads[q.name][item.name].get("time", 1)\n            #         q.estimated_time = payloads[q.name].get("time", 1)\n            #         if "precomputed" in payloads[q.name][item.name]: # Consider removing later.\n            #             item._precomputed_payload = payloads[q.name][item.name][\'precomputed\']\n            #         try:\n            #             if "title" in payloads[q.name][item.name]: # can perhaps be removed later.\n            #                 item.title = payloads[q.name][item.name][\'title\']\n            #         except Exception as e: # Cannot set attribute error. The title is a function (and probably should not be).\n            #             pass\n            #             # print("bad", e)\n        # self.payloads = payloads\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\nclass MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n    pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        item_title = item_title.split("\\n")[0]\n\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 2\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    @classmethod\n    def question_title(cls):\n        return cls.__doc__.splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    # def _callSetUp(self):\n    #     # Always run before method is called.\n    #     print("asdf")\n    #     pass\n    # @classmethod\n    # def setUpClass(cls):\n    #     # self._cache_put((self.cache_id(), \'title\'), value)\n    #     cls.reset()\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    # def unique_cache_id(self):\n    #     k0 = self.cache_id()\n    #     # key = ()\n    #     i = 0\n    #     for i in itertools.count():\n    #         # key = k0 + (i,)\n    #         if i not in self._cache_get( (k0, \'assert\') ):\n    #             break\n    #     return i\n    #     return key\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n    #\n    # def _cache2_contains(self, key):\n    #     print("Is this needed?")\n    #     self._ensure_cache_exists()\n    #     return key in self.__class__._cache2\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    # try:  # For registering stats.\n    #     import unitgrade_private\n    #     import irlc.lectures\n    #     import xlwings\n    #     from openpyxl import Workbook\n    #     import pandas as pd\n    #     from collections import defaultdict\n    #     dd = defaultdict(lambda: [])\n    #     error_computed = []\n    #     for k1, (q, _) in enumerate(report.questions):\n    #         for k2, item in enumerate(q.items):\n    #             dd[\'question_index\'].append(k1)\n    #             dd[\'item_index\'].append(k2)\n    #             dd[\'question\'].append(q.name)\n    #             dd[\'item\'].append(item.name)\n    #             dd[\'tol\'].append(0 if not hasattr(item, \'tol\') else item.tol)\n    #             error_computed.append(0 if not hasattr(item, \'error_computed\') else item.error_computed)\n    #\n    #     qstats = report.wdir + "/" + report.name + ".xlsx"\n    #\n    #     if os.path.isfile(qstats):\n    #         d_read = pd.read_excel(qstats).to_dict()\n    #     else:\n    #         d_read = dict()\n    #\n    #     for k in range(1000):\n    #         key = \'run_\'+str(k)\n    #         if key in d_read:\n    #             dd[key] = list(d_read[\'run_0\'].values())\n    #         else:\n    #             dd[key] = error_computed\n    #             break\n    #\n    #     workbook = Workbook()\n    #     worksheet = workbook.active\n    #     for col, key in enumerate(dd.keys()):\n    #         worksheet.cell(row=1, column=col+1).value = key\n    #         for row, item in enumerate(dd[key]):\n    #             worksheet.cell(row=row+2, column=col+1).value = item\n    #\n    #     workbook.save(qstats)\n    #     workbook.close()\n    #\n    # except ModuleNotFoundError as e:\n    #     s = 234\n    #     pass\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n        # res = UTextTestRunner(verbosity=2, resultclass=unittest.TextTestResult).run(suite)\n        z = 234\n        # for j, item in enumerate(q.items):\n        #     if qitem is not None and question is not None and j+1 != qitem:\n        #         continue\n        #\n        #     if q_with_outstanding_init is not None: # check for None bc. this must be called to set titles.\n        #         # if not item.question.has_called_init_:\n        #         start = time.time()\n        #\n        #         cc = None\n        #         if show_progress_bar:\n        #             total_estimated_time = q.estimated_time # Use this. The time is estimated for the q itself.  # sum( [q2.estimated_time for q2 in q_with_outstanding_init] )\n        #             cc = ActiveProgress(t=total_estimated_time, title=q_title_print)\n        #         from unitgrade import Capturing # DON\'T REMOVE THIS LINE\n        #         with eval(\'Capturing\')(unmute=unmute):  # Clunky import syntax is required bc. of minify issue.\n        #             try:\n        #                 for q2 in q_with_outstanding_init:\n        #                     q2.init()\n        #                     q2.has_called_init_ = True\n        #\n        #                 # item.question.init()  # Initialize the question. Useful for sharing resources.\n        #             except Exception as e:\n        #                 if not passall:\n        #                     if not silent:\n        #                         print(" ")\n        #                         print("="*30)\n        #                         print(f"When initializing question {q.title} the initialization code threw an error")\n        #                         print(e)\n        #                         print("The remaining parts of this question will likely fail.")\n        #                         print("="*30)\n        #\n        #         if show_progress_bar:\n        #             cc.terminate()\n        #             sys.stdout.flush()\n        #             print(q_title_print, end="")\n        #\n        #         q_time =np.round(  time.time()-start, 2)\n        #\n        #         print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")\n        #         print("=" * nL)\n        #         q_with_outstanding_init = None\n        #\n        #     # item.question = q # Set the parent question instance for later reference.\n        #     item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)\n        #\n        #     if show_progress_bar:\n        #         cc = ActiveProgress(t=item.estimated_time, title=item_title_print)\n        #     else:\n        #         print(item_title_print + ( \'.\'*max(0, nL-4-len(ss)) ), end="")\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        #     if show_progress_bar:\n        #         cc.terminate()\n        #         sys.stdout.flush()\n        #         print(item_title_print + (\'.\' * max(0, nL - 4 - len(ss))), end="")\n        #\n        #     if not hidden:\n        #         ss = "PASS" if current == possible else "*** FAILED"\n        #         if tsecs >= 0.1:\n        #             ss += " ("+ str(tsecs) + " seconds)"\n        #         print(ss)\n\n        # ws, possible, obtained = upack(q_)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nfrom cs101.homework1 import reverse_list, add\nimport unittest\n\nclass Week1(unittest.TestCase):\n    def test_add(self):\n        self.assertEqual(add(2,2), 4)\n        self.assertEqual(add(-100, 5), -95)\n\n    def test_reverse(self):\n        self.assertEqual(reverse_list([1,2,3]), [3,2,1])\n        # print("Bad output\\n\\n")\n\n\nimport cs101\nclass Report1(Report):\n    title = "CS 101 Report 1"\n    questions = [(Week1, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs101]'
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, unmute=False, **kwargs):\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n            # for item in q.items:\n            #     if q.name not in payloads or item.name not in payloads[q.name]:\n            #         s = f"> Broken resource dictionary submitted to unitgrade for question {q.name} and subquestion {item.name}. Framework will not work."\n            #         if strict:\n            #             raise Exception(s)\n            #         else:\n            #             print(s)\n            #     else:\n            #         item._correct_answer_payload = payloads[q.name][item.name][\'payload\']\n            #         item.estimated_time = payloads[q.name][item.name].get("time", 1)\n            #         q.estimated_time = payloads[q.name].get("time", 1)\n            #         if "precomputed" in payloads[q.name][item.name]: # Consider removing later.\n            #             item._precomputed_payload = payloads[q.name][item.name][\'precomputed\']\n            #         try:\n            #             if "title" in payloads[q.name][item.name]: # can perhaps be removed later.\n            #                 item.title = payloads[q.name][item.name][\'title\']\n            #         except Exception as e: # Cannot set attribute error. The title is a function (and probably should not be).\n            #             pass\n            #             # print("bad", e)\n        # self.payloads = payloads\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\nclass MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n    pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        item_title = item_title.split("\\n")[0]\n\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 2\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    @classmethod\n    def question_title(cls):\n        return cls.__doc__.splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    # def _callSetUp(self):\n    #     # Always run before method is called.\n    #     print("asdf")\n    #     pass\n    # @classmethod\n    # def setUpClass(cls):\n    #     # self._cache_put((self.cache_id(), \'title\'), value)\n    #     cls.reset()\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    # def unique_cache_id(self):\n    #     k0 = self.cache_id()\n    #     # key = ()\n    #     i = 0\n    #     for i in itertools.count():\n    #         # key = k0 + (i,)\n    #         if i not in self._cache_get( (k0, \'assert\') ):\n    #             break\n    #     return i\n    #     return key\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n    #\n    # def _cache2_contains(self, key):\n    #     print("Is this needed?")\n    #     self._ensure_cache_exists()\n    #     return key in self.__class__._cache2\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    # try:  # For registering stats.\n    #     import unitgrade_private\n    #     import irlc.lectures\n    #     import xlwings\n    #     from openpyxl import Workbook\n    #     import pandas as pd\n    #     from collections import defaultdict\n    #     dd = defaultdict(lambda: [])\n    #     error_computed = []\n    #     for k1, (q, _) in enumerate(report.questions):\n    #         for k2, item in enumerate(q.items):\n    #             dd[\'question_index\'].append(k1)\n    #             dd[\'item_index\'].append(k2)\n    #             dd[\'question\'].append(q.name)\n    #             dd[\'item\'].append(item.name)\n    #             dd[\'tol\'].append(0 if not hasattr(item, \'tol\') else item.tol)\n    #             error_computed.append(0 if not hasattr(item, \'error_computed\') else item.error_computed)\n    #\n    #     qstats = report.wdir + "/" + report.name + ".xlsx"\n    #\n    #     if os.path.isfile(qstats):\n    #         d_read = pd.read_excel(qstats).to_dict()\n    #     else:\n    #         d_read = dict()\n    #\n    #     for k in range(1000):\n    #         key = \'run_\'+str(k)\n    #         if key in d_read:\n    #             dd[key] = list(d_read[\'run_0\'].values())\n    #         else:\n    #             dd[key] = error_computed\n    #             break\n    #\n    #     workbook = Workbook()\n    #     worksheet = workbook.active\n    #     for col, key in enumerate(dd.keys()):\n    #         worksheet.cell(row=1, column=col+1).value = key\n    #         for row, item in enumerate(dd[key]):\n    #             worksheet.cell(row=row+2, column=col+1).value = item\n    #\n    #     workbook.save(qstats)\n    #     workbook.close()\n    #\n    # except ModuleNotFoundError as e:\n    #     s = 234\n    #     pass\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n        # res = UTextTestRunner(verbosity=2, resultclass=unittest.TextTestResult).run(suite)\n        z = 234\n        # for j, item in enumerate(q.items):\n        #     if qitem is not None and question is not None and j+1 != qitem:\n        #         continue\n        #\n        #     if q_with_outstanding_init is not None: # check for None bc. this must be called to set titles.\n        #         # if not item.question.has_called_init_:\n        #         start = time.time()\n        #\n        #         cc = None\n        #         if show_progress_bar:\n        #             total_estimated_time = q.estimated_time # Use this. The time is estimated for the q itself.  # sum( [q2.estimated_time for q2 in q_with_outstanding_init] )\n        #             cc = ActiveProgress(t=total_estimated_time, title=q_title_print)\n        #         from unitgrade import Capturing # DON\'T REMOVE THIS LINE\n        #         with eval(\'Capturing\')(unmute=unmute):  # Clunky import syntax is required bc. of minify issue.\n        #             try:\n        #                 for q2 in q_with_outstanding_init:\n        #                     q2.init()\n        #                     q2.has_called_init_ = True\n        #\n        #                 # item.question.init()  # Initialize the question. Useful for sharing resources.\n        #             except Exception as e:\n        #                 if not passall:\n        #                     if not silent:\n        #                         print(" ")\n        #                         print("="*30)\n        #                         print(f"When initializing question {q.title} the initialization code threw an error")\n        #                         print(e)\n        #                         print("The remaining parts of this question will likely fail.")\n        #                         print("="*30)\n        #\n        #         if show_progress_bar:\n        #             cc.terminate()\n        #             sys.stdout.flush()\n        #             print(q_title_print, end="")\n        #\n        #         q_time =np.round(  time.time()-start, 2)\n        #\n        #         print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")\n        #         print("=" * nL)\n        #         q_with_outstanding_init = None\n        #\n        #     # item.question = q # Set the parent question instance for later reference.\n        #     item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)\n        #\n        #     if show_progress_bar:\n        #         cc = ActiveProgress(t=item.estimated_time, title=item_title_print)\n        #     else:\n        #         print(item_title_print + ( \'.\'*max(0, nL-4-len(ss)) ), end="")\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        #     if show_progress_bar:\n        #         cc.terminate()\n        #         sys.stdout.flush()\n        #         print(item_title_print + (\'.\' * max(0, nL - 4 - len(ss))), end="")\n        #\n        #     if not hidden:\n        #         ss = "PASS" if current == possible else "*** FAILED"\n        #         if tsecs >= 0.1:\n        #             ss += " ("+ str(tsecs) + " seconds)"\n        #         print(ss)\n\n        # ws, possible, obtained = upack(q_)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nfrom programs.homework1 import reverse_list, add\nimport unittest\n\nclass Week1(unittest.TestCase):\n    def test_add(self):\n        self.assertEqual(add(2,2), 4)\n        self.assertEqual(add(-100, 5), -95)\n\n    def test_reverse(self):\n        self.assertEqual(reverse_list([1,2,3]), [3,2,1])\n        # print("Bad output\\n\\n")\n\n\nimport programs\nclass Report1(Report):\n    title = "CS 101 Report 1"\n    questions = [(Week1, 10)]  # Include a single question for 10 credits.\n    pack_imports = [programs]'
 report1_payload = '8004953f000000000000007d948c055765656b31947d948c2c6e6f20636163686520736565205f73657475705f616e737765727320696e20756e69746772616465322e7079948873732e'
 name="Report1"
 
diff --git a/examples/autolab_example/tmp/cs102/src/driver_python.py b/examples/autolab_example/tmp/cs102/src/driver_python.py
index 092842a..80da44e 100644
--- a/examples/autolab_example/tmp/cs102/src/driver_python.py
+++ b/examples/autolab_example/tmp/cs102/src/driver_python.py
@@ -55,8 +55,8 @@ def rcom(cm):
 start = time.time()
 rcom(command)
 # pfiles()
-# for f in glob.glob(host_tmp_dir + "/cs101/*"):
-#     print("cs101/", f)
+# for f in glob.glob(host_tmp_dir + "/programs/*"):
+#     print("programs/", f)
 # print("---")
 ls = glob.glob(token)
 # print(ls)
diff --git a/examples/autolab_example/tmp/cs103/src/driver_python.py b/examples/autolab_example/tmp/cs103/src/driver_python.py
index ed9bd8b..34e6b0b 100644
--- a/examples/autolab_example/tmp/cs103/src/driver_python.py
+++ b/examples/autolab_example/tmp/cs103/src/driver_python.py
@@ -55,8 +55,8 @@ def rcom(cm):
 start = time.time()
 rcom(command)
 # pfiles()
-# for f in glob.glob(host_tmp_dir + "/cs101/*"):
-#     print("cs101/", f)
+# for f in glob.glob(host_tmp_dir + "/programs/*"):
+#     print("programs/", f)
 # print("---")
 ls = glob.glob(token)
 # print(ls)
diff --git a/examples/example_docker/instructor/cs103/.coverage b/examples/example_docker/instructor/cs103/.coverage
new file mode 100644
index 0000000000000000000000000000000000000000..f386b2198168450113494de5b3b3bd99d653d108
GIT binary patch
literal 53248
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

literal 0
HcmV?d00001

diff --git a/examples/example_docker/instructor/cs103/Report3_handin_25_of_30.token b/examples/example_docker/instructor/cs103/Report3_handin_25_of_30.token
new file mode 100644
index 0000000000000000000000000000000000000000..af7c703d2692f8bf15644581b9cdf6688b4b9c3b
GIT binary patch
literal 117485
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
IHae^R4>-ihm;e9(

literal 0
HcmV?d00001

diff --git a/examples/example_docker/instructor/cs103/Report3_handin_30_of_30.token b/examples/example_docker/instructor/cs103/Report3_handin_30_of_30.token
new file mode 100644
index 0000000000000000000000000000000000000000..0ddcac53870efc12081817272c4b694c4c34fe9e
GIT binary patch
literal 117467
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
CdBY6=

literal 0
HcmV?d00001

diff --git a/examples/example_docker/instructor/cs103/__pycache__/homework1.cpython-38.pyc b/examples/example_docker/instructor/cs103/__pycache__/homework1.cpython-38.pyc
index 4beaff64aef655b294b4513aa4842f7eada9c024..c2ad43883cce209ac9cd30ec4db9f197297be5f1 100644
GIT binary patch
delta 20
acmX@ec94xbl$V!_0SKh07;NM=V+H^%jRWTZ

delta 20
acmX@ec94xbl$V!_0SG=G*4fBy#tZ;7Z3O55

diff --git a/examples/example_docker/instructor/cs103/__pycache__/report3.cpython-38.pyc b/examples/example_docker/instructor/cs103/__pycache__/report3.cpython-38.pyc
index da19a02cc1c508d3eaafcf35b0b34e9d58501d7e..78157d3ccd77777a3e6bdc5d8ef57fa286b7b497 100644
GIT binary patch
delta 25
fcmaFC^@58pl$V!_0SNTx8YFr#Z{&+)Wn=~bPCo@V

delta 25
fcmaFC^@58pl$V!_0SJ`-=_DR!+Q=8l%E$-+RfPrt

diff --git a/examples/example_docker/instructor/cs103/__pycache__/report3_complete.cpython-38.pyc b/examples/example_docker/instructor/cs103/__pycache__/report3_complete.cpython-38.pyc
index 921af5c7208e7aa4d953fa1e4551029aeb05c182..ca3fa7b43ad2a579965093501504022367ac79d6 100644
GIT binary patch
delta 53
zcmcb@dy<zol$V!_0SN3C8zipX$ZNpHDp_2VtT)+?O_h%i#463pEJ-g)Oi7*Gz!uEN
F3;=XP4yFJA

delta 64
zcmX@fdxe)bl$V!_0SI{i=_HzN<TYSp6rJqErYb92nwMFUUX+-UYNQ8e#%HAF6r>gv
LPcCH(W@H2aEmRWf

diff --git a/examples/example_docker/instructor/cs103/deploy.py b/examples/example_docker/instructor/cs103/deploy.py
index 9379f59..e1350f9 100644
--- a/examples/example_docker/instructor/cs103/deploy.py
+++ b/examples/example_docker/instructor/cs103/deploy.py
@@ -4,25 +4,24 @@ from unitgrade_private2.hidden_create_files import setup_grade_file_report
 from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
 from unitgrade_private2.deployment import remove_hidden_methods
 from unitgrade_private2.docker_helpers import docker_run_token_file
-import shutil
 import os
 import glob
 import pickle
 from snipper.snip_dir import snip_dir
+wd = os.path.dirname(__file__)
 
 def deploy_student_files():
     setup_grade_file_report(Report3, minify=False, obfuscate=False, execute=False)
-    # Report3.reset()
 
     fout, ReportWithoutHidden = remove_hidden_methods(Report3, outfile="report3.py")
     setup_grade_file_report(ReportWithoutHidden, minify=False, obfuscate=False, execute=False)
-    sdir = "../../students/cs103"
-    snip_dir(source_dir="../cs103", dest_dir=sdir, clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py', 'report3_complete*.py'])
+    sdir = wd+"/../../students/cs103"
+    snip_dir(source_dir=wd+"/../cs103", dest_dir=sdir, clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py', 'report3_complete*.py'])
     return sdir
 
 def run_student_code_on_docker(Dockerfile, student_token_file):
     token = docker_run_token_file(Dockerfile_location=Dockerfile,
-                          host_tmp_dir=os.path.dirname(Dockerfile) + "/tmp",
+                          host_tmp_dir=os.path.dirname(Dockerfile) + "/home",
                           student_token_file=student_token_file,
                           instructor_grade_script="report3_complete_grade.py")
     with open(token, 'rb') as f:
@@ -32,17 +31,14 @@ def run_student_code_on_docker(Dockerfile, student_token_file):
 if __name__ == "__main__":
     # Step 1: Deploy the students files and return the directory they were written to
     student_directory = deploy_student_files()
-    # import sys
-    # sys.exit()
-    # student_directory = "../../students/cs103"
+
     # Step 2: Simulate that the student run their report script and generate a .token file.
     os.system("cd ../../students && python -m cs103.report3_grade")
     student_token_file = glob.glob(student_directory + "/*.token")[0]
 
-
     # Step 3: Compile the Docker image (obviously you will only do this once; add your packages to requirements.txt).
-    Dockerfile = os.path.dirname(__file__) + "/../unitgrade-docker/Dockerfile"
-    os.system("cd ../unitgrade-docker && docker build --tag unitgrade-docker .")
+    Dockerfile = os.path.dirname(__file__) + "/../../../../docker_images/unitgrade-docker/Dockerfile"
+    os.system(f"cd {os.path.dirname(Dockerfile)} && docker build --tag unitgrade-docker .")
 
     # Step 4: Test the students .token file and get the results-token-file. Compare the contents with the students_token_file:
     checked_token = run_student_code_on_docker(Dockerfile, student_token_file)
diff --git a/examples/example_docker/instructor/cs103/report3.py b/examples/example_docker/instructor/cs103/report3.py
index 6dfbe04..3bdc6e6 100644
--- a/examples/example_docker/instructor/cs103/report3.py
+++ b/examples/example_docker/instructor/cs103/report3.py
@@ -1,5 +1,5 @@
-from unitgrade2.unitgrade2 import UTestCase, Report, hide
-from unitgrade2.unitgrade_helpers2 import evaluate_report_student
+from src.unitgrade2.unitgrade2 import UTestCase, Report
+from src.unitgrade2 import evaluate_report_student
 
 class Week1(UTestCase):
     """ The first question for week 1. """
@@ -21,4 +21,6 @@ class Report3(Report):
     pack_imports = [cs103]
 
 if __name__ == "__main__":
+    # from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
+    # gather_upload_to_campusnet(Report3())
     evaluate_report_student(Report3())
\ No newline at end of file
diff --git a/examples/example_docker/instructor/cs103/report3_complete.py b/examples/example_docker/instructor/cs103/report3_complete.py
index 4e72f82..dd85bd8 100644
--- a/examples/example_docker/instructor/cs103/report3_complete.py
+++ b/examples/example_docker/instructor/cs103/report3_complete.py
@@ -1,5 +1,5 @@
 from unitgrade2.unitgrade2 import UTestCase, Report, hide
-from unitgrade2.unitgrade_helpers2 import evaluate_report_student
+from unitgrade2 import evaluate_report_student
 
 class Week1(UTestCase):
     """ The first question for week 1. """
@@ -30,4 +30,6 @@ class Report3(Report):
     pack_imports = [cs103]
 
 if __name__ == "__main__":
+    # from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
+    # gather_upload_to_campusnet(Report3())
     evaluate_report_student(Report3())
diff --git a/examples/example_docker/instructor/cs103/report3_complete_grade.py b/examples/example_docker/instructor/cs103/report3_complete_grade.py
index b053e48..8ea5f2e 100644
--- a/examples/example_docker/instructor/cs103/report3_complete_grade.py
+++ b/examples/example_docker/instructor/cs103/report3_complete_grade.py
@@ -4,15 +4,10 @@ from tabulate import tabulate
 from datetime import datetime
 import pyfiglet
 import unittest
-# from unitgrade2.unitgrade2 import MySuite
-
 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: 
@@ -113,24 +108,20 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         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)
@@ -140,11 +131,10 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         q.possible = 0
         q.obtained = 0
         q_ = {} # Gather score in this class.
-        # unittest.Te
-        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
         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)
 
@@ -153,20 +143,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) )
@@ -181,15 +167,16 @@ 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") +")")
+    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
 
 
-
-
 from tabulate import tabulate
 from datetime import datetime
 import inspect
@@ -212,7 +199,8 @@ def gather_imports(imp):
     # dn = os.path.dirname(f)
     # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
     # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
-    if m.__class__.__name__ == 'module' and False:
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
         top_package = os.path.dirname(m.__file__)
         module_import = True
     else:
@@ -233,7 +221,7 @@ def gather_imports(imp):
             for file in files:
                 if file.endswith(".py"):
                     fpath = os.path.join(root, file)
-                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
                     zip.write(fpath, v)
 
     resources['zipfile'] = zip_buffer.getvalue()
@@ -277,14 +265,14 @@ def gather_upload_to_campusnet(report, output_dir=None):
     results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
                                           show_progress_bar=not args.noprogress,
                                           big_header=not args.autolab)
-    print(" ")
-    print("="*n)
-    print("Final evaluation")
-    print(tabulate(table_data))
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
     # also load the source code of missing files...
 
     sources = {}
-
+    print("")
     if not args.autolab:
         if len(report.individual_imports) > 0:
             print("By uploading the .token file, you verify the files:")
@@ -297,12 +285,15 @@ def gather_upload_to_campusnet(report, output_dir=None):
             print("Including files in upload...")
             for k, m in enumerate(report.pack_imports):
                 nimp, top_package = gather_imports(m)
-                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
                 nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
                 nimp['name'] = m.__name__
                 sources[k] = nimp
                 # if len([k for k in nimp if k not in sources]) > 0:
-                print(f"*** {m.__name__}")
+                print(f" * {m.__name__}")
                 # sources = {**sources, **nimp}
     results['sources'] = sources
 
@@ -315,15 +306,17 @@ def gather_upload_to_campusnet(report, output_dir=None):
     vstring = "_v"+report.version if report.version is not None else ""
 
     token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
-    token = os.path.join(output_dir, token)
+    token = os.path.normpath(os.path.join(output_dir, token))
+
+
     with open(token, 'wb') as f:
         pickle.dump(results, f)
 
     if not args.autolab:
         print(" ")
-        print("To get credit for your results, please upload the single file: ")
+        print("To get credit for your results, please upload the single unmodified file: ")
         print(">", token)
-        print("To campusnet without any modifications.")
+        # print("To campusnet without any modifications.")
 
         # print("Now time for some autolab fun")
 
@@ -336,8 +329,8 @@ def source_instantiate(name, report1_source, payload):
 
 
 
-report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\n# class MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n#     raise Exception("no suite")\n#     pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        # item_title = item_title.split("\\n")[0]\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    def capture(self):\n        return Capturing2(stdout=self._stdout)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        self._stdout = sys.stdout\n        import io\n        sys.stdout = io.StringIO()\n        super().setUp()\n        # print("Setting up...")\n\n    def _callTearDown(self):\n        sys.stdout = self._stdout\n        super().tearDown()\n        # print("asdfsfd")\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n# from unitgrade2.unitgrade2 import MySuite\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n    @hide\n    def test_add_hidden(self):\n        # This is a hidden test. The @hide-decorator will allow unitgrade to remove the test.\n        # See the output in the student directory for more information.\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n    @hide\n    def test_hidden_fail(self):\n        self.assertEqual(2,3)\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
-report1_payload = '80049586000000000000007d94288c055765656b31947d94288c055765656b31948c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b04756803680486948c0474696d659486944700000000000000008c0474696d6594473f60628000000000758c0d4175746f6d6174696350617373947d94680c473f689d000000000073752e'
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            # print(self.questions)\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                print("q is", q())\n                q()._cache_put(\'time\', q.time) # = q.time\n                report_cache[q.__qualname__] = q._cache2\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            # self._stdout = sys.stdout\n            # sys._stdout = io.StringIO()\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f" * q{n+1})   Total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.normpath(os.path.join(output_dir, token))\n\n\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n    @hide\n    def test_add_hidden(self):\n        # This is a hidden test. The @hide-decorator will allow unitgrade to remove the test.\n        # See the output in the student directory for more information.\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n    @hide\n    def test_hidden_fail(self):\n        self.assertEqual(2,3)\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
+report1_payload = '80049589000000000000007d94288c055765656b31947d942868018c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b047568018c0f746573745f6164645f68696464656e948694680586947d944b004b04738c0474696d6594473fe3b8a400000000758c0d4175746f6d6174696350617373947d94680c473fc45a520000000073752e'
 name="Report3"
 
 report = source_instantiate(name, report1_source, report1_payload)
diff --git a/examples/example_docker/instructor/cs103/report3_grade.py b/examples/example_docker/instructor/cs103/report3_grade.py
index 06bc99f..3b6b512 100644
--- a/examples/example_docker/instructor/cs103/report3_grade.py
+++ b/examples/example_docker/instructor/cs103/report3_grade.py
@@ -4,15 +4,10 @@ from tabulate import tabulate
 from datetime import datetime
 import pyfiglet
 import unittest
-# from unitgrade2.unitgrade2 import MySuite
-
 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: 
@@ -113,24 +108,20 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         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)
@@ -140,11 +131,10 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         q.possible = 0
         q.obtained = 0
         q_ = {} # Gather score in this class.
-        # unittest.Te
-        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
         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)
 
@@ -153,20 +143,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) )
@@ -181,15 +167,16 @@ 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") +")")
+    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
 
 
-
-
 from tabulate import tabulate
 from datetime import datetime
 import inspect
@@ -212,7 +199,8 @@ def gather_imports(imp):
     # dn = os.path.dirname(f)
     # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
     # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
-    if m.__class__.__name__ == 'module' and False:
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
         top_package = os.path.dirname(m.__file__)
         module_import = True
     else:
@@ -233,7 +221,7 @@ def gather_imports(imp):
             for file in files:
                 if file.endswith(".py"):
                     fpath = os.path.join(root, file)
-                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
                     zip.write(fpath, v)
 
     resources['zipfile'] = zip_buffer.getvalue()
@@ -277,14 +265,14 @@ def gather_upload_to_campusnet(report, output_dir=None):
     results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
                                           show_progress_bar=not args.noprogress,
                                           big_header=not args.autolab)
-    print(" ")
-    print("="*n)
-    print("Final evaluation")
-    print(tabulate(table_data))
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
     # also load the source code of missing files...
 
     sources = {}
-
+    print("")
     if not args.autolab:
         if len(report.individual_imports) > 0:
             print("By uploading the .token file, you verify the files:")
@@ -297,12 +285,15 @@ def gather_upload_to_campusnet(report, output_dir=None):
             print("Including files in upload...")
             for k, m in enumerate(report.pack_imports):
                 nimp, top_package = gather_imports(m)
-                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
                 nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
                 nimp['name'] = m.__name__
                 sources[k] = nimp
                 # if len([k for k in nimp if k not in sources]) > 0:
-                print(f"*** {m.__name__}")
+                print(f" * {m.__name__}")
                 # sources = {**sources, **nimp}
     results['sources'] = sources
 
@@ -315,15 +306,17 @@ def gather_upload_to_campusnet(report, output_dir=None):
     vstring = "_v"+report.version if report.version is not None else ""
 
     token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
-    token = os.path.join(output_dir, token)
+    token = os.path.normpath(os.path.join(output_dir, token))
+
+
     with open(token, 'wb') as f:
         pickle.dump(results, f)
 
     if not args.autolab:
         print(" ")
-        print("To get credit for your results, please upload the single file: ")
+        print("To get credit for your results, please upload the single unmodified file: ")
         print(">", token)
-        print("To campusnet without any modifications.")
+        # print("To campusnet without any modifications.")
 
         # print("Now time for some autolab fun")
 
@@ -336,8 +329,8 @@ def source_instantiate(name, report1_source, payload):
 
 
 
-report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\n# class MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n#     raise Exception("no suite")\n#     pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        # item_title = item_title.split("\\n")[0]\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    def capture(self):\n        return Capturing2(stdout=self._stdout)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        self._stdout = sys.stdout\n        import io\n        sys.stdout = io.StringIO()\n        super().setUp()\n        # print("Setting up...")\n\n    def _callTearDown(self):\n        sys.stdout = self._stdout\n        super().tearDown()\n        # print("asdfsfd")\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n# from unitgrade2.unitgrade2 import MySuite\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
-report1_payload = '80049525010000000000007d94288c055765656b31947d94288c055765656b31948c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b04756803680486948c0474696d65948694473f506a000000000068038c0f746573745f6164645f68696464656e948694680686947d944b004b04736803680c8694680a86944700000000000000008c0474696d6594473f926de000000000758c0d4175746f6d6174696350617373947d94288c0d4175746f6d6174696350617373948c10746573745f68696464656e5f6661696c9486948c066173736572749486947d9468158c13746573745f73747564656e745f706173736564948694681886947d946815681b86948c0474696d659486944700000000000000006812473f9894100000000075752e'
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            # print(self.questions)\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                print("q is", q())\n                q()._cache_put(\'time\', q.time) # = q.time\n                report_cache[q.__qualname__] = q._cache2\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            # self._stdout = sys.stdout\n            # sys._stdout = io.StringIO()\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f" * q{n+1})   Total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.normpath(os.path.join(output_dir, token))\n\n\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
+report1_payload = '80049568000000000000007d94288c055765656b31947d942868018c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b04758c0474696d6594473fb71ac800000000758c0d4175746f6d6174696350617373947d946808473fb127100000000073752e'
 name="Report3"
 
 report = source_instantiate(name, report1_source, report1_payload)
diff --git a/examples/example_docker/instructor/cs103/unitgrade/AutomaticPass.pkl b/examples/example_docker/instructor/cs103/unitgrade/AutomaticPass.pkl
index 2a722e2b9c8264b76eca73fec2c7dd84eb0e02d3..9b6ff7ac689837f86e1b0e393993ec7acbb784e8 100644
GIT binary patch
literal 4
LcmZo*@zVnU0@?uq

literal 93
zcmZo*nHt0Z0ku;!dUzd6OY(CQOEQxK5{rwc^az)v7MH{qmz1WY=9R=30L4;MrnF7z
gVFR&>N`TDTDH)6zOh6%)lFZyxpnyBnIEGR^0Ou<p2><{9

diff --git a/examples/example_docker/instructor/cs103/unitgrade/Week1.pkl b/examples/example_docker/instructor/cs103/unitgrade/Week1.pkl
index fe27b785553c86fe6975853b9990eed439d2d5bc..20eb565b4b7903e4aef2d3d44e08726a2b0e14ed 100644
GIT binary patch
delta 22
ZcmWHy<85G>YRmuuwNobY=`$7U0RS=m1aSZW

delta 47
tcmcBu=WAe@>cap5wNo@E^6E=vFlI2dP3d7N$;?fi(l*5%D$7u+2LK2n3he*@

diff --git a/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/Report3_handin_5_of_30.token b/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/Report3_handin_5_of_30.token
deleted file mode 100644
index 675c59014e1063147604cc9ab25520eb3d1bbb5e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3_complete_grade.py b/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3_complete_grade.py
deleted file mode 100644
index b053e48..0000000
--- a/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3_complete_grade.py
+++ /dev/null
@@ -1,345 +0,0 @@
-
-import numpy as np
-from tabulate import tabulate
-from datetime import datetime
-import pyfiglet
-import unittest
-# from unitgrade2.unitgrade2 import MySuite
-
-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: 
-
-> python assignment1_dp.py
-
-To run only question 2 or question 2.1
-
-> python assignment1_dp.py -q 2
-> python assignment1_dp.py -q 2.1
-
-Note this scripts does not grade your report. To grade your report, use:
-
-> python report1_grade.py
-
-Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
-For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
-
-> python -m course_package.report1
-
-see https://docs.python.org/3.9/using/cmdline.html
-""", formatter_class=argparse.RawTextHelpFormatter)
-parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
-parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
-parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
-parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
-parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
-
-def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
-    args = parser.parse_args()
-    if question is None and args.q is not None:
-        question = args.q
-        if "." in question:
-            question, qitem = [int(v) for v in question.split(".")]
-        else:
-            question = int(question)
-
-    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
-        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
-
-    if unmute is None:
-        unmute = args.unmute
-    if passall is None:
-        passall = args.passall
-
-    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
-                                          show_tol_err=show_tol_err)
-
-
-    if question is None:
-        print("Provisional evaluation")
-        tabulate(table_data)
-        table = table_data
-        print(tabulate(table))
-        print(" ")
-
-    fr = inspect.getouterframes(inspect.currentframe())[1].filename
-    gfile = os.path.basename(fr)[:-3] + "_grade.py"
-    if os.path.exists(gfile):
-        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
-        print(">>>", gfile)
-        print("In the same manner as you ran this file.")
-
-
-    return results
-
-
-def upack(q):
-    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
-    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
-    h = np.asarray(h)
-    return h[:,0], h[:,1], h[:,2],
-
-class UnitgradeTextRunner(unittest.TextTestRunner):
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-
-class SequentialTestLoader(unittest.TestLoader):
-    def getTestCaseNames(self, testCaseClass):
-        test_names = super().getTestCaseNames(testCaseClass)
-        # testcase_methods = list(testCaseClass.__dict__.keys())
-        ls = []
-        for C in testCaseClass.mro():
-            if issubclass(C, unittest.TestCase):
-                ls = list(C.__dict__.keys()) + ls
-        testcase_methods = ls
-        test_names.sort(key=testcase_methods.index)
-        return test_names
-
-def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
-                    show_progress_bar=True,
-                    show_tol_err=False,
-                    big_header=True):
-
-    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)
-    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(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)
-        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
-        q_title_print = "Question %i: %s"%(n+1, qtitle)
-        print(q_title_print, end="")
-        q.possible = 0
-        q.obtained = 0
-        q_ = {} # Gather score in this class.
-        # unittest.Te
-        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
-        UTextResult.q_title_print = q_title_print # Hacky
-        UTextResult.show_progress_bar = show_progress_bar # Hacky.
-        UTextResult.number = n
-
-        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)
-
-        possible = res.testsRun
-        obtained = len(res.successes)
-
-        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}"
-        s2 = f" {q.obtained}/{w}"
-        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )
-        print(" ")
-        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])
-
-    ws, possible, obtained = upack(score)
-    possible = int( msum(possible) )
-    obtained = int( msum(obtained) ) # Cast to python int
-    report.possible = possible
-    report.obtained = obtained
-    now = datetime.now()
-    dt_string = now.strftime("%H:%M:%S")
-
-    dt = int(time.time()-t_start)
-    minutes = dt//60
-    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") +")")
-
-    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])
-    results = {'total': (obtained, possible), 'details': score}
-    return results, table_data
-
-
-
-
-from tabulate import tabulate
-from datetime import datetime
-import inspect
-import json
-import os
-import bz2
-import pickle
-import os
-
-def bzwrite(json_str, token): # to get around obfuscation issues
-    with getattr(bz2, 'open')(token, "wt") as f:
-        f.write(json_str)
-
-def gather_imports(imp):
-    resources = {}
-    m = imp
-    # for m in pack_imports:
-    # print(f"*** {m.__name__}")
-    f = m.__file__
-    # dn = os.path.dirname(f)
-    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
-    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
-    if m.__class__.__name__ == 'module' and False:
-        top_package = os.path.dirname(m.__file__)
-        module_import = True
-    else:
-        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
-        module_import = False
-
-    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
-    # top_package = os.path.dirname(top_package)
-    import zipfile
-    # import strea
-    # zipfile.ZipFile
-    import io
-    # file_like_object = io.BytesIO(my_zip_data)
-    zip_buffer = io.BytesIO()
-    with zipfile.ZipFile(zip_buffer, 'w') as zip:
-        # zip.write()
-        for root, dirs, files in os.walk(top_package):
-            for file in files:
-                if file.endswith(".py"):
-                    fpath = os.path.join(root, file)
-                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))
-                    zip.write(fpath, v)
-
-    resources['zipfile'] = zip_buffer.getvalue()
-    resources['top_package'] = top_package
-    resources['module_import'] = module_import
-    return resources, top_package
-
-    if f.endswith("__init__.py"):
-        for root, dirs, files in os.walk(os.path.dirname(f)):
-            for file in files:
-                if file.endswith(".py"):
-                    # print(file)
-                    # print()
-                    v = os.path.relpath(os.path.join(root, file), top_package)
-                    with open(os.path.join(root, file), 'r') as ff:
-                        resources[v] = ff.read()
-    else:
-        v = os.path.relpath(f, top_package)
-        with open(f, 'r') as ff:
-            resources[v] = ff.read()
-    return resources
-
-import argparse
-parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
-
-> python report1_grade.py
-
-Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
-For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
-
-> python -m course_package.report1
-
-see https://docs.python.org/3.9/using/cmdline.html
-""", formatter_class=argparse.RawTextHelpFormatter)
-parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
-parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
-
-def gather_upload_to_campusnet(report, output_dir=None):
-    n = report.nL
-    args = parser.parse_args()
-    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
-                                          show_progress_bar=not args.noprogress,
-                                          big_header=not args.autolab)
-    print(" ")
-    print("="*n)
-    print("Final evaluation")
-    print(tabulate(table_data))
-    # also load the source code of missing files...
-
-    sources = {}
-
-    if not args.autolab:
-        if len(report.individual_imports) > 0:
-            print("By uploading the .token file, you verify the files:")
-            for m in report.individual_imports:
-                print(">", m.__file__)
-            print("Are created/modified individually by you in agreement with DTUs exam rules")
-            report.pack_imports += report.individual_imports
-
-        if len(report.pack_imports) > 0:
-            print("Including files in upload...")
-            for k, m in enumerate(report.pack_imports):
-                nimp, top_package = gather_imports(m)
-                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
-                nimp['report_relative_location'] = report_relative_location
-                nimp['name'] = m.__name__
-                sources[k] = nimp
-                # if len([k for k in nimp if k not in sources]) > 0:
-                print(f"*** {m.__name__}")
-                # sources = {**sources, **nimp}
-    results['sources'] = sources
-
-    if output_dir is None:
-        output_dir = os.getcwd()
-
-    payload_out_base = report.__class__.__name__ + "_handin"
-
-    obtain, possible = results['total']
-    vstring = "_v"+report.version if report.version is not None else ""
-
-    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
-    token = os.path.join(output_dir, token)
-    with open(token, 'wb') as f:
-        pickle.dump(results, f)
-
-    if not args.autolab:
-        print(" ")
-        print("To get credit for your results, please upload the single file: ")
-        print(">", token)
-        print("To campusnet without any modifications.")
-
-        # print("Now time for some autolab fun")
-
-def source_instantiate(name, report1_source, payload):
-    eval("exec")(report1_source, globals())
-    pl = pickle.loads(bytes.fromhex(payload))
-    report = eval(name)(payload=pl, strict=True)
-    # report.set_payload(pl)
-    return report
-
-
-
-report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\n# class MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n#     raise Exception("no suite")\n#     pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        # item_title = item_title.split("\\n")[0]\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    def capture(self):\n        return Capturing2(stdout=self._stdout)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        self._stdout = sys.stdout\n        import io\n        sys.stdout = io.StringIO()\n        super().setUp()\n        # print("Setting up...")\n\n    def _callTearDown(self):\n        sys.stdout = self._stdout\n        super().tearDown()\n        # print("asdfsfd")\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n# from unitgrade2.unitgrade2 import MySuite\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n    @hide\n    def test_add_hidden(self):\n        # This is a hidden test. The @hide-decorator will allow unitgrade to remove the test.\n        # See the output in the student directory for more information.\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n    @hide\n    def test_hidden_fail(self):\n        self.assertEqual(2,3)\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
-report1_payload = '80049586000000000000007d94288c055765656b31947d94288c055765656b31948c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b04756803680486948c0474696d659486944700000000000000008c0474696d6594473f60628000000000758c0d4175746f6d6174696350617373947d94680c473f689d000000000073752e'
-name="Report3"
-
-report = source_instantiate(name, report1_source, report1_payload)
-output_dir = os.path.dirname(__file__)
-gather_upload_to_campusnet(report, output_dir)
\ No newline at end of file
diff --git a/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3_grade.py b/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3_grade.py
deleted file mode 100644
index ecff9f7..0000000
--- a/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/report3_grade.py
+++ /dev/null
@@ -1,347 +0,0 @@
-"""
-Example student code. This file is automatically generated from the files in the instructor-directory
-"""
-import numpy as np
-from tabulate import tabulate
-from datetime import datetime
-import pyfiglet
-import unittest
-# from unitgrade2.unitgrade2 import MySuite
-
-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: 
-
-> python assignment1_dp.py
-
-To run only question 2 or question 2.1
-
-> python assignment1_dp.py -q 2
-> python assignment1_dp.py -q 2.1
-
-Note this scripts does not grade your report. To grade your report, use:
-
-> python report1_grade.py
-
-Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
-For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
-
-> python -m course_package.report1
-
-see https://docs.python.org/3.9/using/cmdline.html
-""", formatter_class=argparse.RawTextHelpFormatter)
-parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
-parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
-parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
-parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
-parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
-
-def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
-    args = parser.parse_args()
-    if question is None and args.q is not None:
-        question = args.q
-        if "." in question:
-            question, qitem = [int(v) for v in question.split(".")]
-        else:
-            question = int(question)
-
-    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
-        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
-
-    if unmute is None:
-        unmute = args.unmute
-    if passall is None:
-        passall = args.passall
-
-    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
-                                          show_tol_err=show_tol_err)
-
-
-    if question is None:
-        print("Provisional evaluation")
-        tabulate(table_data)
-        table = table_data
-        print(tabulate(table))
-        print(" ")
-
-    fr = inspect.getouterframes(inspect.currentframe())[1].filename
-    gfile = os.path.basename(fr)[:-3] + "_grade.py"
-    if os.path.exists(gfile):
-        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
-        print(">>>", gfile)
-        print("In the same manner as you ran this file.")
-
-
-    return results
-
-
-def upack(q):
-    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
-    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
-    h = np.asarray(h)
-    return h[:,0], h[:,1], h[:,2],
-
-class UnitgradeTextRunner(unittest.TextTestRunner):
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-
-class SequentialTestLoader(unittest.TestLoader):
-    def getTestCaseNames(self, testCaseClass):
-        test_names = super().getTestCaseNames(testCaseClass)
-        # testcase_methods = list(testCaseClass.__dict__.keys())
-        ls = []
-        for C in testCaseClass.mro():
-            if issubclass(C, unittest.TestCase):
-                ls = list(C.__dict__.keys()) + ls
-        testcase_methods = ls
-        test_names.sort(key=testcase_methods.index)
-        return test_names
-
-def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
-                    show_progress_bar=True,
-                    show_tol_err=False,
-                    big_header=True):
-
-    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)
-    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(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)
-        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
-        q_title_print = "Question %i: %s"%(n+1, qtitle)
-        print(q_title_print, end="")
-        q.possible = 0
-        q.obtained = 0
-        q_ = {} # Gather score in this class.
-        # unittest.Te
-        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
-        UTextResult.q_title_print = q_title_print # Hacky
-        UTextResult.show_progress_bar = show_progress_bar # Hacky.
-        UTextResult.number = n
-
-        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)
-
-        possible = res.testsRun
-        obtained = len(res.successes)
-
-        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}"
-        s2 = f" {q.obtained}/{w}"
-        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )
-        print(" ")
-        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])
-
-    ws, possible, obtained = upack(score)
-    possible = int( msum(possible) )
-    obtained = int( msum(obtained) ) # Cast to python int
-    report.possible = possible
-    report.obtained = obtained
-    now = datetime.now()
-    dt_string = now.strftime("%H:%M:%S")
-
-    dt = int(time.time()-t_start)
-    minutes = dt//60
-    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") +")")
-
-    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])
-    results = {'total': (obtained, possible), 'details': score}
-    return results, table_data
-
-
-
-
-from tabulate import tabulate
-from datetime import datetime
-import inspect
-import json
-import os
-import bz2
-import pickle
-import os
-
-def bzwrite(json_str, token): # to get around obfuscation issues
-    with getattr(bz2, 'open')(token, "wt") as f:
-        f.write(json_str)
-
-def gather_imports(imp):
-    resources = {}
-    m = imp
-    # for m in pack_imports:
-    # print(f"*** {m.__name__}")
-    f = m.__file__
-    # dn = os.path.dirname(f)
-    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
-    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
-    if m.__class__.__name__ == 'module' and False:
-        top_package = os.path.dirname(m.__file__)
-        module_import = True
-    else:
-        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
-        module_import = False
-
-    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
-    # top_package = os.path.dirname(top_package)
-    import zipfile
-    # import strea
-    # zipfile.ZipFile
-    import io
-    # file_like_object = io.BytesIO(my_zip_data)
-    zip_buffer = io.BytesIO()
-    with zipfile.ZipFile(zip_buffer, 'w') as zip:
-        # zip.write()
-        for root, dirs, files in os.walk(top_package):
-            for file in files:
-                if file.endswith(".py"):
-                    fpath = os.path.join(root, file)
-                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))
-                    zip.write(fpath, v)
-
-    resources['zipfile'] = zip_buffer.getvalue()
-    resources['top_package'] = top_package
-    resources['module_import'] = module_import
-    return resources, top_package
-
-    if f.endswith("__init__.py"):
-        for root, dirs, files in os.walk(os.path.dirname(f)):
-            for file in files:
-                if file.endswith(".py"):
-                    # print(file)
-                    # print()
-                    v = os.path.relpath(os.path.join(root, file), top_package)
-                    with open(os.path.join(root, file), 'r') as ff:
-                        resources[v] = ff.read()
-    else:
-        v = os.path.relpath(f, top_package)
-        with open(f, 'r') as ff:
-            resources[v] = ff.read()
-    return resources
-
-import argparse
-parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
-
-> python report1_grade.py
-
-Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
-For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
-
-> python -m course_package.report1
-
-see https://docs.python.org/3.9/using/cmdline.html
-""", formatter_class=argparse.RawTextHelpFormatter)
-parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
-parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
-
-def gather_upload_to_campusnet(report, output_dir=None):
-    n = report.nL
-    args = parser.parse_args()
-    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
-                                          show_progress_bar=not args.noprogress,
-                                          big_header=not args.autolab)
-    print(" ")
-    print("="*n)
-    print("Final evaluation")
-    print(tabulate(table_data))
-    # also load the source code of missing files...
-
-    sources = {}
-
-    if not args.autolab:
-        if len(report.individual_imports) > 0:
-            print("By uploading the .token file, you verify the files:")
-            for m in report.individual_imports:
-                print(">", m.__file__)
-            print("Are created/modified individually by you in agreement with DTUs exam rules")
-            report.pack_imports += report.individual_imports
-
-        if len(report.pack_imports) > 0:
-            print("Including files in upload...")
-            for k, m in enumerate(report.pack_imports):
-                nimp, top_package = gather_imports(m)
-                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
-                nimp['report_relative_location'] = report_relative_location
-                nimp['name'] = m.__name__
-                sources[k] = nimp
-                # if len([k for k in nimp if k not in sources]) > 0:
-                print(f"*** {m.__name__}")
-                # sources = {**sources, **nimp}
-    results['sources'] = sources
-
-    if output_dir is None:
-        output_dir = os.getcwd()
-
-    payload_out_base = report.__class__.__name__ + "_handin"
-
-    obtain, possible = results['total']
-    vstring = "_v"+report.version if report.version is not None else ""
-
-    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
-    token = os.path.join(output_dir, token)
-    with open(token, 'wb') as f:
-        pickle.dump(results, f)
-
-    if not args.autolab:
-        print(" ")
-        print("To get credit for your results, please upload the single file: ")
-        print(">", token)
-        print("To campusnet without any modifications.")
-
-        # print("Now time for some autolab fun")
-
-def source_instantiate(name, report1_source, payload):
-    eval("exec")(report1_source, globals())
-    pl = pickle.loads(bytes.fromhex(payload))
-    report = eval(name)(payload=pl, strict=True)
-    # report.set_payload(pl)
-    return report
-
-
-
-report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\n# class MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n#     raise Exception("no suite")\n#     pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        # item_title = item_title.split("\\n")[0]\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    def capture(self):\n        return Capturing2(stdout=self._stdout)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        self._stdout = sys.stdout\n        import io\n        sys.stdout = io.StringIO()\n        super().setUp()\n        # print("Setting up...")\n\n    def _callTearDown(self):\n        sys.stdout = self._stdout\n        super().tearDown()\n        # print("asdfsfd")\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n# from unitgrade2.unitgrade2 import MySuite\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
-report1_payload = '80049525010000000000007d94288c055765656b31947d94288c055765656b31948c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b04756803680486948c0474696d65948694473f506a000000000068038c0f746573745f6164645f68696464656e948694680686947d944b004b04736803680c8694680a86944700000000000000008c0474696d6594473f926de000000000758c0d4175746f6d6174696350617373947d94288c0d4175746f6d6174696350617373948c10746573745f68696464656e5f6661696c9486948c066173736572749486947d9468158c13746573745f73747564656e745f706173736564948694681886947d946815681b86948c0474696d659486944700000000000000006812473f9894100000000075752e'
-name="Report3"
-
-report = source_instantiate(name, report1_source, report1_payload)
-output_dir = os.path.dirname(__file__)
-gather_upload_to_campusnet(report, output_dir)
diff --git a/examples/example_docker/run_all_docker.py b/examples/example_docker/run_all_docker.py
new file mode 100644
index 0000000..15e9ea7
--- /dev/null
+++ b/examples/example_docker/run_all_docker.py
@@ -0,0 +1,57 @@
+from unitgrade_private2.docker_helpers import docker_run_token_file
+import os
+import glob
+import pickle
+import time
+
+""" Run all examples on docker. """
+
+if __name__ == "__main__":
+    # Step 0: Compile our two docker images.
+    from unitgrade_private2.docker_helpers import compile_docker_image
+
+    docker_files = [f"{os.getcwd()}/../../docker_images/unitgrade-docker/Dockerfile"]
+    docker_tags = []
+    for f in docker_files:
+        tag = compile_docker_image(f)
+        docker_tags.append( (f, tag) )
+
+    EX_BASE =  f"{os.getcwd()}/../" # Base of examples.
+
+    runs = [
+        ("example_flat", "programs", "programs/report1flat_grade.py", "programs", "programs/report1flat_grade.py",),
+        ("example_simplest", "", "cs101/report1_grade.py", "", "cs101/report1_grade.py", ),
+        ("example_framework", "", "cs102/report2_grade.py", "", "cs102/report2_grade.py", ),
+        ("example_docker", "", "cs103/report3_complete_grade.py", "", "cs103/report3_grade.py",),
+             ]
+    rs = []
+
+    def p2mod(file, base):
+        return ".".join(os.path.normpath(os.path.relpath(file, base)).split(os.sep))[:-3]
+    start = time.time()
+    for ex, ibase, ig, sbase, sg in runs:
+        ibase = f"{EX_BASE}/{ex}/instructor/{ibase}"
+        ig = f"{EX_BASE}/{ex}/instructor/{ig}"
+        sbase = f"{EX_BASE}/{ex}/students/{sbase}"
+        sg = f"{EX_BASE}/{ex}/students/{sg}"
+
+        # Uncomment to run example deployment scripts:
+        # os.system(f"cd {ibase} && python -m {p2mod(os.path.dirname(ig) + '/deploy.py', ibase)}")
+
+        os.system(f"cd {sbase} && python -m { p2mod(sg, sbase) }")
+        stoken = glob.glob(f"{os.path.dirname(sg)}/*.token")[0]
+
+        Dockerfile, tag = docker_tags[0] # Get first docker file.
+        token = docker_run_token_file(Dockerfile_location=Dockerfile,
+                                      host_tmp_dir=os.path.dirname(Dockerfile) + "/tmp",
+                                      student_token_file=stoken,
+                                      instructor_grade_script=ig)
+        with open(token, 'rb') as f:
+            iresults = pickle.load(f)
+        with open(stoken, 'rb') as f:
+            sresults = pickle.load(f)
+        rs.append( (ex, sresults, iresults) )
+
+    for ex, sresults, iresults in rs:
+        print( f"[{ex}]", "Student's score was:", sresults['total'], "score using my eval script", iresults['total'])
+    print("Total elapsed time", time.time()-start, "seconds")
\ No newline at end of file
diff --git a/examples/example_docker/students/cs103/.coverage b/examples/example_docker/students/cs103/.coverage
new file mode 100644
index 0000000000000000000000000000000000000000..f386b2198168450113494de5b3b3bd99d653d108
GIT binary patch
literal 53248
zcmeI)PjAy^90zba4oTA{GE-GWtg8B4rclu|O*;;B5~C{>LSvd>3^6Sb9Or3kNbF!c
zr9DhjU=sID+KuD3x3OvOfa5N^?gem|#18xYY(Gsx8_0TLMPI8){pWceKhNj+<2aAo
zFRov6LMgU9ziowLRXeTex^_tjP17dnRiKwzvb2&`8}wTrSRb`IsV!~%UNCQI`OJ@+
zdAD%eEa!hJRHpvO@8*7(`Xzfm*P;VhAOHafKmY=fK<|1!TRd|{fBa2oHCi(CEnE8W
zdtu|o=K9S|adZ8XYnvk8C(cd^TFPayE`0Bi=ty5|IV~w1x9Qkc=(yV=+>t7DH;_%f
z;?X|3=5fHKC_b;%ohHQ!<u)bJ@twBi?~4a=e=!P>oGp}lVZ4J9k<PZuA;j4v`hxJ~
zmh`1-%OK9hS*N)$x$xxM$!u|YT7N2|GFiS&KT|`cp&k9AT-~CCY|n3U?i;@4+B-5>
z6xKlrZIAM~7sjRay>=z^M9XobV!DA7I-V=!p0vB6Y#v#_MMhH#;SH9C(z?e5x);Yx
z&NZOZk9<VTBzO{ei!$eWinSk+Pfd}dJiFa?gUIi9+a0bPiV>eU^hU)T6*u&f!j4@x
zN7QA%yhGKg$hk)2SY6k7*p&yBzbN`K7o%dh-lE__Pz(5ADpR~Lt!vaO<zDcxMIXHC
zRyXvb?K)L{y-IKS@7|lp7U$>nrw^ls!aVhc69xw>xuHgLuzN();p3y*4fm4aM#8<Q
z)e_!T)MYrfh%1L$^I)H;C=AQzjwZY$Am#L}wl>Zz<v}!BUSqheMJ*<f)In%0P{Fpk
zuFYK~;4;|WuJo;Kxs)7@hlRJ@kf`ZYbD84i{HUgL&;;t$gVo92nM}4gJF7p=Ma?Lw
zt>jmBs0pc>JYpDChuYE#y1p7nUN=ap82wRF^^xQV6{nod6xU}*6(<Q-uO=%Ky=*#L
zoSD&kagX3}iC?FN3c-8&UEq}q!T8zlSmBO1oOj+$884m66hE37m2u8Oy~^*ICpS`2
zmY-%L{WcBy{4$2J%zOG-{#5RlcdZtUCLPQ1smszB9A5zh2W(mt*lKv)FlxWN88uJ7
z_Vn``C(z$k_7rL%3QpadP86)E4N=;$0v>#Vl4y8dOImJxNuYpN13Hxxi0IUZFGe5t
z(+KuCjqTl1lofSN;nDpj^)=P4Xr<k@+-7o_;;V0*Dh>JEC;2?_*g+9RiTYwdJ@b_`
zRiepJ9;j6MOC6%%RNGcF?&Vw;11Ub*k%y9tFG82CP=-!h3JwxwCTdTQtU%blq=R$`
zT__o^t9`DddX?Y#E_s4K$n@s*Z1LPVz1L0pU_89k1G<*CEtTzLGd0vUUOCurCZE$d
zOCNFun+MwsaPVe)1|HMm8f?T0Dpc|jXL5mW@OAU0Mn6~}009U<00Izz00bZa0SG_<
z0uXrj1Pnc;XZij=ZGNSh-<wa&ZCb$s0SG_<0uX=z1Rwwb2tWV=5P-n=0{OHtXR1dl
zmftswnN@zYU}brwT3)_TUS1K^>e`3r*H)GbDPwjznV3JnbiSph=X#&12P(cUZLC$k
z4CqOSO4!|zmCK&pZA&){D)eMWxb4$}4t07?ahIM@sK`C5-D$}{t<;;I{XqH^#|=Wi
zYlog+v4iUJYNaVVEpMNmmMGofhy2s#bIp8izA*nX{~W)72nhiQKmY;|fB*y_009U<
z00Izzz}pkZ8*{q)-XT3<%;@~JgE3{y>dAKusVQSFr@mj{`Tvx8M>Bt=H!Ki<00bZa
z0SG_<0uX=z1Rwwb2>f>eE0xxIS2osa(FA^tC-7?r6Zo}56ZkbXfv;AQ3H(}r0>2hb
z;MaWF@%(U=X7DfSbPD~Ar|6$-Wnh)!^Zb9xysMeN(Hj;BKmY;|fB*y_009U<00Izz
z00fR9&`9^Ly!qx_J;1MS`vbKy#{GZlV!Eg2j(`7;|NnQ4YDE+XKmY;|fB*y_009U<
z00Izzz{wFXbVDof{J(DgqtOo*2tWV=5P$##AOHafKmY;|fB*#EK>@=k<l?{of2Nr~
zo6p|CBBDqTfB*y_009U<00Izz00bZaf&afiHkH<Mr&HRc+xn?ouD5dR9REEkW;*`+
z{}-D1(tI&05cWd=0uX=z1Rwwb2tWV=5P$##AaL>oGW4y2o=T<Dxm+~=ubn=5Wk8N0
z009U<00Izz00bZa0SG_<0uUHqfam{l|3AJLLP7un5P$##AOHafKmY;|fB*zeq5%K>
hKkoleV$C7X5P$##AOHafKmY;|fB*y_0D<uZ{sjSu+NS^j

literal 0
HcmV?d00001

diff --git a/examples/example_docker/students/cs103/Report3_handin_10_of_30.token b/examples/example_docker/students/cs103/Report3_handin_10_of_30.token
index 7231343c1882f4366cfe40348680c8d947889798..3880b47087c30a84d5471426ba613e6421ea54fe 100644
GIT binary patch
delta 8228
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
F@PBGw8_56w

delta 15750
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
Wdq&=#ID4isZFhEDc^2v9`2PXKe~fnk

diff --git a/examples/example_docker/students/cs103/__pycache__/homework1.cpython-38.pyc b/examples/example_docker/students/cs103/__pycache__/homework1.cpython-38.pyc
index 5c552a81fc42feaf0654da24d93270b73dc806af..d82e790ad8cee1871f1919af140451af558d6b85 100644
GIT binary patch
delta 20
acmaFB{(zl3l$V!_0SFA{8f@gg$_xNBQUv4x

delta 20
acmaFB{(zl3l$V!_0SJ`;>1^b_$_xNDDFrkD

diff --git a/examples/example_docker/students/cs103/__pycache__/homework1.cpython-39.pyc b/examples/example_docker/students/cs103/__pycache__/homework1.cpython-39.pyc
index 6dfacc25f48700797f5286eae416edaeaf0e2b5b..0e7a0c627f56abdd78d2ba3ec05f9d13ea233030 100644
GIT binary patch
delta 20
acmX@ec94xbk(ZZ?0SF!^Yj5N>V+H^+dIW_4

delta 20
acmX@ec94xbk(ZZ?0SKbqG&gdaF#`ZD3IpB%

diff --git a/examples/example_docker/students/cs103/__pycache__/report3.cpython-38.pyc b/examples/example_docker/students/cs103/__pycache__/report3.cpython-38.pyc
index da19a02cc1c508d3eaafcf35b0b34e9d58501d7e..78157d3ccd77777a3e6bdc5d8ef57fa286b7b497 100644
GIT binary patch
delta 25
fcmaFC^@58pl$V!_0SNTx8YFr#Z{&+)Wn=~bPCo@V

delta 25
fcmaFC^@58pl$V!_0SJ`-=_DR!+Q=8l%E$-+RfPrt

diff --git a/examples/example_docker/students/cs103/__pycache__/report3_complete.cpython-38.pyc b/examples/example_docker/students/cs103/__pycache__/report3_complete.cpython-38.pyc
index 921af5c7208e7aa4d953fa1e4551029aeb05c182..41e62d06e5af5bb771d3c92d6afde5e8a0d36380 100644
GIT binary patch
delta 24
ecmcb@dxe)bl$V!_0SFES=_c;j$a{>9kr@C^>jp6Z

delta 24
ecmcb@dxe)bl$V!_0SI{i=_HzN<UPj5$Or&RJO!cv

diff --git a/examples/example_docker/students/cs103/__pycache__/report3_complete.cpython-39.pyc b/examples/example_docker/students/cs103/__pycache__/report3_complete.cpython-39.pyc
index 2f18f8be0976727ab41dd1114924b8483c6d3aac..3e87b71662ab4e431da5c9b952594f5411205f72 100644
GIT binary patch
literal 1764
zcma)6&u=3&6t+D-GHKH`%eE{6?P?GRDbgy_Y_A9{Du`Qz*hNTlv4*kJ44KJf?U^n_
z%Z2vO;J_a9FZs$T{{jcfd!A$`MJ-~adGfQL-~0T%&rS{w_6U5x{rxmKb_w|to!t-S
z$aDDh9E>1>=A@u8Em+J7Cw3^#vD_`Z*rVhdA{^mf6X8mF<-|Vtp76o<t>1yzP9DSo
z%m<<i^Igdxt}FM%-i)cAq$j&q<cdPp&I>ZwUqekYa7_36mr_^fiI&FyPA*DS8F!iq
zIiTi|yiD>ssU%l+f$ORka$cplb@y|?c@Dq+6pSP>6(nYY#*SdZxhAnIJ>d%P8p_AM
z@S%Lict1!v8!f}|<y3}~OzA3oRRfZ&oQIQAg|A^b91X*iLeA~SVBo=j4!=GHBPcKg
zto;h-dPDwTZz!<jT(P&U4}}|F5Gd@A6((F!<0L|?F=6)m&CSgk)2^KODAl9Wv*ENX
z<m*z+Mk;`L(@V6Ls`~m>o#f{$W?U`viCtO|bp#QAT}HSis_LnXzADqY0G@PI&$H@6
zB|`Fr$}WM)NdBA@i(Kj`sjD(ie&m~pXgJ)iaZ#o-siJJID^;gesUiz1YPxX7(-Kou
za=7@#1Ql?`;V3?!&}azl(LP-sT7HMy<@;$2VatEfXlZjB+EfRERTs@ZngcX={>JoS
zWRA8aImig)f`J;PPTU?{p4^7Di5Y_+0?y}2AvrgDoEN32a~$_LN76Sd9ggI1t{y--
zg-O+WXj%w%gg6v(fe{)z7*Ll69;0^le*K0J+Ui#@(5@rh=Hh{NJ>j8*%)yt?ydtTx
z^ji?dEoxC*Sk)>Naeyk3Uiy~deTMC9YzYJf?(e8-Mb#lh@0`Sv`OuQNxp#bl8^lA1
z(<od*mml9k(scWF^#4M~-l20EbZflQ>H{<%qG<`Xu=*BO(_cPGviyArYA~_olRGf&
zgpLQk!Xv0-G$&|2LSwu67)NcfwwsS&0b6Y)9?-ynUgF&N{$_p#%WX4lBiV$(Q{+t8
z1&e*zxu9_%T<D2sI?da6wmdq25spqrVdIBqYlOMRhkQKf{tLMAs;tVT6_rI}y4yEQ
z8_!-^(_19zjAsSDtoqKQJ%QZFz~*Q!++Kxqcq57=n{z(cHz)6&l4rwqs89yV_6q4U
zkK3g-ice*}kV-#O_{Ozh)hFm;rRG?7&~Adyo16Fr>RO{hk7<wf5Bott`(8l*0eOCd
AF#rGn

delta 416
zcmY*VJx{|h5X~iZ;#6%KphZF|Eo%frtF8#a0$Ue48Hp&0tt#p#PC9i!sQiJ-JHLPh
z{s#Xb0~0d~8x!YNlyZ`v{O+Egp6{dl?s`$VTr{w5E`z9NExkJ2E{{7cZg4Vmm~&-t
zn>&vNcZ9jH7!@w315+|V1YH;l0MuO@f&21w0>IQ89NHebeaGq(TB>cn`X!`N_tsER
zUuM$uH7{t`*-W-IbE{GB#yI*{CbDxp>5+OMHNOvx2piGi7G@}@XVSdy22}2%M($~-
zBIG1XvZ0VR-kEzh6KR%A#%WICwB72k(lm+(VKSOdWR`9PUB#(rlYIp3mTCtI1t`L*
zm(wsDMaeh}gCeWV#!1$fs%JNF52+no9Q?jr=lT2I#yO{_qY0l4#TjUOy{RgcOy8s6
G6AC}%7f#9m

diff --git a/examples/example_docker/instructor/unitgrade-docker/tmp/cs103/__pycache__/report3_complete_grade.cpython-38.pyc b/examples/example_docker/students/cs103/__pycache__/report3_complete_grade.cpython-39.pyc
similarity index 90%
rename from examples/example_docker/instructor/unitgrade-docker/tmp/cs103/__pycache__/report3_complete_grade.cpython-38.pyc
rename to examples/example_docker/students/cs103/__pycache__/report3_complete_grade.cpython-39.pyc
index 8bcaebe92988bf2a57647836e6aabc65f30fdadc..5efad03805d904ffdc7a11abb12cf5d179ea47c5 100644
GIT binary patch
delta 2103
zcmah~Uu;uV7{BMX>zc0Zx^7*!c3r!5Y<8A)8!#Z7h>AlNFh-XE6}Vn{@7lYyx8>Y>
z%Z#_qtzZB(0!Mivku7Kl@ddJ&ATh>7qt8B>R7qIki#`yel3+}X-*?B@<i*~c-~G<_
z=k%QK`<?IJ{n~c_8=F`3cw8L(7XC?!{y%SeKX8N$j!u~M)4aqPWL2sViI}9!u`e8H
zADGX9*<G=jc5vZXZ~ZV2uXOzn6G|#qEXXO{$jPZa#f(vqRb5LNs-kD9D9J*JDrHfZ
zQ}V1>DCK2sO%SAFW=5tdMb&g_Wb`6sBhEqlAF#1y)wzv#w1Gqe?7Hh*e-nz$2&+nv
z(#=X%EmB!1D4M3ISz$`a%e0*xZRjL5W;VP*hS`ILdv@yMICjt7O~S0n(@mmmt0zfD
zndp(jc37qnhSmz8b5(8{PONYy|1n{AJbh$<)p_G&7fX0w0jzi<;b*{+dJ)C|4#UuR
z04Jeiu;OlZ-+Pff#m+RoMxJKBH16<O{+R34pnYt}H@@pRobN$+9$_ECID+M9!TSH~
z1;bGoYyY#CedfEw8-yKbI)blHn{N9ixCLTHrNE5+JfS!A7&H8*Nf-OuACGjKfhsv-
ztHdkON=%RGaWh&aRZ@wf%to90NQ`Bg4+pxWgw&|_nA~(rl>|AdBgpAJ?EB_htNCLs
zmmq)rfg!S;9SI~Fw%~TRB5Y&l1KlLVmIJx25Guj|HKNf&@J^7L4T_uK=?I!cHr5*B
zsgE6N&5=#)yVjB6C(ye=5Xv&ul%gsKH75j2=}JMS$1tV~;UIe1E#+R83J&?wsI{{9
za1*6qjQH7wV3JI-FN3i;+JGSru~d>(iH^b~Z7*m>fgT4jk)WG#fpt~|aN2@^RG>iw
zWLnLu<%%bToSZKSQ+Y94b7;UaRi}RRXh#p%aU}~5z;sHdK#_KfT80(c+8iSK46=9H
z;+vx=V$#xenxW`&+Hpcxbl|IsI{t)Evr$=F%jl17$v_Gt)(K&8u8(!J&%fFSmJG6P
z?PmkQ2?Keh?E=s_9WHN`H;Keo`S(K=-sBf~lUpK$JIG0#9iFO<aH?;J(*_4QVm*gB
z!hUX-$pV`QMaZu#7n&tHTM6aDk45~pG2*3gZ{$rNn5)uIahvWv+|hi+V|o@FrTQfT
zbWAc9esX6=#b^2!152Dq%*L_*Zo)srohRD68y1E6i6o3pb)2n)g9HB`{nLhM=Ie-%
zEo`7;V)wI<3~F7sZj|BxwR%aRs#uU~E<sQVr6Sb@fyU6{6oitf=YWHCmOxLjTOIwK
zIV*|+1;9w>EYGa0m&LpxQ}bdZ8kh$iJ&o`-!YPFJ*w)C|*Z}V)PJDQdxZv%!wUJgb
z!h4CEBniE|d?#|8C%-T6jtvp)r&?D(Ug|4dJGXaKn)LR?kZCuYmiWi&wwkir8xGBx
zw&^-Z<309Q*Fcow4%V5h;nZTRj#7w?cRz5+Af|btOb@Xa;%9wjv_ud(5&GClynPOD
zCq=5!Nr1FpQ6;6UNQRhym^zJ~L4&&_W@a9#3K(!1;ZfG<1)L_(w;pn5wdzO3sX0KE
zIVoA!oMO7E2~cw!C@Gnlyj-(OMxm7OTbH)xDjIsp&;=+XokiaP1nasCqO^$cAwZ4H
zr0pt{c(pViv2S}iTd-ZE>&wt%;FCe$Lf?7zpl9Bl<gGeEmFP8gdebR#mAQH&(JQ!+
zm&(YKAweq|G$YgNxCmd$)6HzWcL%w-JlFfx=UaB-Vpg*7Leeb4egr(Wm5Q`eq}h^4
zH5uCC>l)27dUtdVlMYQok_50?Ur(z^(P0d;I+u4+p4BI1O@G-?RcJH#?Mb^(vA<~b
z9sEd8><el8v{qE<n>fFUuz+CI;u=af5pDpa8`sXnk}J*-9&@!P;vJ!95wNoK6ZYcD
G#eV@W+XAov

delta 1936
zcmZ{lUu;uV7{Kqj?b_0HZMU^+*R6lYIyVMv;DGT*K^Zf|m^cC9W~969Ubg;O+nswm
z1a2Lys2N6B{0xRfaSIX>jZU+Ki1A;dFGgeHlcs1QFFqK<g9M{5#_zjh%olHSe&;*q
zJLfz1et%ByeP#LOON;wpU7b_Fr|+L`Idktr_iMIL*1`81_Kc_q*)_{jnJLU*SsQ#}
zlf0-tk7`%hVpwsB1CsVlB6gDfhnlq;<zf*|J9-?N6^+^iacR-fC)xry;6C`xdEW0O
zv4OBWiIUU^@?xXNgK(ub!X)^#_B88(e%GA`R$yISf`#BIWCSMbx>-M5sZ#?M-0Z=o
zkv(0g2pN1$LxhOCgRO^s?l!g)GVW)PpSi;=kK!WkCTvF>!KR4_2jkn(+HTn5d6n&e
zuRSAd7j${IdCm3YoaIe}z`gq(*+b*U2#*s63400VLKCa!44~pDwv}@R;7{)*F}nsX
z)DKhld;P~=JvPIPsN&CB=NSJ$kHd|I7gz#zHnxS^41a|UTgq+aXgQ|G^|eN{!YZsB
zB^ivy4i<;E8;|%CN~hw{+YKS(tFVBev<3vd9U6QeIW-%ej!_W2@SX1xdQkQEvOaj-
z-&xyBFTIJd8NTr+STo%5kH?#7B7~?ijUU3klT|I6&O1f^FsV{-qA6y-i=uEU4&VD)
z;AYbkED2&@OHBt(O0X*sXd0%aF~UJa)vBi_R6YQiK(F^O&6=*efA+h97^{bG1Kn&0
z{tm<rRNZ?tP33yJkRRZ@z<Dj1uwh=Qd4>1mK(bC~r3pTQVrM7s#*VKhm5+vv1V5pP
z5P+k>)<8XpK}6MgEIpPQS7k-zT!pz{%$6eEMz|4dTOT2joFmm}rL?X}wn;s$=Tx4f
zIdL*2S-7gLc+S?`?cYE<R>N;*SP}-C&kiP0GfFwO@=(IA!A1_yx)8dcV{KJLgDGM~
zyyz{9hBz-8!UAK$vqGQnv@j$bhPIH(&cJLa%-(_Pq32izVlCtL746lQWOy9Y#96K_
zyA0P};pm}qol!UMQS1v0lPU<mwyYa!D0>a>ynjK!3i0e*H7?At$sjgozDKuYtn>8-
z*7br|_UJytqPXy-{%<E-Yz?zsc&~MT*KYh2Zk9%zqy(aBSJFH$PpDOADwUon7Py{D
z@hHT@el`PJ!(EXva}`%}MOh!`Wg0ogRDDX$l~jHTro&PHG+C<<&Jkt^FT+xJHWm_H
z%t1d<U{35^mLO|lG11Lj*z?Ov!;xbm`)TR(STCd7>5q69Ra_*|A8#nv>&^2a!)nwo
zi2rf3U|2FWb4>dYE+jTYC+V!!9O5)IQ%EDJ8Ez&1aw;fFVrq&Xf}h)Fr%R-1C4>nS
zeaV?G6nS9`Q$~~Qa!D`b<YSyFg;QSeAzIUr&MWDuv{I6D_dTWY7fInN%A?r_Q(4+@
znef2L{2~n>qP6z1X;nX-#zfssa}<oK4c$3<LNTk5le_sTbGn!w&F0jqRVhsrI~&Xr
zsyYiLy;#yy7&U%^maZq5xxJC3D+EAPSyr;<F`~<Xc>|{;Z&5y(1Et;XqpFtdQ+Q>h
z^JDyZ+B6NXw4Ze~iDtMkSo|7<lIPe0yp;?`-z1A}u2O#VrnEwdkE;AS84-&)-VL{s
z+t}iguj7lGo41lN(`!^l{5WAhfxh4LiR6&^SW)JhikH?&jc34qdq;#KBDrKmNujnh
zq2_fyLOXg0{V;OdH%)&ClJkJ7=}#8SYk_X=<p5eUS|QI38ZQve5X>lCBWaQFK0@-W
hd<6Ldt#JCZ<?D&+fxkqcu=1;f)eFNZz}?$3{{lKB%*Fr!

diff --git a/examples/example_docker/students/cs103/__pycache__/report3_grade.cpython-38.pyc b/examples/example_docker/students/cs103/__pycache__/report3_grade.cpython-38.pyc
index 7433fca776754f5b6910141e9adc509cbf13a6f5..fe08941631eb3353b6394ba8fca90bb65c4db357 100644
GIT binary patch
delta 10563
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
M&*C4xcCC>9A3>*p$^ZZW

delta 17866
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
Vo9Hu8&uncSed}L|uTJZw{|o*POrZb(

diff --git a/examples/example_docker/students/cs103/report3.py b/examples/example_docker/students/cs103/report3.py
index c97b5a4..f83bb53 100644
--- a/examples/example_docker/students/cs103/report3.py
+++ b/examples/example_docker/students/cs103/report3.py
@@ -1,8 +1,8 @@
 """
 Example student code. This file is automatically generated from the files in the instructor-directory
 """
-from unitgrade2.unitgrade2 import UTestCase, Report, hide
-from unitgrade2.unitgrade_helpers2 import evaluate_report_student
+from src.unitgrade2.unitgrade2 import UTestCase, Report
+from src.unitgrade2 import evaluate_report_student
 
 class Week1(UTestCase):
     """ The first question for week 1. """
@@ -24,4 +24,6 @@ class Report3(Report):
     pack_imports = [cs103]
 
 if __name__ == "__main__":
+    # from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
+    # gather_upload_to_campusnet(Report3())
     evaluate_report_student(Report3())
diff --git a/examples/example_docker/students/cs103/report3_grade.py b/examples/example_docker/students/cs103/report3_grade.py
index ecff9f7..3c64c04 100644
--- a/examples/example_docker/students/cs103/report3_grade.py
+++ b/examples/example_docker/students/cs103/report3_grade.py
@@ -6,15 +6,10 @@ from tabulate import tabulate
 from datetime import datetime
 import pyfiglet
 import unittest
-# from unitgrade2.unitgrade2 import MySuite
-
 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: 
@@ -115,24 +110,20 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         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)
@@ -142,11 +133,10 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         q.possible = 0
         q.obtained = 0
         q_ = {} # Gather score in this class.
-        # unittest.Te
-        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
         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)
 
@@ -155,20 +145,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) )
@@ -183,15 +169,16 @@ 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") +")")
+    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
 
 
-
-
 from tabulate import tabulate
 from datetime import datetime
 import inspect
@@ -214,7 +201,8 @@ def gather_imports(imp):
     # dn = os.path.dirname(f)
     # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
     # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
-    if m.__class__.__name__ == 'module' and False:
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
         top_package = os.path.dirname(m.__file__)
         module_import = True
     else:
@@ -235,7 +223,7 @@ def gather_imports(imp):
             for file in files:
                 if file.endswith(".py"):
                     fpath = os.path.join(root, file)
-                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
                     zip.write(fpath, v)
 
     resources['zipfile'] = zip_buffer.getvalue()
@@ -279,14 +267,14 @@ def gather_upload_to_campusnet(report, output_dir=None):
     results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
                                           show_progress_bar=not args.noprogress,
                                           big_header=not args.autolab)
-    print(" ")
-    print("="*n)
-    print("Final evaluation")
-    print(tabulate(table_data))
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
     # also load the source code of missing files...
 
     sources = {}
-
+    print("")
     if not args.autolab:
         if len(report.individual_imports) > 0:
             print("By uploading the .token file, you verify the files:")
@@ -299,12 +287,15 @@ def gather_upload_to_campusnet(report, output_dir=None):
             print("Including files in upload...")
             for k, m in enumerate(report.pack_imports):
                 nimp, top_package = gather_imports(m)
-                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
                 nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
                 nimp['name'] = m.__name__
                 sources[k] = nimp
                 # if len([k for k in nimp if k not in sources]) > 0:
-                print(f"*** {m.__name__}")
+                print(f" * {m.__name__}")
                 # sources = {**sources, **nimp}
     results['sources'] = sources
 
@@ -317,15 +308,17 @@ def gather_upload_to_campusnet(report, output_dir=None):
     vstring = "_v"+report.version if report.version is not None else ""
 
     token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
-    token = os.path.join(output_dir, token)
+    token = os.path.normpath(os.path.join(output_dir, token))
+
+
     with open(token, 'wb') as f:
         pickle.dump(results, f)
 
     if not args.autolab:
         print(" ")
-        print("To get credit for your results, please upload the single file: ")
+        print("To get credit for your results, please upload the single unmodified file: ")
         print(">", token)
-        print("To campusnet without any modifications.")
+        # print("To campusnet without any modifications.")
 
         # print("Now time for some autolab fun")
 
@@ -338,8 +331,8 @@ def source_instantiate(name, report1_source, payload):
 
 
 
-report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\n# class MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n#     raise Exception("no suite")\n#     pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        # item_title = item_title.split("\\n")[0]\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    def capture(self):\n        return Capturing2(stdout=self._stdout)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        self._stdout = sys.stdout\n        import io\n        sys.stdout = io.StringIO()\n        super().setUp()\n        # print("Setting up...")\n\n    def _callTearDown(self):\n        sys.stdout = self._stdout\n        super().tearDown()\n        # print("asdfsfd")\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n# from unitgrade2.unitgrade2 import MySuite\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
-report1_payload = '80049525010000000000007d94288c055765656b31947d94288c055765656b31948c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b04756803680486948c0474696d65948694473f506a000000000068038c0f746573745f6164645f68696464656e948694680686947d944b004b04736803680c8694680a86944700000000000000008c0474696d6594473f926de000000000758c0d4175746f6d6174696350617373947d94288c0d4175746f6d6174696350617373948c10746573745f68696464656e5f6661696c9486948c066173736572749486947d9468158c13746573745f73747564656e745f706173736564948694681886947d946815681b86948c0474696d659486944700000000000000006812473f9894100000000075752e'
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            # print(self.questions)\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                print("q is", q())\n                q()._cache_put(\'time\', q.time) # = q.time\n                report_cache[q.__qualname__] = q._cache2\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            # self._stdout = sys.stdout\n            # sys._stdout = io.StringIO()\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f" * q{n+1})   Total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.normpath(os.path.join(output_dir, token))\n\n\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        from cs103.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n\nclass AutomaticPass(UTestCase):\n    def test_student_passed(self):\n        self.assertEqual(2,2)\n\n\nimport cs103\nclass Report3(Report):\n    title = "CS 101 Report 3"\n    questions = [(Week1, 20), (AutomaticPass, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs103]'
+report1_payload = '80049568000000000000007d94288c055765656b31947d942868018c08746573745f6164649486948c066173736572749486947d94284b014aa1ffffff4b004b04758c0474696d6594473fb71ac800000000758c0d4175746f6d6174696350617373947d946808473fb127100000000073752e'
 name="Report3"
 
 report = source_instantiate(name, report1_source, report1_payload)
diff --git a/examples/example_docker/students/cs103/unitgrade/AutomaticPass.pkl b/examples/example_docker/students/cs103/unitgrade/AutomaticPass.pkl
index 2a722e2b9c8264b76eca73fec2c7dd84eb0e02d3..9b6ff7ac689837f86e1b0e393993ec7acbb784e8 100644
GIT binary patch
literal 4
LcmZo*@zVnU0@?uq

literal 93
zcmZo*nHt0Z0ku;!dUzd6OY(CQOEQxK5{rwc^az)v7MH{qmz1WY=9R=30L4;MrnF7z
gVFR&>N`TDTDH)6zOh6%)lFZyxpnyBnIEGR^0Ou<p2><{9

diff --git a/examples/example_docker/students/cs103/unitgrade/Week1.pkl b/examples/example_docker/students/cs103/unitgrade/Week1.pkl
index fe27b785553c86fe6975853b9990eed439d2d5bc..20eb565b4b7903e4aef2d3d44e08726a2b0e14ed 100644
GIT binary patch
delta 22
ZcmWHy<85G>YRmuuwNobY=`$7U0RS=m1aSZW

delta 47
tcmcBu=WAe@>cap5wNo@E^6E=vFlI2dP3d7N$;?fi(l*5%D$7u+2LK2n3he*@

diff --git a/examples/example_flat/instructor/cs101flat/Report1Flat_handin_10_of_10.token b/examples/example_flat/instructor/cs101flat/Report1Flat_handin_10_of_10.token
new file mode 100644
index 0000000000000000000000000000000000000000..6207232bba6714f3ffac3686c93f17dac4be1cb1
GIT binary patch
literal 65761
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
P{Nmq*F?xy1Y4iUBSTFT6

literal 0
HcmV?d00001

diff --git a/examples/example_flat/instructor/cs101flat/__pycache__/deploy.cpython-38.pyc b/examples/example_flat/instructor/cs101flat/__pycache__/deploy.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9c91ca3192aaec26f60abe00c1109cb32983e52a
GIT binary patch
literal 581
zcmZWn%Wl*#6tySGBs0?iHVD1|DM+LYON1&UsxG^LRzg;UW$Zg0Q^$$?K%H53&xi0I
zd_}gb_yty6r=mi_FP(F*<#W%KFW2iO!SUn#g}9v&@-vZtM~UPuZvPPvMHDrpqm0so
zXJ*!AESqp<@~&V7B`{a{^~_yB22>T(oPWzPUVJH3sVcQlOSMu*SD9L;xO(t`)DM5*
z>!haR>OBm-3!5_|0@5cQLLB&&6AJiN8{lrrW2*924_s+CR-AW2Th7nwjLkc3^>)t|
z{pW4;QUqWn+<=S$Msj%CG{?Anhze}*$I@?JZnmg(F|Ift_EN|laDFJCH=(}<dsrwK
zOuui2eVwzV@1v8DL|LW4hY3BF2888_Yb%285#t3^l?G+b>yoYRs-Bb_cA2ne(duw#
zYjFB2miemLX@ymB=>X~E*1IfSE|b*(oXe3VyH<2q<#*y17?_UVpWeN0FFiQlhPZ?F
zw3o3<7Tf=XTDTG2V8H(cJT;)z)(015=v{l?mG<8KSiR|b6%CwFl=SJ(98sLJiawhE
E0rXq1T>t<8

literal 0
HcmV?d00001

diff --git a/examples/example_flat/instructor/cs101flat/__pycache__/homework1.cpython-38.pyc b/examples/example_flat/instructor/cs101flat/__pycache__/homework1.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4ad952b7db7aa4adbd8a113e6d74f318bd77ce47
GIT binary patch
literal 835
zcmYjPy>8nu5GLh6)pfR_S#OJl7($(FK@$W`f3^%QGBi;j(;{sPktl<toZ9f_zD3cc
zTVF|QC%;0c9%-xa0Y}~)cy}MaySt;KE<p+XkllKO{ISlVbkMm*)gSTTgwyZjo^X#h
z@TS7!%_mR26Aj)Hl(%_%<NY8%y$z)VV;w;-=JOZ4J8f?0#-oJ4{6d0WLa|sa)^4EQ
zpz0nTh8Vgg_@3fhy86`xluzkGNMMkq+Q3P^wD$=pVM--+9Zw3WF`mjP6caEr0h;9k
zL?&_}jfPZW#zH79pio?>5I%&{(AD3^V_UcXFdUo>&L0ENv!cxSz70H_V|e%oeO7l2
zcFBQPHEm+$@5}Ij-nVxke-mYY_m|yVM0Xl{N2Z*K=zWot4pdai)JzrQBA%;s!HkH+
zH<r&cp=%?aWXwdV)JBzwDO8l`;hUig&Wc<-7wTyk&X-m1@Dr9+jT0rLrCN9<&bB^^
zwXHhNeKgi&O^=D=d%Wk`JQpC#e2kD`#74j*htYV1w5A#+rA$m($eJOYBI0FD6f&PG
z&}Dw%xV-|#d7ll&0bBw*9fM;8Nu#WyW9RISCL*aC_}D_)fo~{lSAHDlER}J*I{sRe
z3LEJ%Gj_^naEf{fTl=5Y>(6e!b^{pboMoBYn5`Yb*3z)G3w;|j9Vh>5OI(vUu39(&
dX$}C{H04nFZ}WnenYePiT1<Y&Z~5LU`VUWM*y8{I

literal 0
HcmV?d00001

diff --git a/examples/example_flat/instructor/cs101flat/__pycache__/report1flat.cpython-38.pyc b/examples/example_flat/instructor/cs101flat/__pycache__/report1flat.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2b843499aeb6a5314ec477e4a8ff9439e6927c59
GIT binary patch
literal 1204
zcmZ`&OK%e~5VpOKIFCLQC<qCp9La&I=@B7>6ri^pC>4?w$y&v3y2P8LwzojVE&UlB
z=&^rkubgt_$feBewoN38rJ4OaW6yZLnLXOrXb@P<gBQtfM#wMRtgjF@Z$R7}lp=~6
zl2Jh^VrEzth@ixQ3A0E<SuEmmADWt|9S{|%_=2cd*FN(_AnI@{G@%H=Q&Su~TvM<&
zbW_zQ%o-i&#)2#`et1Z_jU{9yU0TE+^n7MLpvU?wF?r&(w53TppDR7}T~@TLKGW7|
zX;SBlAW>>C!u#tBYOLyc3P2M<6%kBP#V&{lRG>omhAM*GaS?sedeR%wwfl%8kUofe
z4(dDkNj!xBbiow6Wc1bop}-QMMG*`)SYqxa5}N+FzP?^!ob(b9JiVDXr>%c?nkUAh
z<BArc)8_b!*bUhJ8TDTdkKl+K`us!>-_AyP235OZK281DCQ8e>P0xUrq5hg=bEDlY
zkjEzR!*uGr%}0J_ha=b9>y^fe!V>S!zZKkT=Oyq~gOm<mN@$y&Z<ajl-a7vwB!+V(
zAsqmBgfJD1g9Qanf!}d(M?^SSB8wJtECWzoW^o2B=Ce&ySaGE`0Trz>^G$Q{fI}t;
zJ#Vi)?8ZIlMg^C0nq*qaq9J8AQ@KIhk`mdiJa!8L*fy$FvJzoNixr`i9B|6R((?ad
z>cH96Fo{5iiXF2t6_JiX*Hi!#5Ejj9ihJ*&A?I8D!w&SJQ`tJbC6X}ca{B<j_93br
zP(|cZZ*=(pQ9sS0L+Nbliu%bc(_dzG(i5$DGMdOV!#~8`ThAj1v<>30C{9D#pcZXN
zRhFbvDZ4GPb2m!+yDMmsYw>JlSo!3MHgg!seT!|hPf(Rj!~qr@uVCi{{|LID!1QAJ
hGI3SpJ=7QcRn@WAI3x}q-J&hJO*w1VIo*zU@E4}j6Al0X

literal 0
HcmV?d00001

diff --git a/examples/example_flat/instructor/cs101flat/deploy.py b/examples/example_flat/instructor/cs101flat/deploy.py
new file mode 100644
index 0000000..be04b5a
--- /dev/null
+++ b/examples/example_flat/instructor/cs101flat/deploy.py
@@ -0,0 +1,15 @@
+from report1flat import Report1Flat
+from unitgrade_private2.hidden_create_files import setup_grade_file_report
+from snipper import snip_dir
+
+if __name__ == "__main__":
+    setup_grade_file_report(Report1Flat, minify=False, obfuscate=False, execute=False)
+
+    # from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
+    # gather_upload_to_campusnet((Report1Flat()))
+
+    # Deploy the files using snipper: https://gitlab.compute.dtu.dk/tuhe/snipper
+    snip_dir.snip_dir(source_dir="", dest_dir="../../students/cs101flat", clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py'])
+
+
+
diff --git a/examples/example_flat/instructor/cs101flat/homework1.py b/examples/example_flat/instructor/cs101flat/homework1.py
new file mode 100644
index 0000000..286b79f
--- /dev/null
+++ b/examples/example_flat/instructor/cs101flat/homework1.py
@@ -0,0 +1,16 @@
+def reverse_list(mylist): #!f
+    """
+    Given a list 'mylist' returns a list consisting of the same elements in reverse order. E.g.
+    reverse_list([1,2,3]) should return [3,2,1] (as a list).
+    """
+    return list(reversed(mylist))
+
+def add(a,b): #!f
+    """ Given two numbers `a` and `b` this function should simply return their sum:
+    > add(a,b) = a+b """
+    return a+b
+
+if __name__ == "__main__":
+    # Problem 1: Write a function which add two numbers
+    print(f"Your result of 2 + 2 = {add(2,2)}")
+    print(f"Reversing a small list", reverse_list([2,3,5,7]))
diff --git a/examples/example_flat/instructor/cs101flat/report1flat.py b/examples/example_flat/instructor/cs101flat/report1flat.py
new file mode 100644
index 0000000..9ede035
--- /dev/null
+++ b/examples/example_flat/instructor/cs101flat/report1flat.py
@@ -0,0 +1,24 @@
+from src.unitgrade2.unitgrade2 import Report
+from src.unitgrade2 import evaluate_report_student
+from homework1 import reverse_list, add
+import unittest
+
+class Week1(unittest.TestCase):
+    def test_add(self):
+        self.assertEqual(add(2,2), 4)
+        self.assertEqual(add(-100, 5), -95)
+
+    def test_reverse(self):
+        self.assertEqual(reverse_list([1,2,3]), [3,2,1])
+
+
+import homework1
+class Report1Flat(Report):
+    title = "CS 101 Report 1"
+    questions = [(Week1, 10)]  # Include a single question for 10 credits.
+    pack_imports = [homework1]
+
+if __name__ == "__main__":
+    # Uncomment to simply run everything as a unittest:
+    # unittest.main(verbosity=2)
+    evaluate_report_student(Report1Flat())
diff --git a/examples/example_flat/instructor/cs101flat/report1flat_grade.py b/examples/example_flat/instructor/cs101flat/report1flat_grade.py
new file mode 100644
index 0000000..48b0980
--- /dev/null
+++ b/examples/example_flat/instructor/cs101flat/report1flat_grade.py
@@ -0,0 +1,349 @@
+
+import numpy as np
+from tabulate import tabulate
+from datetime import datetime
+import pyfiglet
+import unittest
+# from unitgrade2.unitgrade2 import MySuite
+
+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: 
+
+> python assignment1_dp.py
+
+To run only question 2 or question 2.1
+
+> python assignment1_dp.py -q 2
+> python assignment1_dp.py -q 2.1
+
+Note this scripts does not grade your report. To grade your report, use:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
+parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
+parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
+parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
+parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
+
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+    args = parser.parse_args()
+    if question is None and args.q is not None:
+        question = args.q
+        if "." in question:
+            question, qitem = [int(v) for v in question.split(".")]
+        else:
+            question = int(question)
+
+    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
+        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
+
+    if unmute is None:
+        unmute = args.unmute
+    if passall is None:
+        passall = args.passall
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+                                          show_tol_err=show_tol_err)
+
+
+    if question is None:
+        print("Provisional evaluation")
+        tabulate(table_data)
+        table = table_data
+        print(tabulate(table))
+        print(" ")
+
+    fr = inspect.getouterframes(inspect.currentframe())[1].filename
+    gfile = os.path.basename(fr)[:-3] + "_grade.py"
+    if os.path.exists(gfile):
+        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
+        print(">>>", gfile)
+        print("In the same manner as you ran this file.")
+
+
+    return results
+
+
+def upack(q):
+    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
+    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
+    h = np.asarray(h)
+    return h[:,0], h[:,1], h[:,2],
+
+class UnitgradeTextRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+class SequentialTestLoader(unittest.TestLoader):
+    def getTestCaseNames(self, testCaseClass):
+        test_names = super().getTestCaseNames(testCaseClass)
+        # testcase_methods = list(testCaseClass.__dict__.keys())
+        ls = []
+        for C in testCaseClass.mro():
+            if issubclass(C, unittest.TestCase):
+                ls = list(C.__dict__.keys()) + ls
+        testcase_methods = ls
+        test_names.sort(key=testcase_methods.index)
+        return test_names
+
+def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
+                    show_progress_bar=True,
+                    show_tol_err=False,
+                    big_header=True):
+
+    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)
+    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(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)
+        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
+        q_title_print = "Question %i: %s"%(n+1, qtitle)
+        print(q_title_print, end="")
+        q.possible = 0
+        q.obtained = 0
+        q_ = {} # Gather score in this class.
+        # unittest.Te
+        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
+        UTextResult.q_title_print = q_title_print # Hacky
+        UTextResult.show_progress_bar = show_progress_bar # Hacky.
+        UTextResult.number = n
+
+        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)
+
+        possible = res.testsRun
+        obtained = len(res.successes)
+
+        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}"
+        s2 = f" {q.obtained}/{w}"
+        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )
+        print(" ")
+        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])
+
+    ws, possible, obtained = upack(score)
+    possible = int( msum(possible) )
+    obtained = int( msum(obtained) ) # Cast to python int
+    report.possible = possible
+    report.obtained = obtained
+    now = datetime.now()
+    dt_string = now.strftime("%H:%M:%S")
+
+    dt = int(time.time()-t_start)
+    minutes = dt//60
+    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") +")")
+
+    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])
+    results = {'total': (obtained, possible), 'details': score}
+    return results, table_data
+
+
+
+
+from tabulate import tabulate
+from datetime import datetime
+import inspect
+import json
+import os
+import bz2
+import pickle
+import os
+
+def bzwrite(json_str, token): # to get around obfuscation issues
+    with getattr(bz2, 'open')(token, "wt") as f:
+        f.write(json_str)
+
+def gather_imports(imp):
+    resources = {}
+    m = imp
+    # for m in pack_imports:
+    # print(f"*** {m.__name__}")
+    f = m.__file__
+    # dn = os.path.dirname(f)
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
+        top_package = os.path.dirname(m.__file__)
+        module_import = True
+    else:
+        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
+        module_import = False
+
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = os.path.dirname(top_package)
+    import zipfile
+    # import strea
+    # zipfile.ZipFile
+    import io
+    # file_like_object = io.BytesIO(my_zip_data)
+    zip_buffer = io.BytesIO()
+    with zipfile.ZipFile(zip_buffer, 'w') as zip:
+        # zip.write()
+        for root, dirs, files in os.walk(top_package):
+            for file in files:
+                if file.endswith(".py"):
+                    fpath = os.path.join(root, file)
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
+                    zip.write(fpath, v)
+
+    resources['zipfile'] = zip_buffer.getvalue()
+    resources['top_package'] = top_package
+    resources['module_import'] = module_import
+    return resources, top_package
+
+    if f.endswith("__init__.py"):
+        for root, dirs, files in os.walk(os.path.dirname(f)):
+            for file in files:
+                if file.endswith(".py"):
+                    # print(file)
+                    # print()
+                    v = os.path.relpath(os.path.join(root, file), top_package)
+                    with open(os.path.join(root, file), 'r') as ff:
+                        resources[v] = ff.read()
+    else:
+        v = os.path.relpath(f, top_package)
+        with open(f, 'r') as ff:
+            resources[v] = ff.read()
+    return resources
+
+import argparse
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
+parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
+
+def gather_upload_to_campusnet(report, output_dir=None):
+    n = report.nL
+    args = parser.parse_args()
+    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
+                                          show_progress_bar=not args.noprogress,
+                                          big_header=not args.autolab)
+    print(" ")
+    print("="*n)
+    print("Final evaluation")
+    print(tabulate(table_data))
+    # also load the source code of missing files...
+
+    sources = {}
+
+    if not args.autolab:
+        if len(report.individual_imports) > 0:
+            print("By uploading the .token file, you verify the files:")
+            for m in report.individual_imports:
+                print(">", m.__file__)
+            print("Are created/modified individually by you in agreement with DTUs exam rules")
+            report.pack_imports += report.individual_imports
+
+        if len(report.pack_imports) > 0:
+            print("Including files in upload...")
+            for k, m in enumerate(report.pack_imports):
+                nimp, top_package = gather_imports(m)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
+                nimp['name'] = m.__name__
+                sources[k] = nimp
+                # if len([k for k in nimp if k not in sources]) > 0:
+                print(f"*** {m.__name__}")
+                # sources = {**sources, **nimp}
+    results['sources'] = sources
+
+    if output_dir is None:
+        output_dir = os.getcwd()
+
+    payload_out_base = report.__class__.__name__ + "_handin"
+
+    obtain, possible = results['total']
+    vstring = "_v"+report.version if report.version is not None else ""
+
+    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
+    token = os.path.join(output_dir, token)
+    with open(token, 'wb') as f:
+        pickle.dump(results, f)
+
+    if not args.autolab:
+        print(" ")
+        print("To get credit for your results, please upload the single file: ")
+        print(">", token)
+        print("To campusnet without any modifications.")
+
+        # print("Now time for some autolab fun")
+
+def source_instantiate(name, report1_source, payload):
+    eval("exec")(report1_source, globals())
+    pl = pickle.loads(bytes.fromhex(payload))
+    report = eval(name)(payload=pl, strict=True)
+    # report.set_payload(pl)
+    return report
+
+
+
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport os\nfrom io import StringIO\nfrom unittest.runner import _WritelnDecorator\nimport inspect\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n# class MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n#     raise Exception("no suite")\n#     pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="")\n            else:\n                print( dot_parts, end="")\n\n            if tsecs >= 0.1:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        # item_title = item_title.split("\\n")[0]\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n# def wrapper(foo):\n#     def magic(self):\n#         # s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n#         foo(self)\n#     magic.__doc__ = foo.__doc__\n#     return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    def capture(self):\n        return Capturing2(stdout=self._stdout)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        self._stdout = sys.stdout\n        import io\n        sys.stdout = io.StringIO()\n        super().setUp()\n        # print("Setting up...")\n\n    def _callTearDown(self):\n        sys.stdout = self._stdout\n        super().tearDown()\n        # print("asdfsfd")\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n# from unitgrade2.unitgrade2 import MySuite\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nfrom homework1 import reverse_list, add\nimport unittest\n\nclass Week1(unittest.TestCase):\n    def test_add(self):\n        self.assertEqual(add(2,2), 4)\n        self.assertEqual(add(-100, 5), -95)\n\n    def test_reverse(self):\n        self.assertEqual(reverse_list([1,2,3]), [3,2,1])\n\n\nimport homework1\nclass Report1Flat(Report):\n    title = "CS 101 Report 1"\n    questions = [(Week1, 10)]  # Include a single question for 10 credits.\n    pack_imports = [homework1]'
+report1_payload = '8004953f000000000000007d948c055765656b31947d948c2c6e6f20636163686520736565205f73657475705f616e737765727320696e20756e69746772616465322e7079948873732e'
+name="Report1Flat"
+
+report = source_instantiate(name, report1_source, report1_payload)
+output_dir = os.path.dirname(__file__)
+gather_upload_to_campusnet(report, output_dir)
\ No newline at end of file
diff --git a/examples/example_flat/students/cs101flat/Report1Flat_handin_0_of_10.token b/examples/example_flat/students/cs101flat/Report1Flat_handin_0_of_10.token
new file mode 100644
index 0000000000000000000000000000000000000000..c9122d00c8fff99b66be2f551819687826d1b9c0
GIT binary patch
literal 65468
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
K@ETXk=KmLBw3|}^

literal 0
HcmV?d00001

diff --git a/examples/example_flat/students/cs101flat/__pycache__/deploy.cpython-38.pyc b/examples/example_flat/students/cs101flat/__pycache__/deploy.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9c91ca3192aaec26f60abe00c1109cb32983e52a
GIT binary patch
literal 581
zcmZWn%Wl*#6tySGBs0?iHVD1|DM+LYON1&UsxG^LRzg;UW$Zg0Q^$$?K%H53&xi0I
zd_}gb_yty6r=mi_FP(F*<#W%KFW2iO!SUn#g}9v&@-vZtM~UPuZvPPvMHDrpqm0so
zXJ*!AESqp<@~&V7B`{a{^~_yB22>T(oPWzPUVJH3sVcQlOSMu*SD9L;xO(t`)DM5*
z>!haR>OBm-3!5_|0@5cQLLB&&6AJiN8{lrrW2*924_s+CR-AW2Th7nwjLkc3^>)t|
z{pW4;QUqWn+<=S$Msj%CG{?Anhze}*$I@?JZnmg(F|Ift_EN|laDFJCH=(}<dsrwK
zOuui2eVwzV@1v8DL|LW4hY3BF2888_Yb%285#t3^l?G+b>yoYRs-Bb_cA2ne(duw#
zYjFB2miemLX@ymB=>X~E*1IfSE|b*(oXe3VyH<2q<#*y17?_UVpWeN0FFiQlhPZ?F
zw3o3<7Tf=XTDTG2V8H(cJT;)z)(015=v{l?mG<8KSiR|b6%CwFl=SJ(98sLJiawhE
E0rXq1T>t<8

literal 0
HcmV?d00001

diff --git a/examples/example_flat/students/cs101flat/__pycache__/homework1.cpython-38.pyc b/examples/example_flat/students/cs101flat/__pycache__/homework1.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f019923d47a404593f992813d90c89b3e2da2546
GIT binary patch
literal 994
zcmaJ=J#X7E5Y>l26gL41v}o4b5+SKkCqRav2@0fX(GDKkW@w^7rbOB%B9Q?}CAG)8
z|Dx#9Eq_UCCy!k-^+?-6rXE1@_$2Y(JwBanY;-(~zfZg5AoRRHcJnyexOsy^f5eG;
z=N|QG@WVUzX-FHm1}vn_t3bVD4ccM>ZPWHF`04!$X1?zs7BL^OHQJ$1Mva+23w)2R
zfA->y>8Nx1jg;2~18pkGgn?XA)`c%)u3^X#$CXq@mc;O!6vYHaOfW?ZqcBvm1T$vt
zMGaiI4Hw#|DmPNSq+BtZOgg!b%vWLa0LKXqy^fQ?hGzbEYzj$*)88Gyc+YQ`00ITq
z2DZwHUAI6nQz?O*7I-d&Mx2Wg$e}B*Ny&f}ti)y<C&g}<(hQ`cOm*S3JL<agmw0N=
z-M;AU?(Obh#-PWtD(JEdT<jy<yM%4Bsu(XmzTf;{RkKB4Sc%+lDIk+{(!cZTXMJfN
z9y5BXlvJ^Q-dgl<=cxwve4m~iCTAL{C8ip)<gLsr$2qA4HzP$TORp8bL8TM6xFfwv
z(qTbNvb-^!<hu8&=b*7H*{xJpz3%m-UVq%7Evc>OUQ4xb&RuTz7&iakg=EXiFt-v!
zRc1&U24nz4P#9zb)ZMyeCBsre%~7GrN=dW{SD>r%(20Kxgwk!Yo5gShWG4e<P0?4D
zMI6*Vsr}5!w3wO**CBpl-Lhz-q1G%IrD;jHNYm-&S6L}6r>nwPGwi_*jw6`cGp8>;
zIU87`5YQz$*%@da;={Q;er|uVe%!3vX-Z|DrcS1ZA_8rdrgamqM3_g+tggz@i(Z$K
VRs}n@ooM?*H^L~2T2b)a{|E8E60iUO

literal 0
HcmV?d00001

diff --git a/examples/example_flat/students/cs101flat/__pycache__/report1flat.cpython-38.pyc b/examples/example_flat/students/cs101flat/__pycache__/report1flat.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2b843499aeb6a5314ec477e4a8ff9439e6927c59
GIT binary patch
literal 1204
zcmZ`&OK%e~5VpOKIFCLQC<qCp9La&I=@B7>6ri^pC>4?w$y&v3y2P8LwzojVE&UlB
z=&^rkubgt_$feBewoN38rJ4OaW6yZLnLXOrXb@P<gBQtfM#wMRtgjF@Z$R7}lp=~6
zl2Jh^VrEzth@ixQ3A0E<SuEmmADWt|9S{|%_=2cd*FN(_AnI@{G@%H=Q&Su~TvM<&
zbW_zQ%o-i&#)2#`et1Z_jU{9yU0TE+^n7MLpvU?wF?r&(w53TppDR7}T~@TLKGW7|
zX;SBlAW>>C!u#tBYOLyc3P2M<6%kBP#V&{lRG>omhAM*GaS?sedeR%wwfl%8kUofe
z4(dDkNj!xBbiow6Wc1bop}-QMMG*`)SYqxa5}N+FzP?^!ob(b9JiVDXr>%c?nkUAh
z<BArc)8_b!*bUhJ8TDTdkKl+K`us!>-_AyP235OZK281DCQ8e>P0xUrq5hg=bEDlY
zkjEzR!*uGr%}0J_ha=b9>y^fe!V>S!zZKkT=Oyq~gOm<mN@$y&Z<ajl-a7vwB!+V(
zAsqmBgfJD1g9Qanf!}d(M?^SSB8wJtECWzoW^o2B=Ce&ySaGE`0Trz>^G$Q{fI}t;
zJ#Vi)?8ZIlMg^C0nq*qaq9J8AQ@KIhk`mdiJa!8L*fy$FvJzoNixr`i9B|6R((?ad
z>cH96Fo{5iiXF2t6_JiX*Hi!#5Ejj9ihJ*&A?I8D!w&SJQ`tJbC6X}ca{B<j_93br
zP(|cZZ*=(pQ9sS0L+Nbliu%bc(_dzG(i5$DGMdOV!#~8`ThAj1v<>30C{9D#pcZXN
zRhFbvDZ4GPb2m!+yDMmsYw>JlSo!3MHgg!seT!|hPf(Rj!~qr@uVCi{{|LID!1QAJ
hGI3SpJ=7QcRn@WAI3x}q-J&hJO*w1VIo*zU@E4}j6Al0X

literal 0
HcmV?d00001

diff --git a/examples/example_flat/students/cs101flat/__pycache__/report1flat_grade.cpython-38.pyc b/examples/example_flat/students/cs101flat/__pycache__/report1flat_grade.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..01435181f7f83079961ed2105a4d343c2511a9d0
GIT binary patch
literal 57893
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
GCI3IRfNa<R

literal 0
HcmV?d00001

diff --git a/examples/example_flat/students/cs101flat/homework1.py b/examples/example_flat/students/cs101flat/homework1.py
new file mode 100644
index 0000000..3543f1b
--- /dev/null
+++ b/examples/example_flat/students/cs101flat/homework1.py
@@ -0,0 +1,21 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+def reverse_list(mylist): 
+    """
+    Given a list 'mylist' returns a list consisting of the same elements in reverse order. E.g.
+    reverse_list([1,2,3]) should return [3,2,1] (as a list).
+    """
+    # TODO: 1 lines missing.
+    raise NotImplementedError("Implement function body")
+
+def add(a,b): 
+    """ Given two numbers `a` and `b` this function should simply return their sum:
+    > add(a,b) = a+b """
+    # TODO: 1 lines missing.
+    raise NotImplementedError("Implement function body")
+
+if __name__ == "__main__":
+    # Problem 1: Write a function which add two numbers
+    print(f"Your result of 2 + 2 = {add(2,2)}")
+    print(f"Reversing a small list", reverse_list([2,3,5,7]))
diff --git a/examples/example_flat/students/cs101flat/report1flat.py b/examples/example_flat/students/cs101flat/report1flat.py
new file mode 100644
index 0000000..4a268f7
--- /dev/null
+++ b/examples/example_flat/students/cs101flat/report1flat.py
@@ -0,0 +1,27 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+from src.unitgrade2.unitgrade2 import Report
+from src.unitgrade2 import evaluate_report_student
+from homework1 import reverse_list, add
+import unittest
+
+class Week1(unittest.TestCase):
+    def test_add(self):
+        self.assertEqual(add(2,2), 4)
+        self.assertEqual(add(-100, 5), -95)
+
+    def test_reverse(self):
+        self.assertEqual(reverse_list([1,2,3]), [3,2,1])
+
+
+import homework1
+class Report1Flat(Report):
+    title = "CS 101 Report 1"
+    questions = [(Week1, 10)]  # Include a single question for 10 credits.
+    pack_imports = [homework1]
+
+if __name__ == "__main__":
+    # Uncomment to simply run everything as a unittest:
+    # unittest.main(verbosity=2)
+    evaluate_report_student(Report1Flat())
diff --git a/examples/example_flat/students/cs101flat/report1flat_grade.py b/examples/example_flat/students/cs101flat/report1flat_grade.py
new file mode 100644
index 0000000..65db51b
--- /dev/null
+++ b/examples/example_flat/students/cs101flat/report1flat_grade.py
@@ -0,0 +1,351 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+import numpy as np
+from tabulate import tabulate
+from datetime import datetime
+import pyfiglet
+import unittest
+# from unitgrade2.unitgrade2 import MySuite
+
+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: 
+
+> python assignment1_dp.py
+
+To run only question 2 or question 2.1
+
+> python assignment1_dp.py -q 2
+> python assignment1_dp.py -q 2.1
+
+Note this scripts does not grade your report. To grade your report, use:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
+parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
+parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
+parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
+parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
+
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+    args = parser.parse_args()
+    if question is None and args.q is not None:
+        question = args.q
+        if "." in question:
+            question, qitem = [int(v) for v in question.split(".")]
+        else:
+            question = int(question)
+
+    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
+        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
+
+    if unmute is None:
+        unmute = args.unmute
+    if passall is None:
+        passall = args.passall
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+                                          show_tol_err=show_tol_err)
+
+
+    if question is None:
+        print("Provisional evaluation")
+        tabulate(table_data)
+        table = table_data
+        print(tabulate(table))
+        print(" ")
+
+    fr = inspect.getouterframes(inspect.currentframe())[1].filename
+    gfile = os.path.basename(fr)[:-3] + "_grade.py"
+    if os.path.exists(gfile):
+        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
+        print(">>>", gfile)
+        print("In the same manner as you ran this file.")
+
+
+    return results
+
+
+def upack(q):
+    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
+    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
+    h = np.asarray(h)
+    return h[:,0], h[:,1], h[:,2],
+
+class UnitgradeTextRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+class SequentialTestLoader(unittest.TestLoader):
+    def getTestCaseNames(self, testCaseClass):
+        test_names = super().getTestCaseNames(testCaseClass)
+        # testcase_methods = list(testCaseClass.__dict__.keys())
+        ls = []
+        for C in testCaseClass.mro():
+            if issubclass(C, unittest.TestCase):
+                ls = list(C.__dict__.keys()) + ls
+        testcase_methods = ls
+        test_names.sort(key=testcase_methods.index)
+        return test_names
+
+def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
+                    show_progress_bar=True,
+                    show_tol_err=False,
+                    big_header=True):
+
+    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)
+    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(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)
+        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
+        q_title_print = "Question %i: %s"%(n+1, qtitle)
+        print(q_title_print, end="")
+        q.possible = 0
+        q.obtained = 0
+        q_ = {} # Gather score in this class.
+        # unittest.Te
+        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
+        UTextResult.q_title_print = q_title_print # Hacky
+        UTextResult.show_progress_bar = show_progress_bar # Hacky.
+        UTextResult.number = n
+
+        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)
+
+        possible = res.testsRun
+        obtained = len(res.successes)
+
+        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}"
+        s2 = f" {q.obtained}/{w}"
+        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )
+        print(" ")
+        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])
+
+    ws, possible, obtained = upack(score)
+    possible = int( msum(possible) )
+    obtained = int( msum(obtained) ) # Cast to python int
+    report.possible = possible
+    report.obtained = obtained
+    now = datetime.now()
+    dt_string = now.strftime("%H:%M:%S")
+
+    dt = int(time.time()-t_start)
+    minutes = dt//60
+    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") +")")
+
+    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])
+    results = {'total': (obtained, possible), 'details': score}
+    return results, table_data
+
+
+
+
+from tabulate import tabulate
+from datetime import datetime
+import inspect
+import json
+import os
+import bz2
+import pickle
+import os
+
+def bzwrite(json_str, token): # to get around obfuscation issues
+    with getattr(bz2, 'open')(token, "wt") as f:
+        f.write(json_str)
+
+def gather_imports(imp):
+    resources = {}
+    m = imp
+    # for m in pack_imports:
+    # print(f"*** {m.__name__}")
+    f = m.__file__
+    # dn = os.path.dirname(f)
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
+        top_package = os.path.dirname(m.__file__)
+        module_import = True
+    else:
+        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
+        module_import = False
+
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = os.path.dirname(top_package)
+    import zipfile
+    # import strea
+    # zipfile.ZipFile
+    import io
+    # file_like_object = io.BytesIO(my_zip_data)
+    zip_buffer = io.BytesIO()
+    with zipfile.ZipFile(zip_buffer, 'w') as zip:
+        # zip.write()
+        for root, dirs, files in os.walk(top_package):
+            for file in files:
+                if file.endswith(".py"):
+                    fpath = os.path.join(root, file)
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
+                    zip.write(fpath, v)
+
+    resources['zipfile'] = zip_buffer.getvalue()
+    resources['top_package'] = top_package
+    resources['module_import'] = module_import
+    return resources, top_package
+
+    if f.endswith("__init__.py"):
+        for root, dirs, files in os.walk(os.path.dirname(f)):
+            for file in files:
+                if file.endswith(".py"):
+                    # print(file)
+                    # print()
+                    v = os.path.relpath(os.path.join(root, file), top_package)
+                    with open(os.path.join(root, file), 'r') as ff:
+                        resources[v] = ff.read()
+    else:
+        v = os.path.relpath(f, top_package)
+        with open(f, 'r') as ff:
+            resources[v] = ff.read()
+    return resources
+
+import argparse
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
+parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
+
+def gather_upload_to_campusnet(report, output_dir=None):
+    n = report.nL
+    args = parser.parse_args()
+    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
+                                          show_progress_bar=not args.noprogress,
+                                          big_header=not args.autolab)
+    print(" ")
+    print("="*n)
+    print("Final evaluation")
+    print(tabulate(table_data))
+    # also load the source code of missing files...
+
+    sources = {}
+
+    if not args.autolab:
+        if len(report.individual_imports) > 0:
+            print("By uploading the .token file, you verify the files:")
+            for m in report.individual_imports:
+                print(">", m.__file__)
+            print("Are created/modified individually by you in agreement with DTUs exam rules")
+            report.pack_imports += report.individual_imports
+
+        if len(report.pack_imports) > 0:
+            print("Including files in upload...")
+            for k, m in enumerate(report.pack_imports):
+                nimp, top_package = gather_imports(m)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
+                nimp['name'] = m.__name__
+                sources[k] = nimp
+                # if len([k for k in nimp if k not in sources]) > 0:
+                print(f"*** {m.__name__}")
+                # sources = {**sources, **nimp}
+    results['sources'] = sources
+
+    if output_dir is None:
+        output_dir = os.getcwd()
+
+    payload_out_base = report.__class__.__name__ + "_handin"
+
+    obtain, possible = results['total']
+    vstring = "_v"+report.version if report.version is not None else ""
+
+    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
+    token = os.path.join(output_dir, token)
+    with open(token, 'wb') as f:
+        pickle.dump(results, f)
+
+    if not args.autolab:
+        print(" ")
+        print("To get credit for your results, please upload the single file: ")
+        print(">", token)
+        print("To campusnet without any modifications.")
+
+        # print("Now time for some autolab fun")
+
+def source_instantiate(name, report1_source, payload):
+    eval("exec")(report1_source, globals())
+    pl = pickle.loads(bytes.fromhex(payload))
+    report = eval(name)(payload=pl, strict=True)
+    # report.set_payload(pl)
+    return report
+
+
+
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport os\nfrom io import StringIO\nfrom unittest.runner import _WritelnDecorator\nimport inspect\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n# class MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n#     raise Exception("no suite")\n#     pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="")\n            else:\n                print( dot_parts, end="")\n\n            if tsecs >= 0.1:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        # item_title = item_title.split("\\n")[0]\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n# def wrapper(foo):\n#     def magic(self):\n#         # s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n#         foo(self)\n#     magic.__doc__ = foo.__doc__\n#     return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    def capture(self):\n        return Capturing2(stdout=self._stdout)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        self._stdout = sys.stdout\n        import io\n        sys.stdout = io.StringIO()\n        super().setUp()\n        # print("Setting up...")\n\n    def _callTearDown(self):\n        sys.stdout = self._stdout\n        super().tearDown()\n        # print("asdfsfd")\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n# from unitgrade2.unitgrade2 import MySuite\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nfrom homework1 import reverse_list, add\nimport unittest\n\nclass Week1(unittest.TestCase):\n    def test_add(self):\n        self.assertEqual(add(2,2), 4)\n        self.assertEqual(add(-100, 5), -95)\n\n    def test_reverse(self):\n        self.assertEqual(reverse_list([1,2,3]), [3,2,1])\n\n\nimport homework1\nclass Report1Flat(Report):\n    title = "CS 101 Report 1"\n    questions = [(Week1, 10)]  # Include a single question for 10 credits.\n    pack_imports = [homework1]'
+report1_payload = '8004953f000000000000007d948c055765656b31947d948c2c6e6f20636163686520736565205f73657475705f616e737765727320696e20756e69746772616465322e7079948873732e'
+name="Report1Flat"
+
+report = source_instantiate(name, report1_source, report1_payload)
+output_dir = os.path.dirname(__file__)
+gather_upload_to_campusnet(report, output_dir)
diff --git a/examples/example_framework/instructor/cs102/.coverage b/examples/example_framework/instructor/cs102/.coverage
new file mode 100644
index 0000000000000000000000000000000000000000..a93b4d7e94a84f8ad080beeafaa98b3784e23e91
GIT binary patch
literal 53248
zcmeI)&2Q6Y90zbaHc68<HB;3^T~+nDOrfG}k|LzhNsO-afCich>_sD6aFQpjA+dw)
z^hMe<0+TrIfHY0oWtWM6gK7T($6a>VWfv~MjUD!TY(I5E8^|Ux)aq-sv131vpXd2J
zFOKuLy|RAM@;PfbZp-x9Ddo7Ls>(UW6h+C<Z<c=LlA;Y=zM-|+vpr}tqb#oemNh<A
z#*#lM##h<TjfJsavW3y#$F|b<M<1kaq?>dA3j`nl0SG`K5a_OtrE*hK>YZ<Vv)bgo
zYu30MzGhc1udQ5NV^>!`ytu}~ee6Vr(Xz0>R+#H-vo?2G!)kJ7*>$UC`j)-H{7o)H
zcRXGfS3KHB*E|t$F^Dg=Dps9h`Fw*;(RQtt>F%<de0M$w5T)kx9Y5SbC*jtHEkdvp
zQS>?H@&<RgUE^MuixXCTE;D!c+e|7qF`?e$L77aqMn9u{rJ)^hQ7$y-L^a2)i`-XT
z)2?lDZ=RWZC9FA=&mBK3t?RT3zQdZ99Td~{EZ=f$#&>wF<MaA~1)LXXav{9l($KlC
zivnE_V@7H9=){o^h#3WsA~z^=wj){Nh$3l<9OT*Vw5mjYqtj}O%Apux!oD*o=AgK~
z6BTyox;daO<MQ@Zrz96O8pi6_)~ycTtNeKu$D9v}VLS6o6oOj7yQ9h6nF&>)R>^m~
zTTS}lRWUoh6TGib<yT7dGWOkDBdOf%ta|TO&`<<VrE2-!-bT8w(d_LW&~(J{!R<!$
zlKw^_dQr2<oJP=PL~IsT4z=dqK2wkwrYkxcbE1Hh(>L1ML}n=utlD&{{cSC1F&?K5
zLSump*67$Z(N#QAhMKd*U2}skMn}V8;Y~LrYC5HKGPgE6sOjuAfl6s_Gt-?)rgGEM
z>Ya4ZjH23#R;j)wBx~}3VN@P!antL#av*uxASq+SqonL3(Ge=nLMoYCnI2S}C|so!
zZH#nNdMY<LsdmF2A;u-~d#tYzVo%%!UbqkppZ&J!Z?gS)7rQCr`D4l4`;&t*F0xQ5
ziPz-a%ZVV%_fmm=iw1r1tMz4B?1{7d5#L?dGMhA-v`x#UE=yx@cm-f0VBMs^X4UEV
zLHiYNgXSr&J#l`+6U6VOJ%ySJf>ZaVguG?>hUGU+PYga@o>d*E$xS=FBv8N$9wlXY
zEJ%9)#pr|h9Nw-t$HrDZ$cntCh|&Ej^)=b8Xrt9K?Rs>X5?9~wtTg0{J}J@(#}10f
z^3)eS>X|Q`Q=T+BDh4Wf{>3&?h_klLdf3ZFUG$uBdz0@wU3d{XZ~EM~TAYa>L1u#X
zv~7B<=5jhnm(aPq_OjX+l~gH-S8<m-B0k7;XVp~h<Vm&LiTYqTyi`28mbXlq?dWZy
zuWh_=Fm5Iv(>O~Xa(bJGu<PLvZ^IPCm=@MxHB^wHqK`P4IdOxp8qXE_!2$sYKmY;|
zfB*y_009U<00Izzz|j-X)P$N6_y0Q0&l}$xw~ab&V1WPxAOHafKmY;|fB*y_009U<
zU`T;6U7IoFa}~vRG;Q*fc&=cnxKvswo>?d^u~KQdSX?fh&L*_!iD*{-^x|np)n~d_
z<kJ+_@~g{*Pds`IqTqKndEvZM>$JG-dj)!|!{2b}DTfL@q_{<oClvUO*=jerCpRh$
zm!3G;cHEl<%l3S?Q}Z3SQ1eQ~r9z#zo6ashEs_6HJmjw%j}+sP@yz(k_+!WdA{Yc9
z009U<00Izz00bZa0SG_<0&i4cOq)^VR}cD#HmQnl9<)(yT8+MDNQ`PTY55g{nE%(t
zpD4yd;|p40fdB*`009U<00Izz00bZa0SFusfrh3l-SySwaxk%878C2`y@~bmzKQj+
zoLH9|@x*#Lo>(sj6YJ$oC!BIG(cF4HLFrt2J?Xf-?YRCDrE*rKRMc0d5|?YKXOrTK
z`G0Nvsbc&({?xd3M5-9YfB*y_009U<00Izz00bZa0SG9{hTdI&^&PW(uwLHwdvasg
z`+tq=-Ak`2o%sGgaaQlD>HmKJkN^LNE&%}uKmY;|fB*y_009U<00Iy=(gK>QDOoZ9
zuNr?V^n(Qg5P$##AOHafKmY;|fB*y_0D&VYplR83@b~}5eZ_cS{6s4(5P$##AOHaf
zKmY;|fB*y_009X6KLSZjSJUI#xlDrAZzm|xhhKlD9!saY#ebWDhZA9p+eWayttjvP
z{NvQ0Pjq>rbHU&L8;=#^IsO0t$8tB;5P$##AOHafKmY;|fB*y_009UbT7e{ep`dD7
zuu3F!J)I8b|CQs1wnWG{1Rwwb2tWV=5P$##AOHafKmY<m2#EQA-2V>&g&+`s00bZa
y0SG_<0uX=z1Rwx`Lo6Wv{vY@MhqwZfbqGKJ0uX=z1Rwwb2tWV=5P-lC0{;Ne06KmE

literal 0
HcmV?d00001

diff --git a/examples/example_framework/instructor/cs102/Report2_handin_10_of_18.token b/examples/example_framework/instructor/cs102/Report2_handin_10_of_18.token
deleted file mode 100644
index 3dc602acc93517ba2a3211a3f926b2dfe0cf8c90..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/examples/example_framework/instructor/cs102/Report2_handin_13_of_18.token b/examples/example_framework/instructor/cs102/Report2_handin_13_of_18.token
new file mode 100644
index 0000000000000000000000000000000000000000..303223eab586229ad1fd65b48a7b96322ded0274
GIT binary patch
literal 60507
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

literal 0
HcmV?d00001

diff --git a/examples/example_framework/instructor/cs102/Report2_handin_18_of_18.token b/examples/example_framework/instructor/cs102/Report2_handin_18_of_18.token
index 01a473c0bc4e8c0b536bb6c2b01d901ca33c5689..fe0c87cc2b34d3770b07ece28291836a66a6d7ed 100644
GIT binary patch
delta 9214
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
ZYxeB4exl;rBk#<h6Y@RwNJ2}v{~s1;2W|iW

literal 80175
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
HoOS+hrn664

diff --git a/examples/example_framework/instructor/cs102/Report2_handin_28_of_28.token b/examples/example_framework/instructor/cs102/Report2_handin_28_of_28.token
deleted file mode 100644
index 4fe9c89fea3b77998c9201c910a729cc1eb16d89..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/examples/example_framework/instructor/cs102/Report2_handin_5_of_18.token b/examples/example_framework/instructor/cs102/Report2_handin_5_of_18.token
deleted file mode 100644
index e22d430bac7ac0c21c0931fd87cd6871fa95b8c9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 78385
zcmeIb&2MB$k{?(-+pV4{sieVRFcA7MdL4-rgPG*xM}Agzv%0dgvbqxW)t#9=H6t<+
z6^wX6Mll!>j2BEMD<=W%Wq}3iSc3kBIS;f4VE|!oI!kxm^bhDR?EZfC;qLFn3zDfG
z4Q5vp-C2xy&p*t~%+1Zs&CLJx5C6^IyrZ8t-?zW}(R?!Rj=ul&N1y)D|MC5IKkgUv
z?r>Cok5`|*!}mWp`~K5+zx(~^q%4Q~qe6a6_EBhD^ik`(9}VZlG0UT+;T#3N`_t!#
zMK&1D%6WEjT9otQWSk8qv+S%Wj<T)%`_oT<fQAqM(Wk$E_+$M0{ZHRH{DU{&AO7R-
z{^_%#HyQV{>1=|Yj=w)W{qD!*<aE|6*uH}E<8O!4!4Td2@~<|3@XoJ4{oj80$1;}x
zy7!Z3|NTGxmp}ZI-+SjB{`+Tm+AFs<w>SF5bTm27r{{y&<T#UO`K*{uX7lZAc+9`q
zQ~mkgyHezIJe(iQy8WUvoef`h=f!q@IPCX}ai=#c@Uz4IORrlN^V4ZZ%kxD?+rG4|
zgYNvWm~~D8T(|FyRUUTclTNRDJUuPP#oXE}$HVEgnC1N2=?`aK(SN`9?r@NGI^*tf
z(dlG6J6WsKIR>pdoz{c*-hJ=g44>tlv<(sM)m1IJWN=<?Eju2LhlBH-kGrF?Sj#5+
zgVVAH6#0YVRna^3pWdc{-d56b6g#av-w?{Q*0MfWCOpLRa()Wj&&yDtH!8a04vP)P
zU2>O{em*+|1jVb~2*r1HS2~^Pd9T|$1Rhq_vXvY8d~#Hb`86=a$_s!LS?DKU{p8ty
z{%`;8KYRi9;lDo$EOa<IF3u*iqb+bzzZhh*;$<-_i_U0R&fCZ5{ImKXyY|z8Vy)F`
z>6c#(Ul!x6o3TK)q6Jq_dwx0_m;M|qU*i36e2`5B8JHp~LA|WN4B)V{;n@4jCbK?h
zpFPeGa_yi3$nMtK_S&r%t66zCIUV(_pKSLQ9&f$K+FkE*)oKSg6(Rw%ZB6!lTtLx#
z?{d)He!tya+pi5Y(=pD^CfWG(cpqrVzV3dVbuo><-v1iI8J5}LblejuV1SjFcB6BL
z4<iO2m#4>IP_pL-p{Hyo>)zbY>R{p-VY-OX+0M1>*D6P{tq0jxGl(f*Jb-d`IP4v=
zrz`<o0l=&u&)b96UqJK#$ntbFCuO#?oA|ery(S{I*S1&Rw2Y&@!c$=j60)0>$KBCL
zFbbBgk_kjwyR&xh1t(d;eJ}p>*<bzJ|M>V{{P>-B`0oz`_nEMA2^PfDb{@aF9MB0|
z7d}bJ&S5cv04am)D_(X-r<7{iO~<C&1x<vizkQB5_^8X7FEec|gPbft8I`ItFu~-Q
zr0R{jWtn{i`M=c;l~#@3Aa8c@iV-=0d^o3kAPvf5H1I}9a5nVOq*u;CzXMrug!_(*
z`QfA=+hEaTDF}1hQHZ9M4_J_W<N&^y%^#nfc1MrePJN^O@<Qudo11Id9a34_3&0yY
zEDYcxs8SY+;Bm;xb!2W4GkkO{dkDtvX0jk>^NC0m;>{+0Gtg-lZ5Jj2y;JZvww!M_
zQ?a^yM~r_c+!2v*d=6%#1nrIl2W#1=ObK~S_+dq>tzbduO=jIWG>Bqco?=4EaKcQ6
zfEiEb+3a+jLD8W6yx~j6jjT7p`Z+IV5oOo1C*yKnV9jOG-lSh-Xd$VMcUUzb$Golx
zGZr>kfZ|iKM4$bg4d;h!DeYi_-!o`2#kw^?SxhlfX6x(OFfVe{Naf<$5VC?G%!-5V
ztPky?q{KO#oC%ONob0fRwI2%y2zuCkS?Q7zRn`kYmC`XG_}g=rEemOTZBS|%KX)+k
zdPnCAY%Oz0SrPh3x9ktfZhv4)Bw2A(Laer1`=@hIYA`y7#Js(hZ6z~o1bMZilQCtU
z464_tAWYdRnEpADD!A;9&bsFy(`?c|?G=K=+3?^HTq1NxurexdUC^@60yNJ_H7X|=
z^?>qc(xk98o17LsS*XEkS$B4DDhqeg$)XgICyhhd##m~D>CGW|uwZfqrwl<B?HA~W
z|1+U0T9nUMSLgJvPq9FXN6)gY%`MY@vu&e@>+B@TZd-&lh_Si4mbJtDU(4>Vz934T
zj78t#f(M~HDyka))@BBkxj&qjhKy;qchpfxrFnt&g@Av7+DaZ-vP`)qDjI8CO#c9j
z>4*RRum9%hwI960e}7V6OjTjWk{S>P?PYqNK}Q--ZS9+P_fJPy8GT{!-}btXSMwn>
zHN(9B4lQEGF$7AWx?2e@*Q8-WuHjgiClr~K;VT$v+J%-G9+c<tB|8o;=7-pq^ttF=
z%leb?%G^PEE-$kEUQThMx;ms?c}k`+pynt2<4~_Z(WOxyrUmwkUiY*tVl(T~3`ZhB
z&cG}VaQ@Jyz^@7ZtPM@QHyci=0q(3kHgzLASM7@XuN+!=F&&O32Rm539>2n#XH-1M
z-h21?M5H1$DdJ6Z;Vvc|EAjn%?|zU?&#}Bi$;S5dV9bfP)#*=#u%Z5BjLG9{4IK_E
zN&J;>UEEH#ev)lp)R7d>R=${kTST<$h)a+I%N3U=*&tR1ondqfPuDVFS$1k+WIEif
zgk#@(_hamQAQ9HsG<)oV<b$+zu4y2QD6ZY?7-A4}v(4$(Jt#1hsh{hTCL3S{7nnUc
z9YUUks?xI6T9XRv$Js<kDGHV$|G0ae?H2@na5@5OeGCkPv*+D$54s^BOS<A7nb2Wd
z17%G`<wg(8fc=#9w4p=3)#37q2~>cb3i8+0f?u<tuCqW2=Q!&fcE<-rhTSEE^JE6;
zImuRHkGe&{np;IShF9&vOa;OuWl>~@^ZB%Vu(8pHq6x6bd--H`uyHGYf8&%gaHDtJ
zAHg`1AI^_Q@4X9#UL&fGyIkBlq6zPWnew!I_PlsC{{%WYaHeIj?CF%sp=x$eRB+T@
zSwF!v8RK`kv+@gkou5yO9VolpF%P=XE_S|{jDc<{_&Y0KlILA$0{=i%;Q4le4desi
z+trn&-K}G{c2>ON+E(<@U)GgP+)k?mItwiJrv-*)-92+%#Vf$<QUdj^`CQVC>q%Gc
zraLarpks*;5gpE2C@<*fbbJg|@Jd~%nm}o%d%HZ(SE&ykW8Mhsvd;^;qJD@8dRbo&
zPv;X5eb|%bot3g6>+<ZkGM%!sL)Z}d#s2BR0oW^Nueu?3>ehB{*uis7uLXJ=U!2fT
zXWtbS_QQa+Uy!0C?=j>%x)WQMTXV<|FiMR&#cZa}T%{maVg)e1l|SU%vTZsXL_pv^
za3UF1L=em5C!EEUk$h~MLN58ChAb^87j<m3*UDRzAzmn{m(~RqIBcpi+|<8Z6|wa)
zt(lk8(Qw{Id#lhySec&!2CXG+qA|ARJqtZp1wb8kOU(0GAVJF+yQ2&%=xnXZ*g4_}
zWC-kl`LLu|v}$>+QYp1!r3MNmkj}b8tkaKQ^$HQw?bZj`<JoL7dmx*t%BI975xd4r
zc38UmC1JW4n6<1GmbT&*%vX8#=&<M=>5Mc<3^ZX47(s`^(obWFq8E5l{v+LMG`AN<
zas3r)8KX8-^EXz{etL&Gn@fnyF6_!3C~95Mur_@H&77_~{$-5@wKEulCkJS$?Cf`E
zJ0zY$XB@U8e72ThTf09gg8|g%mi@J+Tu5>uDDza#S^?*PSiqmGX|Frhd1P2};KiTH
z^i6*VWwfPh*?e~XfSNtmaBN3G+CuCppkz?vuSrLVR$DQbdrK^2Wrnj+FCSqg;r6}Z
z{j1R#giYm*Y*#1P?@rHOjl7+&u=(1bOpY3wm_jtu!U^TY>^BOfZhI#q_6|0L^j7PX
zEt>sd5BfMk)#9+5?D&GpckNO4c)#C$knPe~9LqrjPOzM-d4Y9yO?X(Zz~0dowoE5$
zS!b2vroaZHfEgpqa%Zn#`p}x}0{TLBv<=OPqN`H(B<Hh+Dy-J;@2+^Oo#D7&yjppY
zi_M_lKJx8!?8U3F#f9SAmC>>&KWPuK?US764NEJq{aBd4E-sH1CKlhMSmkVU(aQQT
z;<M1INNK?mtox%z0IGCyY%FWFTDsCf^_BOPvc!o@5wL<T!1)=^XKrS#jTZiE&xj~K
z%U_MkSGM84mNtUXx*)biL7VlJHj=N8bsttNth#+Dsoj1DXCK9=ZN-5Q9E*T|9a5oR
zvZ^&SR4JbVCHzQ6gh}_HXv46%xd_iuaSmWspi*~MZbC0@A62?${}>!gp&<p{maPa1
z3xUT_=mpx6;}tErEA4KAFSvg!pja$4-Z-{ugH;-)BV;*#_JK*4F6nz(eJFSUmCK+i
zX2mRYSQK-V@WMGYX1CMnAc@J|WVGgZh*F{7&oOKcYym5w?HmLiwP%yF9f%e*b9y}9
z!JnI3tBMx%jW$xaIVSdrI!)rlaJ|?i>os(XW^O_*HFwRKX?>?41Z<SBSvq?*7U+$z
zat5?|5wi7ko_#KR*e@pYk0+<&{$q+?3VT=56uneJw{P9{svHGZURMObe=Z-Jln6QZ
zY2no9<*>w3(H*&tVCoB-<Hrp_?Wj)}H`-h5aCZ`AL&4!Y-Az>MJ158Ytt=`_16o$h
zN|YZI^9illgBip~+4jf1)7cD$4|xjy+1+}PQ>UY>(XJ0<)4dZU%RbI*__jTmt?oWp
zzx9G5DHs?`EG3diG`zAc%{Z?l;DRWH8z0onP4l!!?Q=|s{Q?^pS0##mp6!ik*fHIr
zQgJQAejmVz*@s300{+0y*^(|l_}~MmtO`&ay{#vD3?Rp-*s+bVQ3R)8uSof&dttT<
zg`bR})q|~D2B6P*U~@`cwteEGzLp(=9`HeE@3x1#D`zV&Fs*i1+&jX4x_<-?m}T}2
zDe_K&=yFX0P5mydDBy%=JjEGRcQ)&uw-1dIZ9Ip&57ssTBmZvM-|ZJ`9G@P_{nniw
zXoq-uN@TU&PMP!Ba~R(Ax#NIn=|Eu^&O04Dzqvt0b}hSc<LHdvyd()$p5nN%y_$y_
z^|BF`XD~m3kB8k6JN*oP5mjLPnKw^BFeO-+r;uOBq@ZOTn!Y`I#FIxaPjL7`+#@I|
z9JYl<s?{Td@p%tjb@Wh?ZO9^3DUYFYCGB)vpjYc_?|F$mdK=Pur`~2Rnp+}JjFc>=
zb%`;K{n8zb8idk~zwbxPVWYNN(Tz^nome5+D!8U=wgB6Oq$Ox~>I_ERgB^9nC@F&G
zRz9MDMDUNaT-jGi)e8z&tPfygZz=t|KRm!GH<?EuA@#N380TqF?#*tW<EJk+kae+E
zvYGCdz2OiWK9M2Nw9KLp@k+yf2P-SgH|-WD(XZ$+B(^>b8k^(EaVoa<(Q#{U+{(Y1
z49D$kcO-HF`x;uVV;^dZp!pDr0M#X+uszCoq&<aXhi}B@i_BOf(RVm{=^@N!li|AF
z>{GmFFR6xhIy`s9de-S!GyOS^{AGs+IWjq8Ujv>lv|HEv8`qCFuKz`L{gVgRKYwuj
znGZ-?Z9SXAz+ChnpzWJkXvUi5)G(b_&YP417?JDoZl!7&KxP%OI`(jhWvI+<0-fAz
zb12e(wVw87a6Z-}2W&8<B;-`9&9jX4b+W7wLQUG`DojcPodkiKb&t{Vv0t+_e9#j4
zgj060M8e4h-eo`qojv4C!zYYce$<GAuE7L`qNqIpSH685e}*6TH+29c4UPCvCP0x~
z$m00LnK-qK*Kf2ay~wc6?PQHY6qU3Xb-}T2OV6&jEhTeZ%TCbriBA`M)KRxMyb(E|
zJuJNALD9Y}HtiFLM)}t1tYx2wPn`{iwSf9mJL9G=7z)QXx3ZrC0&_q}rYLK|g$n*t
zr^$(Uc?xY5fGJvX{&^1hS$+&E@e9`rtm+Zu6F(I_$-R?~JkojST#M~|++xdn-z0Ku
z^bnz5)#)S+YcupE9Fvl*-?&fY_2Gl;dfB?(#^7K@lGYN4lzUIo>NqAF_i;v+lsd^>
z_dwgmHbluu?n+4QIlKbFG@$6OVB`bGl)^}mLvltS)Um@_HggSDE<Ln_G7tv^e(2Ei
zp#yakEIQ`lqi6(Zd{=h(jzraeurp8<i0@#6(Jg(YU=9?+-4S-0zUmf<F%~{UP)_vd
zzJd^RSN(l0`vm%$ZGkv|wCciggX)XVtce5(X&dU~hKggKQtSm*Ej*HP<Sx^rAfI3h
z9L~>ouxCOMoY4q=cajEIb8MK~!mbHbuf1)H36)G`lkS>Z{}!-@T@t~+CRF;SX@^)d
zIB9AAm$Q`wOhvTVwFBi7tG>MW#^x|<B@;OA{uigQnMSI;F5$eSJNRPa{Ey~n$~zGv
zJOdXFKR$&M1r95f)p#lhCs*~9axaD0oqoF#yEcw!srZ(L)A_^){PcPt4k2!O2|yP3
zwXt8eB!1l;aN`g<3MLg-543%f*B)KtL6hJnmm>lx2V{m~f<$h{a8NTB#}#r695$iH
zoNU*dBgRkQB8Ux7GogY4Lm(sZ`AY`>P>d$ng^RVlJ>O{>2sC^;o9|R+e`Nx(J$}Ug
z%juzK?PmRb)Sbc>O_ktU_R*JLtUS-2KK}g6KYN@#|K!QD?6W6dJZ{3jID1j+Zm)y}
zR#vfJ;=!Vs<l!HSHXn^n$49Vqsjay@AJ4n5I8*F|y}!gKLqV>ig(mqXaJ=-TD8H~a
zTLBrlpR2C#-hBEO1?zGeJVmWN0WkTR)|Kzq)LiRA!n);%p8x=C{f6JFzg8&W=b#*A
zdDs=AL6~Y>Kq959tYlWBa1NH*iU>%xG@sZkw;j@@D6`_a%ek~PJ1})rj63|z&mtK5
zJe1yP-MF>c$k<-c|7!Dt)>k|)CN%|_WN}Aj_WA@mB&N+9Om{e8co{jLgAxT-NV*c8
zL0V^GDoquQ%OG|8Kf$@IZ0osrQ!+4t@X=9493HD~3gXE(8Xgt!WEdbQMeH>`+Dp4w
zKwJ}7zLh}j^>WzW;6=qloTVgzmlpO=eJDoxV02m@E-!gC1#e*qBnBw<D9vH`nb92D
zhPaPAgmqbV)-pfCVU5OS0!QA+j=Qhgn`_v8tjnIWDp%qDcoPnq{Qu32rhV<7Pg__%
z8MI@2Cj;yQ=%V>n*gA=KCUC6>MO+(flQiv~Q#Hq8gX4BM3^!ucpxkL?H?r|(jYXC$
zHH%AWoe65<i0dP`_Zc+;uqYT4CX6_L+^0!aM7jp@h;&e(P>&vU#4|t2n^bdB<sEIq
zzXKb98#iubC)bDh_2Fuw|3f=c{Y$54I?RQZuc`(#ucxARht*v;$(PeQ%qbKyw3^W&
z&O#+py*}9{Tgg{$D0_i?>$lfw(|}P9ey$Ds8Er9aER)TnfPK;aQLBQYc3>#`%LU1-
zr4-x}wt$5ll{a(wM1DK%u5D&|*tjj0ZWY`hqk{dhGlgMjUbaQQ3l_M_uexu5ymT`|
z%`ZTXJ+PVDiH-+qj??vOfvzW=-EVm0_8KPb2MW|#L62$dcO6{3@UM94+e<tR16xtL
z;gNnpF^3P&C^(de{?KeA;DZ(2OIz2vNY&XMx@V6QC<wjFM4oW$l|}sJ;{9@tV2{gZ
z0ww}PSeObBwYN>&aym55hB^)|=52PbGUnG0pFI;}meGcxfKEIUwiH7jKYa4p<B!Z(
z$lA*M{Dz(s;VR1)<`K*AgZ{)A*KX<3AeCw>Lwyvi=Q9wjn7%&4lypEDP^f{Xpt>Ez
z&}<pYdr7>9N{HndCLV0QV}YariX9dzPkRU`EsGe)KyYwOfEXWH`>KT?!opKgiV$pY
zGd!VQLZ22)<vIuv2-pm5#sf~ej-8d+hv8XeE++7Xg8uBHg2(5o2e4B63|tl}WgDR<
z1Qv)<IY0w*vN8h<M-g1F>cA$g;p<kuS!t4t(%2xe%8wYBcE?e=;3PVgDg5bOLQ42o
zJf*NG@#qBB!XO~jPG(k5wqLPydF?owih;}lO@~`<VW0z9m4D-=xs%th$-PPDg~Xo>
zTGXJui#Hpu&(b2s&|6&d;7oWUYh$&OwQg%w|7vIlrpdP3@Cm=x(=%WG<|mql-D72U
z5DkY09sG)03-Iu4Q3rp?OcJsfOF3GM;@L4b_x=#;v^MAiuaxqK8i50|Dm15wdt`$f
zwW_OoaT<8*mG|BldhoCMe)-8wICnsu+VMqlYN4(4X@BJmNf!>YvD+A--D4}yRi;1R
z*tly3Ra0^0DI~TPy5X;<quB`W)Ke@QVx6|dPQ{=o&B7I>h~yzH*-<%mdMO_aT93@>
zod+w)xe6LE1)SZr4F()2=r<gnpa6c}#1T5)8_0N|-}t_@N(EbS(ZFG?=gb7aHd^Ap
zV?=XGtloqtQ~JV5xSIKaHUyzWxlxZ0s|_Y^+v`WU&h_5%3{Wkg0ovws^%OpJ*d*Ng
zKQZXI3x!)){P$I3bIf%jM8SMhPOxg2xh4t1+5Z-?ANF{P=(Z8;97!oXhu#17jN!#?
zHp0U+z|B~5MoM!sK)XY147X|EY7LO*sg(rKn9HLWmQYTdhtVfRB3vI~TauPQlCwDv
z$Z*V*EX0Gn+OH5-4#mZ^?}1ir0PIKLppY6)z^{IEMDJ)6QNB=9uvqKq`QU9>ukrMY
z+QaK(oO$SZ#~a_e4bT`L)4{@zK@gQR#$)$ugIk<BpV*uulBOQ}(NGSa17b#lw?XXC
zytbiIt?q8VpnHM#xTH<$o>y##&d=d=6pI`Cv_q>fT(0&j8db9*wrx28OGtC^h$4av
zT*`cH&c+HfM59`5(^YNztwxmt&GSPbOo`pptsUh#H&i>Tlkke2Ur3sIn@Nv`9h-2L
z`NJWzr=V=n^=DQj|5wB5$6!ExYz2oCFD2m6u+*9Ce*?E*AbU8;e|ZkU|Kv;LJ?Nkr
z@e;TG`E&ntfQ^2&q`j8OTkE+U>tHUQ;gAq>7tazFxyIi%gA+EOnR7OoVB>{(0%e%M
zO2`TDbk-dmK_Z07;<K7`<cD=xo)#9VmvpBkM6c(o9Q)pqkV99Qp10~PdFcW9C7F}r
zzM$Z-l>~0D!M`t)8Z(@+qm8zcx!ytyJaD;?4sb~a5px0{-0o3O$r~ix?g~l~$Q7!d
z_--_$7o9kfx@9h@k#sG!lHUuhSLUmft~~Mb%=N*|iHcn=4S{?PGK9<^p$8@vEVFPQ
zs?p_A&TtevA_u{j)QR)A&mdt%Sk4VzWC<<bj#(1)Eoo1tBUjH0SZ-yeGjfnFr;a55
z8;G|1k{mP`h?})@O-(2_je>q?k=hBk5kwSO3d_a)M^#BVi_Bz_4lZ~Sg5`mP0Nx+{
zj<LCZQV6Au5xuV6&{nE`1c;bR1A7sNq`|y|?jIsr{~@Ba8qvBwp1AklWucNE4NC@Z
zVYjU3!Wp8lE(-SSBD8YU-M_5aXN+5A7$(Y6N^|=XBP=h-l%<;^EMBK`WPOkfR6Mo!
zb(H$9?VrY<=~6()SUi=PIYZbV1D^TJ1&Z~aZhBCBnUAL!e}j`+B|<Y;k5lhVH@SwA
zkk@cjyujbm#bEWX^y@?jp>P}r{3-qU635JHOa3c5UP@G*G-cE?ky*Ep*l(QhjjJUj
zEZ$L;IPGf%-y^1O`&R!N;%<@KgJ)54@T04>9*Iik1PO*!oeHtQzHnFfQc7kl=JZ@k
zhmmMuc&m0u@ezcl@9^cY53e!bXNikvQl3b%;r{X*Hc&#yBU4IT&1fb-t%-L#{Ed)|
zP2Q>Y=bJJ|HJ5+c+8Jvu_FwBd>7M@fjr*3Q%tN>&YL2}A29%-UV2A+l*a^;Y_s<1V
z=%-z{cSyz>O`-GA^WWkW5UT}T|Do{KAvb{2Eh){;OUL09B5+llr%hadZB1-KR0}Gp
zQ7iUA{yK0(>k+WSLNTDH0c4jBgvvi-EZP-40h8Y3jxOhA`#4b@yqdO-5HLp9zC<dz
z3G(jItPuCvu6cWy2=rc##RGf8t`_E)W;Mn8B8UjU62I2P9!2$C_EP7BH^jf%7!3fb
zGlxC(Vo{r3yGK;NSZ}e2oc3`>?W(WW5oy4pr23J}L_DyD5RCzg_fi&D8*r0RBZVKH
zPtk&M<A(iU>;t<Eb}U&*c314R4As8BXB!m&7#9!v266pJfJ<HqO+miiS)Z$gqQTD2
z>4FJ4jN|h#9Rg(oZfP6rARz{12aMWUU+r?yDkt>~Y&G7QmEa||*qjJBy6(Je-88;-
z=W7h3{v<~8`?<dNDb_4DbiM3cA9f}K{P#M}ZD=loBW!(0egG7KTr*&7MtFO^^O4PE
zL>w8LhBzH?)Vk#<_vQPx4M@<gR=&KCbU-{VqC$X8c)&V_dx3bbuT*3ldxnrFP|)%r
z$xhuAW$VHMpDZ7!Xw*PDG#<`bn1XE(NsE-o>G+aY=qzLo75NIBz)p2eBNL>uii%PM
zS)5b8PiuX_ykqn)p<pYK`!cijnCTM<h?+f>pRrk`2Qa*iU;*W{b`SWijurs%)XT%A
zpE%I9m>RUTYQiX%Js3^)u@;B;&M7VHMiX%rY46iclhX=(SiEwU@gO>7MO2Ya2+pb(
z*_k5jlC0cQwZ{-jS6f+(;RXupnE0c#ryfikc3CXKf%AV_!C^*cE13Cs4-4nscyBBo
zh0ph58Ybj#8zArjej?10g?wa!G9)#sr`<`SGuRMKxthXM?YwHOQj?I_U1Pcd>T#<N
z_QvD^1BMzO7`W^x_Vit|Ar>4a?X6k^%Huw%Ec&kxgSNhBCwO^$1Vcj`k3%hWcm}r`
z&ok>LC5H@x3ugkm)rymnd~T!K!_3@+>TVYA*lTS}I!gmu7?`SK#zMH$8hv}*Z7m1x
zBZ%9d@_iN6HrfD<4;qGX2M`qRjXUk|TMku~P{8<L_)5iIc(3pqE7h<X3M~M_nC_&H
z3yF(^h9}B`!eySV3&M&~kH!#K2(iwKdYCX8&KeIiX`cAlDXhQqV7a(iZj)sQB^S}N
zHBy&Pmhi(2{II|cEYFW&)`@QnFF_w|7+C!I0#mSVv!7@cCYRtds<SxIk!?a3J5Z#m
zmNOw?jjTIw;BWT9kG1hcb77I{88b6r7swXjk4_OAa{(O`2*jk@wrci0#;s}&t3DC~
zBeZ1*1F__pJY%|-{^V?IP>tcgX=}4Hze3<J6gDONDFvVyDHAE%9#|o<az$)dNop!O
zZxGGYLP*oW5X%cvXXM$x{FfPj0O!Z}gLGQ0FC`BRjy~-b@>w79J8%arjf)2)A?n;L
z%R?mA!nY6c5BqV?gOm5?r+NQqV}5#AYy?m4oZYOipH9WEo6ra(;9REp&YkIXT5>M!
zjcp!ytVDQ_r2Y%f;OnzDmZpXiZ|j-pK~KI6g%AhtX+^@b88BlVg}i+636kx_A6R0;
z4;RutSK(VYpG-yo!k*~bVtyWwKz7>v>Ou5}dL>yZ-NiiL8}l5$Qk3WVuRz-4!DxcD
zz1E66l=r&!X!dUi`Of~i9)YzVtx?saxx?im*H|?4sNs~%Wr<foF&7G=sQGiIHN!&f
z#ZATXqQjEQjF<Ip)lms$j=M+5FgYt@32nz%)$3^=WD_~dv*<GuK3r(wu~t~>(gl9!
z>KdzlHaR#zV6rYd4iB4f!@UJX>yeQc;B=GV3G*SQUK1V4VwX||sSxp68(_z*%pOz^
z&=6;204SNvFA<=X_U&lNi!JuBP$2fBp37`5Z5{`;lD3v^&6%ZDX4Fkl^dT6jELuLm
zTOxC@AKf1!wbnT}kptj|?uZeSA&8>QC~EJj0hJarUX41A(dMyz!GIP60`*Js_Oe*?
z6xW>&3}i^z=P~X*2^lGv{A@BSEwmU5FEVaY*Q?}y6=g3OwtxlK0J?==M0X3tg~&l5
zr%9W3BCjzuk`X49CvGD*p|&xpcgzjkaFVoC6YLB1s}&tDECv{=sHlU%l-U>v@DzuN
zACU~PGc6NG3UnS9$IRAvIN>qoJXR8bsvV>G>VsI?W<M)A?8;WqMrvsbob3cE!j4!&
z9FEE)<~S5}$*Ex_NIO9(R%WG6sKh3@AR%w$=~Q=8I=l#Ig=mg+vPmrBM6Zsuj&%t;
zFq}sUaPThje)9zWbZK%24TJUZi_<Mos*5{8r#mHfeAQ<Y3a(9suIfb2=lShzeT8^e
z#05z5?Y?iTDh-9)S>^<6FR96L+A;eI&D%J0r^Y3|_S`?)mfYr+`Y5C77V2@&Y!6_w
z<u4C>L1~4mL9}=oOMh6;PLZJ5>43um+L6TXLn!8WavM%09kEy`0+~<ZsJH27+fU7W
z7i$!w(2ZgLZCjN*^*-PLfGyL?VGI5&v45DignQtW#l)#boP>hSFJc2y-H{5)_}2<V
zm&;)S&QHJw<CcPzEOy5-(xtPn{NQN4L!o)u9TXk#j|OBctn=PWg=@7%E^ro!p6~*@
zO=JxGY7%yriV?)LoW0VQgiJZ%3nY>-t-&V^A`>k4Dy=*tVNai`>>VJJ5#fj=cEi{m
zU&<T9%VZSa!T3W5E#`~aFWc}?jfrEt-&KSyb?56+#&XIyAglT=OJv@7Mg<eilqX1M
z!oLg)m2Ti5w!Mm?v3DU2L{v3#9-2rCVO(tV1CF7FaNR=<V4s?2NEHJK!QG;4Ye(2E
z(X#Rywch*;6hjjb0t7_EbFwoy;Jil5@KlQs5m(;oV@;sHt{bXQ5w+L~6U;$JY4g^P
zYJC}%l2N8!+cB9^@VGqKxg2n{Mi8jT8lP?dePIlEz9#$<nIh$fB_y6gO@GxU9xDt%
zS|_i57ozWg>iyy+tdKkeQDP@e?<|n*?+@8`-mHN$7l2hROBumei~lb%gopxoQ-kyf
z8)$D8>-TXOK|We4fb9K(@PRonnR*v;nzb(sm()>yqlglCM8@cuP<2W>Z(Js5>Y~8w
z{k;<<>FVS*ZXz&UP|{_pvYc537t-X&*q&<!3ri}mUkVqXP;IkQGiY<Lf%B3s9@SBG
zDl?|zLFRbbLSm5?o3VLJ&&CI<rtFEZw*8~aNRzdurr5+tw~3VzN@`>f^+~)f<uR9|
zc8hRe(+Z$yK&{GQzFRuw()NWVO&M%h1%l`!2C0j9$R7w1E%~X_hRfLCw81>YzP#AO
zbg(>Xk;LPn0_=<-2Un7wEwZ~i@l%J6PrVO3joSgoc_r?!69$@MLP&*;6LMoAQ(yKM
zpuHV-BAH+8CKmG!1CA=4IUYJ~|8_xVk4<f|4x!{AJ>dg{-C<M7w1kq55S}U$1lIo<
zSd&g4*!0<P%<2*lL)ShL2%>4jz>^Rk#A#BS<A@gx-jGR3LPiTbg<2z7^D#>RHX==4
zK@S42FjJ367o1?>Fe#Z4gn}QHJqV$Wo$;|F)*-atK4FY|^iNXtDrRv?Q^4p66RQ2P
zZ!2Ia5*FXHjDfwkH{SW%{?t*y?)Y&jEr}995S~y0-^jxw;wV!C;oiz?At|>KZ}wKy
zt+63T!UGun-FB(%$N$PqalYY95#~tH9E$>5dVn*Zb$i7=LN6}DS16Rj>V{JT=KjTz
z=|xpqf7|HYX~M59B1k0=f&u|mgbOU;6UA%;mW2L-U2c$g#<XB%=jwXXl#h;YUh`5B
zRgJre7C0{*2mwr6sa2}HYoe&vcL<y6`@2MTMhrDdh>Pc0Sa*UfMpj@&Z`_06QJwqV
zVv;YN!+*!~*XQnYuGi}5p$9&?fXh9D^_d$kD!@d+osWS()RdHG(w1yX7bHLDr*_#i
z#Vg#^NKBvKm$D5DHqRYz!rvlGgs<6QW>KLK|LX-UY>}HHvn1l;Dx6>dnCUM87<xl6
zG5(s1zStSX+UUzP0W_AhNem5>>H(qgLTpmb@O;R>vO`cOwBFeXNdak%6H}6$>4f1J
ziS~H|&RVvQGf`d4c~k;BF3Zvs7*1W}k{%<fT<Ze6z!}nNGeF0Ns42$dltdN~NG;x&
zgveG^9O!jLi$4ayO9W-Ixp>+yMw7GE9Cl1Sp=BcNKAeaY4Coo*a2NJ0$cNYwI5G;i
z&O^y8X^2XQHAfS;FOTj#VN?cAY`MEXd71L8=B;D%Qqg}7BrH)Bamj2mTDO+aNnkJ1
zBeG2u1N4!?&|U%e)+XEue_oqoA5@xpplE)O>B%t6IErvl|A|ZFctRv)L`#J!7VbBx
za|soAOlr{Fh60A6j-qGxGLGsHDE_rGvT605>HUj?Oys(84a%hLRGGrsNtN}K?ZxZi
zk>@0<B@`oP>QItSNfTuk8Bw*jMV=wyWvSBywAx(4Q+z)=M!k5)NgGKGsF5Cnk%$#Z
z$40mNJW|Hl2>w>DsFNT;v0eg<%CVF{*szK#?|^-rb7B?4X#=$yD!KIelGh^_{YP8{
zJ}=}l;x=!|a!h|Hnw=h8MuOv_XgG9Xj)#*zs(cV7IOs;|=mnUPL;u`*{75cZNSlNg
zMpJWeMj>!a51qDrMD&Y!F}(KN(Xo4;ukLftEPy3&krmJa+@bez2rqX;Bi&yo)(nmA
z?%`VOSU|i|dD()@JpM)NXbCzDe^BYbgElK!Xj_L~S^OO{ox(5YMeNGxMy%8M^l~gD
zYlkIY_!UB>r)^NFD{${LP}OngHh&~wmaqMA+5n#vq6K7S8nn@QN0vw4mLdCVeLMG*
zrJFpadrpr>+{VZ-?J)*!3Dne}2#-Lh<v5fChy4t~koln?S9ny&qpH!l8!50RRr4*z
zBe90Wc?mG$`Ud#oe!C<2FTx{*`9sV^9E#1)^(Q5k6kAwHgQjh*Xv;OW(V6M}>?VXH
z_Hb4y7kVS7>%m-&Gr|$O*pN!3I;$fK|6H@&qYT(Zn~YpWZo(U5rd`}eFJ$FS7Pyoi
zk?rm^(R%TMW!+nSSW3AzTZiMagv(nR;R7r-s$SFp<`j8CAPn-_XgQ{2#GYCsdlK&Q
z+TrVTAC<}>rH9M-4+U#ESOF~1L=2d8cvXq>YOQmSRbGeY7U@bcw4AJbyX5po$EXFI
z9)e87lzPCvLQJ44LzGI_0#N+9FhoAI^$bH;9G`WJcixV0DJImyXpkrqo^5({q^MV%
zSy<N0R)`1&`0*kG8wp!Y4yazoNV^sX;=Uyul=s-d+!VS&VsUEX0;mNb*f@z9xK}7!
z;~j9OurSJn1knqrFl%)P2-}JkC{<E_4wm4jTB<=%xCfFibx*}-x$Vdgf>2$PH94xu
zKzGznMN2>i*wANv8W@v2j^R5Vqm;ZvzCdOxhxGis`)YU$Z!_ku$FW?0e(1z+UUfm_
zV&3lY;_pa7QUW(->4jN%7Z67^Suv&m1vP*qkwM7Fy@%Kow1$<aR*Z#D5Vgy$f|Az^
z&oNyx0Z%V&!={FdB#6CG%11{=lhhLnY_+5^mqslcAd)uJ{3DSZA;xC0O(X`O^Bu4*
zlRTvvvN~XPYxate=OLnvLHkzKJ?qer%w>O-sBD;dSojcEREz(|bBX3x5hK`uzTeP*
zDh$+Xyf>c7O5IA^a{bJzW%EGMvY1xD(C~SKouLH@TnM?6OMyi1){zP-Eq-3G7hL|$
zu5O1J3&-iar3i*VVhC;z^gxP``;CY`631JLgocxD-v5Q}v7*R*XF@YvSk5k@LnU9Y
z$yH00-V+>{M}}$mxDi$_91x~UfE15P>8#!_V}F87?er%d2r>x<0-kc*h7tEaoG+MK
zh9i1gQ06uG7f3&tRpIo<sswD)Z3;SWWWQ_T6Q9gab>KvAj#azvOqy;SY&tVzp1K84
zqQ|c=fO`>F5eKGK5P5@c9a5s9<{y{z2b>RZspePR8I#vue61!9c71rxL>G+j4KZ#P
zuj&p~u5==6s)zm;Up^OB;f@g26R4`Re>}yFNxaz5ZefOF`ixOea8pN)bLvy!4$j<`
z1P(Bc2sBV6EKrB#_^I!?)6HFMXDQ0qgqeH55pkk2|F2C_jT~XB{H-dPk<BmOiHjSi
zX{=|wQNKIuhr0>nj0cV&2-bubNYKUEuUXZj&o>|PLw9*e=;E(%!9nSl4ke7sH3>^n
zP!7V<nP7|Ux%pn4y7|CAfVO^x2ax|TJD5xmKQNoT((M;!6MO_E><U~kpTw!dhOT&@
zMYU2gvh*IOc0_jgmR=N4ZA3x=!SjR+scE75!OJ}TtdkzI#9xswnP^)4!limj^o|VF
zrP#s>C(}b1L!8;G<cDT2dTjO$lla3LhZPxmA#Oj1L4*E2G_jp^&tcb#gHV+SS4-eV
z0F2}HoA^p;n_YppHGQMQyX>^dC0Yk>yo!aIbUs`dA~0c7PF(HDZd~yeA#_BigV?QJ
zHNxOnZ>w6dHX*Or*6Y2MF~bLmE?PIM1mip)UrE%(Hd55=tvsM|nqbuwpA_Vj0n%lI
z)DH21Fa()QmbE&S16L-LBLX<FC8?~V%VBYJz(F_J0N8yOwaKkQ4uaA$Sle#ayWmli
zsPMA&sl7!1eEg!ZNdiG7i7U!4Rc!lG4WAjgv9=3c1UKj)oCelzGJQb50PgaLsVUjd
z8}&;)-H$H<Xm9fDV_qE?R}{j^U+Ky~n4(l~S{<q-`0Jt-qFTCvDPw0W8dnPb@{g9e
zu(Awu$q9UwAA}xyPmO-vTQO2%7FOp_giV@XFz+}EIF*xD=`s$_63lIwIku7|g=32C
zE?me_VO@dmiY<Xut>~H4N3zLrIt%Kfro+J_C=LjGVIFhXdAWi@zb;Y}ZxvYnQamRe
zxfXailB1LC1&Cfevx>-){xMA1@LpwrjGTkL?65m6X=jjOVj5jO$}m#jTVFtF5#jJp
zzF<(zCv2nuE|<e3gj7TTA#~Aw<R8`B7gPn*?x7NN8GS7hfk!x^I_x7Q4ur$u<aE>*
zReis3J0!v9r;0i?k?0%!Z}oi$0Y_|O&9A|>A&!NF))c53FjhZ7;31NUJy-~MVcBf5
z&!yXJ5_$G;O3V9rj$y!4=>Ug!SjBP1fb|EL1Q%|NeTgHX$tkj5;)nskH&`gJLWK){
z#G=iL<@xbGV&-h|AIm*@0MsoUl=E`s9^k43aU`O7D(L`6xZw{WAg$}EYrqL39}<f#
z5r`?r8cZuul^a8p^;Z58s6;7T(_1S8YiEcgNDB{9w4qIQC_tz+h(GxO4CJ7by1TTF
z->sY@>)cl7<S<Cf;k6R6ev(rmB7R_CO?1|w;Uou1XnK&s*mlr(K>Ijq?5*ss-+b|l
zto;jQgvGzTz5WgS2Y12l^>4zl^Dq7BO+NhvT|HTB_i^ze+r7DtnpW@^dn?-0>=gki
zWP3-`O=HhA803HU_~|ddeD>JJ&uCLrd?ggdk2c4rP3o&%ghAp`$F4+m<M1Pg^A7}R
zmy3L>5SfE_T#4{l%8{?SQf4%=<pVTfRuZ&GLf+X-*+Un&*ez*TUq4%6k<a6|>G=cS
zcEa?*^ItnS`zaXAyQ`8J0O<5oy}5R`l26VCs|if(qSo7Go+5>ITF2+yv4oSr)|xmr
z_#;UNMc(vwIWke`$u!9hL7sKsa3$BjEKDk`A^{)VcTlhf>z}-nM9#Qir1qGMMv}n$
zSF@p8-x~@<f1X<Q<=q1KXkp<Q5y+A7<5G|!3a}xZH|KwlloOk5IX%cd9|DVm4Frod
z;h=qU*A&f?q=A%e-V!C)TA2OKLuu+$Ba#XEA>AIa-sjKd8**aJpswf$Kp5j9j)5OV
zq?F7R$fSV2gqnl6Hw+1@E2$QCi;g}H5YhnYs-a;l4AO*{wB=*1jbLGpJVQEzDRq`E
zFo&<`*;!G}sk2miS6T*yi-KHAEKt7&gbr3QAttv35g3D8rCE%I=_wdRG8bUMma2Sk
znPH7(^3y3Vs%_WTjL=AKx1~qk41{8RF>pHS<;}vqM6sr=2?@~<>!Bk}$m*?;kYJGo
z5(dzg&J0ceu@hq+#g_>Otw`4ak3n4h{jzY^<$h82lpRF^z)1iH@8!<c=H^-ioC90@
zVEA@5?+$#yMifhLUh_YHneD!Y0eK2vkT*Yn4P8(#pnCIyB*NTYlf4zrio3X4t`8AN
z*^4$TnYwQEWABvvVmm<W(SfpbK3<0b3r!)r2%~}n!;6y;GdGORf2IQ!H3z1P_us$H
z7-EEo;t+cjYnT?}!@I%+VbMT@X8x!Y0iEJ$v-iWl`w$NBKaC^hL*b5cR1{O8JhCz*
ztj_|m>x6gNiX~DYGU>C07%^-i++fxjme5}05liYi_4)ZTmWjct@?I=-@<LGj1=VI;
zz5(|wi9y#BLShn2BZ7$iY|zgI$+v!NC^wB#Ug2_gf99(e_v5W~yQ=xPJ8j2Q3$McY
zDeh{bVU-s@#dKT8vkAO#4J|gQ<ZyyrL%dqtB`sDRJi<{~-)<78zr&#eK)%B17c~lW
zGR1iWH-K!MrSjpiw&TT#dvJ%m^W$CC<pG*sMP8F)1{+E!jqSH`gC`zBZi|_CCA7<<
z;dE!)`-3~yuee*0tPNDVyU^BIn4QuB2l(M?X@@i5LwLO8gl>Wy9D%34W}{!z;iAVp
zfh8io&s3?wnJ=^}(dS7YnmkxGgZm#sK!FL%Da0;AbKKnKQf_ApsK6l!a^@e>jx|DC
zvIW;sR34uj<gE<J)$#<ohsfl2Je^~6CGp>s*oq^pF~BvO;&Nl4a&w1Y!cGVv;k`);
zSnyoaS5!}wp2~T~Dfl54;!Q+8v1P4`Zm82q$<^%VsvMxiR-mO(4H~iO#JZP~Lj&-z
z)ZCTEU*K@iM@LNIt#69-2n`P$G_sl;t08d~w`S6uL3%Cw8t>S`*Rn&yj+#6J(%`&7
z`vs<$+6%kbJ}g)~OvB!e+=v|kV)}J#@V5E#qc7X@qIWo-jE6^<&wMYI2(|IU<p{#r
zy_m?}0#g_}5($#x%%Ovgn!XH^GeC=5CIEmMjafcmmNFfw0YtM;hM5l}k>V&lZ$?16
z=Xf~cJtWk-VPhs+dh_5h^FjvqTTXdrc+O6Ku4RAz=YRfy^FzEzc?~jJ00Lobtu_aW
z&4)di&p06<17kHtvK!uqr~}aUq**i|#_+^Cz#6e!il(NK!gisk;OVi<)x=B05XrCy
zwgWDyHo+Izfr*p|xDBOo&B@-%&y_YGz)nmgFawp$8l2@If_G$oOdLxJDcHffq!VH=
ze8@)2F{>S3!&%D9$q<Md&U&XKXje$V1#1ZuE@en)6-OrKVC*=Y&!;8Q4D}~H<fl4^
zP#Wix*}=wkes5zm+@HbPy5Te7aDF_x27;~gtZfE^7yiq;6+JeC2_F)C$c~Bc6fm2e
zxC%&pE;&5lQ>7~=nIW4whB^Xidk~W9K%i?hh=JndWLDX=4A&vy|KdJ`!(_d`Ag&WA
zBd<!f=M}GUkyML`NN6O?VdM^t!5EbJ*FbXfK}7e^@J7NB{66TZ%;N2ukRn{_rp0d%
zHuOyLvdNrP#+79P3q%hdmQ<2$D$0GIVxzN|ZRU<mhUt9@-&0)4@(Z4fm=Hs$H@GIU
zDWJfrMIE39m%b0#uyEC}%8hEbUTTPwNChD14{H)hfc*$rmS=bn2C!E#PF=McuaPb^
z+MfK^7zV5%jxAnV9WHHV(*KeYH;gL4D{?qw1aqLRO<&k0p%pw(xM?yDdpO1vta2M%
z`g(y;;RJFz#ZWj0gTImTNnA7RmN{i(gN-vd19jvf1S@|lSj_P#haTiMys?~*`cmdP
zd}L5lTxC@GdXQ~evwY9WzJ5_z;xqEfL5~aoX9qCQtUyjE_UUR1aSV2qMp*&&9T*hx
zg->d{fO1X-mJlyRwj~~mf`3-#lUhaVWTCPRv07j7(9i%IVYj6(Zvw89lyBq5CZH6j
zsVQm)v5bGKFasaj1F6hOi^k-;TDP2OOnp!Mo}G7~!!qoGGKl=5T>jhVupmB_%&Ad-
z=QEzK>vJcGxsU0{)RqOxt}~g-Cl7nLKid{Y8pp$NmX^aD;s_SD>!=^?BUHQHy;L?W
za>7`2k8!yQwwJuZfF6M!d<*vjhfLb8XDNX$cwya0AxgA((V%gwz9vj!0hGvN^G3|p
zKagpiFoR?^mUjBs9!W5pGzvBO;V3orss&$r6aY1^*Jzv`I!kMH<3z7lJ-kj@>Q(MK
zjstUNq+TcNY}<CBqHf%SVDkMS!+d0@pD}&L-pb>rPrrOhF(wd8*j4IIB2OcJtkTE0
zr!v$DcP{!$OOzt}p!8y7<~|d#Z?j}Y1wca3unn#9qyn^>qoI%WQb(w#-bh4%z}LHI
z_>s&>Q>=zCnb2TD=)W7N$k6;mw&K*eDkrr_fYh2scP>Z^!3Oy=8BfARI$<o&+}_H^
zV7G|L#d3CEc8#ph^uEr7un)v8LuBSuA;c_zn+J>4#%ZMZ6~cN`teQX~qcAQ;YGK<`
z)Cz&~O&)-(OB&K4y~X9lb!-TAc$lMYEMQeTuoH5~E$n@ET2;Czk)w&tZy~RD1?8pg
zmXs7pz6#s?y}G=(4qUjr7<q%a&5#3XzrGkYSi5zSulzfeD!-VJ&%+hQdv=F0ANnQ6
zd*K#iJ_S=Ry~dcXJaP_fK*+DeHAd-owTq17C>Lc8m{<Qt;!ylmC6WjmV`xiM7+dpc
zySQ{hlj7Q$a2=apfY!jt;|c(8%I#!6vDQTlDDSDmNlT<wdQW<Ul;w=qx%AZw!WLr3
zbKz2DX%Je)`jVTKt8HI%vICUlEQ#IXAUxhxy6~>yQsrvPwM&?d6slH<EXAeE)f%8m
z<+|nSTY?lXTBex@OxSeOa<!TZ3S$?xLS~Vv{~R(fk*TTT6GdGtS(Ap}WM-R3E4*<z
z_A4Y{X+CC9T7tdcUhs^<hno=Ykyu!6)rgG%0tVsxX$~#;6~&Gt;b~u@Yv!sK`r^S7
zkzt(IpqGCX6+c<v6TYpKk3ZB^pskq#5<}WT7cvk4KC5)X-QX`JN=UZZLK6<X4Pex2
zB))d3;|9zm#7PgqxuP|5aYIV{h@ZxZgF(tI#wXW@`Ssyyb{#pFufsK#Hp8{-8~qc9
zl{AOWszGa8NtAa*N#~dm9>hQVysaz|xO+W7T04oJ?^I!cu0%nqOcr6*z*eYgb?(rD
z3y;$=;=sNp+1^gJRK-e@KuYg$Px(+r4TTvd7i?<r$6s<Xs(a-#NewIWF`bEyUxui@
zqzBA%)P5vc4wfbU!#Q-Pic55ANja5hLbh}-5DkA^7Eda|xH+aKErRBCfWdlLZ6PoV
zdv9>y<Ks#VG}!t%d;`SbBoiTf#tf?NbqcfH2aukT3)#Z8#Wv*T3ZXF!SHez|GSzC$
zyeOynH7q(uRzUq9;zWWQCjvHMHWc9ocz?pfsi^P+28WCH`f6pzURWe2oyA>v#xcD$
z!*Doa*fogKRXsLKkVDDfUZGFke(g`@9ru}>=nbkY`@}k6YHBKx^vxnXwexG%Tm)`G
zoUt{92zRjKf_r8v#9_2dcR7IJRChR6dChjaiWoLvS95b&R=D))Z#y_%h1U>#hZWTy
zFimc}{#y>7`BsC3V8v3$Y1|Mecah*Yg|0>wEuTGxwRDF-k3WN`tDm#tkRG=PxUr_g
z+c=8R_#@=y#nl26oSiMrZ(p(HQ08DQM^g><9C_{{OE|b1eRV-T-KD*Ac>L)05#r#P
z9Kzvl-b9}JZY<b$tS7C+upY71ge2jWS;nOCW}+hBJN)dFEXS%Y*6bGy;MkVoHjSS~
z;>Uu)x1!<Y0^V_?#}1OQm>o{0AOrwRYGO*Wf@UhITCAjO4Bz1Bi2bt}cdxVdU^4MR
z@$qr@VAxw&U9Nc0EnUU4p~@k*V$3FVG9vV^-6=w(e=IXNb?J0~S-kdNTEH+M<pLwq
z7Acn?I18&^LB|G(QxMXzgIon`+0)M^JbDqHYOqwwVuAo09zb>;F}C5!c)%>{@kP58
zp2MAPw{?gU0DNgNAPX1L@mu#*IsBI1+%4_^<ogSmcf_%1aYQ^;3Rsl;W)Cx+11G_V
zkp&gBoD)h%?}t*j(&F$`?!DO1qp6La{oRMje1j*V8=npLHv(c9e<AB@IA}H)F)}sZ
zl0YeAkeIlvOb?R6<VX}FW`3|0T}IRy;?6M&y_WpM-~-m%+RD+H{*_U?_XGQdRO6&k
z{?W#8$~(s>$~L-j24zux<QPYp!!{;$Fm<e2+SX8wq3IwO51aIu`&h6+;qZP^xS)#*
zNU@@Eq!iYt_Qbf4T$+eUsAW*nQvs<@e2`2Sgs4UyYmhJyGY``M4^3?(OTQi*AtUB&
z-NPUm-o(n{6oEt2u=1Dm5ywdc)0yJDL$?!D3k2J_!mTLsj?wc|xc;qA#yFQ>EVk|C
zMCX{Tdm1Gv$q^I#ABuSLb67qhi@AkfmBV^$w_(qmQYZ&>UnNf3?N#in;8_TZJeUo9
zlN8Hvj4UXVbx>a<=|?UE3Bq(S%3PYLk|UB`Udmt%5lycgNsbSWeqrB7_HybIMOav<
zNyt9nbMc1xXwvgBFT+Lb9o6Yr>C4_icZu*7jf!QZKN$>jpSLrntD-VP`6u(5`o5Hg
zWfsef88{c)P809C;vw~tUX8%ooKpom_*%9SdB3m}S!Drlv3tk!hf;YVAq8k`JjePj
z0}`2*B7&0QVl>E<7qPBnTjX|J`ay~p^WRQoGnVqYn)t{@%6y?AR*@9+#(E1lFmb8C
zh4ogBf2|6r6b^zyfjo*9ohZq`IRG7e*qp`El~Bl(0E<mK0b~sHFQHDTOf2AH$qNrs
zo|g@8>IzJN_yKOfps`Y_*_nqX-^Z#j=_L;2Vkeh27KW_&*Y?v`Pac$)l~_yb$Hzvn
z>Wp&PgyC#jWY_9!(Kb2M4%Tf?9LLy&;9cPzW0E>~AQ7cvoU4rUY^b9J$kh$NYV;YV
zwvAPoQDq8Tu()#I|8VMON-3d+dMf1EGdLwNt`@I(p%}8sA;5Mx|Ap2i8w9`zW=eBf
zcXZ5==hA#p!5$D)>_jAfflYsudB&9O-Ws*#*f&f8SZr+RhkjBA;b_xg2vDLv3Cxdb
zI4Q@`hhRtt0&I}<+AX!c1%C&v=vC1?^r7Ke(k2Tmsyo|^gITKYu#S1!@+&_!U_h7-
zH*9e@&I^?{m*Ansat%sJ#3*>hV~P)XXQ;!r;+0HR5Zw>^%_CNwG9p=UVG{jujV^ZY
zU!69FrRDY~t-eIm2~ZcNJ&H_cWkt<OM|VXCwl4w!8o+|&ApsSuH5jNa&_{wmB-l~}
zb75w!HS#6>5(LW&`AM|lCIly3xI~CcN8%clcF_b3#Yh5-u7t^YawRCVP#p)%Ge;3-
z3iSdW!b}PMr$XgQ9mm<jx!efGA_0;)`aiX2m|)|WnT~Qcm+L|v8Nvs2$$OB&9SgBt
z<$-(yx+F#EqIU@V9ZkyCWnsb&ivlUiqhUWqFIm@YV3yYep&B7l+)|Q|L9zWqO&?0&
z_+&h|vJ?X`n}vx2^7s%}S;{M{Mi^fLrV>hL0~s)u^nOh3pw=oWhgc&8-w5xiRy;os
z_L=THAF4%LH$n^{##`}5$&D6%*SSVqTVb<6$$WY=3U+4!DM|292kDySrodKA%=NT0
zV9m(kq%I39o!Xg=em+SLetLw{DQn2nBumOWM7UAa2dmd3`Y#{4G_;!Hh*eQ4T$i|{
zhNIkix=c({NG9@uwc-t~0tEF}-sZdX_Ex)gR4&}EV_%qJ8;lcJ4rgi5M0l$$BZP5N
zH1LRXG%3i`&ZA)u_GG_uP^grwadj#Im)fP)x1FX0#!LQ-?g*B;K4O!ZEC#7|zG7}O
z?7wN&;4>%;+5Bu+Nkc~*C__e?@fj3Qxqsp@f(69ytlj!dnl<3n1i+hXyjKhiU78wp
zFyW!$Wc&-cvzQI?a}|d14V!ewMs%<=m0>z7r$kVJ5@!ut!L`KYRKD<zUIeps!PrfA
z%<4$=zl{uldaNE{Y%uCnrPoiTf?mr@T1lGYWUy*1g?~rUrY+4`*yIQwaUPI+)KYu^
z-!;TFj}L<J9EQFb0zINN-P;J3I1cEk+^oyk{oZ7H&XAURHRS#}93m?@RdIN{!|`8o
zHsSvAVwU*E!x6H5gL=F$kMh0xDY5aq?>2o%aoun;xIhg-BV46hze{mS?`Ej<x#Bdy
z%n?K1Pez$whXZ210@|N&Jw;kfO+krFzm`3I1>a|e^$(8_6M_5$0Y;?OWwstopnZgR
zGFZHjJNSs`5!q-ZapIL;0QnSbP{*E9k6-~A=&b%8F@@}&J66J6e=YG;lm04FpfH1i
zTo1xfyvS)!6V$?3oQ#>B68H#v7+|apTN|Pah6jjwWz;zti&&HouDWEP5OaA+{_$#K
zLVu*Z93LbH4#uBPT}Y?!U}57LW9IcLZ-#dYS*=<$$}iNCS6b;>1_p%uqu7O$J`Y!g
zSgphJgJCfq_AtFj*R*jQrBGTT!jG|#C8kRk`TUA?oMuD+VY(5h6I>E0&x2q^>%y@h
z7!(JvH_ox-kdhga$s{3e0p`z-v2|lSo!*npt7t*S-q8>@)M_{fLd&2-5i;n6l0%d}
zgD_aYN-8!`7_X7E07*tM1xX;NF1Vry*(5dl9nz@{;VfU4yaJenGa{tpBt0lhK;otH
zg70M&6R9Hhzw#^C`{P`L&4~KHoz7h>Pk>dOa}p)^=(A_K?0)q4(U(sjKL7G5xe6nU
zoQUa$*y{-p7<$0ukMCp6V<zYz4YJm(2!bzGYyAv(OIjvFaMThQ6&kNpZe_TbtqRXF
zJP8Ttm0f|Z8lMoMMrfZU&NggRF>0ydC$ryJ@>j)gdPV_}kTE1AtHgYf&bp!`I;3W$
zReSY-+9SNw5fA2U3X*`vkm11)?ukf(cx7kE(zjn2(JA4oahkbokKpT*EVo#ZT@9;N
zrfL-szNm<yUbTEG%dn(6rzKr+-2CX+tF;s9u7$Gfd{{tiR*R9T_&*~Vyt1(Hfg8sN
zYn0Qud3PUSS}_3Ff7@$Dy~}L32K;wuae6)&9w3rBJaC8Zq*tR_D8kFrtvyV4$d3{X
zY!Be67{0UP_``D~fY4YKD8j6Y=1j=;dpX4sG8zmAh;gKd0M}X>riF+V`&fK<FTFfX
zOY9fDF3x&lJL@KD_QnF{3=Hld=MPO({h9-qwUZNJ1gSqJ>kzLHrVN6c!Ve9(OQ17M
zhqzB1e!?xR$-Mat=~u?j^}-`r7-5<eF#<^|wfKH-{DI%*jm;e-H$~)Dr$3b=$53A+
zs2}`f+q6!{Urf+(Q9IfC2|bgRcO(V0l`n9Kmx^zV+rXLE1ZF8Jcan;(GU^PYTX>3S
ze(?ZHI@IBAb)>8f>|?IgBW%LaG<&2Gbda{rbpoW3m8ffBsTpErdq=#DeN7?{xwvTK
zcBvSC$<1D|s<dpibTwMXm8G&Vpq}E$$K;|g2I#mT58TD|4%{uFZ&*Av<)L*Yn@1{=
zW27JG$)Z+nz=;sdf>b;L--Z^w1w#NiVP0U=3i8+0f?so(U56rt69Vgy`3_*x@>IDH
zfqN^l%dZ6oShXQp5^Q69)jn`SLM9b1VWvSp28Y&BiOsx~zrP_-!5h8fKIL!D$V}YZ
z)Pl|dTp`#Ti<=spcEV(N+C5{0$0x{G45Vop$S|E%4D;xqs2~Ym#Oo)VDPue-F_n;H
z2qeKFKHW&FHn}yql^SKf<oPMGlk1!l#UgNiyT}jn2g1FpkjqOuUB}tMnctPdJ{d2_
zWEd?u3GU3{jg29Cm(Ng|t0?!m2x~6-8;}5UT^#f&IE`G|m7gcSMOT__SoxpvZXlst
zc2i#1ncj19#cmXMQS9VSATfEN8)P`@3p2Cd3%g^62Ta<_`+ImgpMVp%$pZCQEhd-E
z>14-SC?%M^U+kYAKyN>Q2n}kRlN%9+WL)Hrz%`agIHW(<g6I?LEq>B*)xO)!FFeR*
z!b`oSQGY?WVlUY-E1OujJP8W<ql24=JBVbe`je1Tu{0Pr%OCP{@Dhe(2<(WNEC=X}
ziDsGngp-@1laG_-Kh%&l2j!xsh4v81Owr<nl6uq!{ILxiu<bGz(@VV@;$>RX9jfzI
zdUZ&{rrz5`V{FTR3O(2-fO5^qNzig0?<nUAI$Ii>%n`e7!?I0lHJtWTZlf!uR;<)O
zp=9(6W}Oc*2}Qd&H8ke6!{Vu-F9ZfoM`6Vi!%Ut%k_>pV+?#*~ny@rr$4@E3xF97U
z@TB}ly4PrKFO1?gab=@}TE?gi)%=asv!C9fPHAjspxlj$jv0Sy(`RwoIDxSRBjcy;
z|2rg}Lgy1prkBTVhP**Ox9qPq<r0(21Cq=qV%G{d2gCyYWKDbBvCiX^AO~LjsZ8JW
zhfqdag0KG!dEKBYa%oR@T%hFKw-9=&ZHi;?gr+<EOQ?L_5}~m&!`Y~pkFZK$zisEt
zl{Q|D&LG?>Z$v?b^=Ldje}zrECLs6<$zk^=6T6MF(!><<gw{&vG)U~izV)@V)8K=L
zjjtadrp5a_%1GXY!^K_t*2QKa0;?Ctdjz=k3hW&r&H?vFWO{)_fxQQ=g-048n^?|X
z;m!%I$u6KpWJfSGQ({w8#k!Ud*f(Uc3aj<|@F?(R;rNQPQse;j2*M*z-qlcv9W7Sy
zD5{1E-b>QHx(rv4M4<Q)z}QDpoIl0MczF#hHA#g{KWlIy%NE3Ch{ZeyB3nhh#zw0&
zbG$5Vw_3c~MfIKcmNLkROc*eek(>7*$O#Y6b?liO!|*KU)u?=Bu>cm&qBw`pbFpko
zgf_cK|30(;oB&`A?n9BqF*<FtqqY?XN+dUjA3SU8$r=|)92)X7ViK?dlyE26QWK3K
z2ioQ$JUE>LFt`f^P9}RRH=((<j~q>GQ9c+R%b_Xl)t0dc3`>D|?66kuB-4^$bhf-n
z{%|A3Li3H|t2SAsV@f{(5dTShA}Uy5o@$CBjMAl26}v1@9u}|}?nqK=7S5?rzpO||
zViV#?4&1AAz2En1*B0;++Rk}%ReLr$+kvn_GpEO6T&+4n##TiO`Udjq<6@tv(<ERF
z+lvGxJ{r13GdCfrn!A=MuR=2gfz1duc;@IV+E}2HRWP96jvYRi986zK<{$Ig$j21O
z6#uS5Di={L-M)1@ZJlees|Mge7iCRqh3o)Yzn&o(bqO5?W^>aTOrdcmajOv$SGtB_
z+{hC05OBno3J%|?ZL3;8wFv5a#Dbtbtu>$#CNTtxEme-kOD2DjGv;arl-1p>7f3LR
z@R8upbYMrjE?wwy#kb7TBbVS%R0T_fiKavv*<qYC<Gd1w(*jX~<%fGg<WuAEGPS02
zObEI3+?5NSWa8Rmnt;r}>-G()iTw$3Cc!3!`7YZ{LSDHV*HDD3-J!)QM0NbOo@m{Y
z=ib=KF%Si;LPI}<m|Ak!F7^OKvsO3Lx@nL4oaXXVs<-VEANIBE5Cr)azQVihA><N*
zzF%Nw;hP8Th6gdm`-N^q#Lep@NHAA1(BSXhmJWijAw&w-Q_W^LwL3Jnw6PuTK3LlX
zwEVkef45&CrDgCX_b@j}qw+r??B)tSVh+nQ7_E3F*%g0JIjye50F`!MiW7#k!jTP~
zL+K6w1!%7cPOuTMXW}pG<;lO|7|Dr1x#6%aG*Yb|nT^kRo?~eg!*M{RJVQ<3eg%(n
zNM`JiQ$d0Ha&CrA0e19^0obXxnTuYRR5DVsoYp1vIQC07IJ)6a?E=1CvFoWcq9<%-
zbRQHpFIGr)623h#Q-N(#(h`TTe02t+?t$fS);qkdd_*CM;2&wZvh89*0C1-lNdKlA
znhRUS0b1t}8d5O}$q2MXrqh$NeX;oG_~{Ee1YfL`?6tdPZ#YCaxX2TzUUn7$S<52<
z%lg{JeW1hnuV&~`420wP4))IQc1UQrkB*ZZ=-KW__5j%Tz^f$bq~e%QeV8GEBX`@E
zEbTAc-#5{Ih$rcSkcfHNB)W>ueG2>RB^A?7$CBZ9ItE^!h9x>1P>@W{*w=su6G%tj
z-?)Cfas4l{>z_Qh{`rIJ&wNBCke@N+vFJZQ+c&e&j5W)-VOp^H=o3hc$hCWY2|I%U
zWL6WaV-J^Dj^z4Tj0iy}Sg57{YCR>m!TDItrW_(6g`J?)<{`-XI(b$Ip_cGcBPWH^
z0z20NBHg`Z;O;bP_|ae(pn^Hz<t)T!j9G@%$b+u26gnQGz5rzT{<0D=O4`u)UvW;?
z!O0b~c;Q~>;xt6np;3&2Dq4-I;aK;rXNY}C_nrp0>q}wZO2Q%F8BL$~gt12*JAz!u
zZ_W7V@Qz1Jc9$ye5)u!!4pIt!BIlRMECF|T=PBXEzCXUX#n2popG;E1LU+#L*w4)Q
zL{j(yWJOEPKhGgS%a3s`#xD{-b&_;`B5cY*hI=3_%tJzioNck+Pxj!-+P*oh-jt;H
zCM*oaMbxpT6F?8G-`D|hc76DOi4(53F+3QWq*wxzGH|6j4%q5hcusOxM9_AUO5r4T
zeWdoBF_Ev|fTq9d!oEMlp%E;?<OOwDkPNyJ`fD-&(R16`a8M*Mo$nYz045zXy}JbC
zqH(>J#%U!pj9UeEVFnK0>x-4Z3ohJnn%s_)=H93v1l?7C<D4A&TjI@>R$W+fP<`>4
zHIYXoq-|*G4^+gIiY1^%;*pdie?3)Q3L<KMQu3xbY@$@t6#m~y8f?A|O(IC%rbR!P
zMuMtJ_PZR4HL|7w(+OvNi<ZN-Ny$mc@J-W}v1XIf()=&ytI{>v_hqs=K^JE6H#Un|
zE1AO4Ah0-*ZC6<BbqVLC=L}#_c<{o{i{p|52_B#ehr7=S&t>2gf%8N<b;{&(3ux?4
zzhS7{++57AjU!qrz@_2HKM4*P(?W=wUILH>er@cR%{OJ1K-&v<KuPqa;KpwO!Zr%X
z1Rrar7C|D<0&$juL_ml`q5vpQkK5Vq$#x#fLC~QlF@CZwv%Q&6L5ES~^1uH19aCf^
zEFKXmCgNbmc3bnK?iA)~Y6Zxj|K%5ZE6=m1k3awN&mL#bKY8*j`|QaVkDCY}4#!lz
zagH0BfbkH)xX18%GQ&MmOrzOHqth|+N}6%IJV$iSE8^9T=le^1Ivf{q1bkAxsH*yo
z?=QvrQZ`|2en83kmC=jcSV63Z@EGU((F_b=tC$IsWftZwANmIobu{F<oUm?*vM11B
zu>(ZlJNOa&W-DblF6Ai8LtM}Vx<Q`m)!m7pt^#b9q{r?Ao!XBGOSLqg*hIID(xoV~
z;=0+nv@|;~rBn<){LRlI82UVv-f7*q<tb^eQen{giaF9rO+hBH<*4M<eIo1L2!=x$
zImLq}g;RIl*TU4}dNY`-t5@kbU1KgC)pPM%v1>7SxJ)-;`j}vf1Zc%klYX^yxJ9Z=
zG2u9RF709gaZOYDtz;^5vxIwP8pREPyC@-D73iz!c#X4(dJn|yPDqghA%O>=F7Hic
z?(lj_n#N`VM|w7zkc_6HSZM@H`+q$5jQB7D*Kd=1CgRGVjQM94d0@FhT3b!)Oi&X?
zTp}?ipHV3Qi-Ixfup2ni9il|y(zj5Oz$4K<uji;YO*vOn|219TjT<+zBzKx^0iYnM
z3Z_#u<*$X7uc`?&FR3Dcs|z>mW|9W24s!~HV7+E~s1vDPADiwrc1`eYxe?MGt>0dk
zbVns}95K?MzNyhRoA!_b_(j`Dt@;niO`(lM=bz}Hz;gmzy(NDZDEt5S<fh6SR~Gn}
z3;U}HdKF$x^FnX@bIGfDz-}Y`fKQIbxzQjBxI59=(x`>hQiL|76g4{+#S+smS5k(?
z2@cFHNgNu>$ogj{x_0X-*+XMpMO4Wg-RU6DV6<~12Rxbf8Rd?h+m4^r(3ly^dr7>9
ziiqX9o;5USfOux1Qu96+)t+&Zh{#zXMzs(`T6ijF%(#%^W_S{EhBI!v3POYumc*F!
zl@4cTW%glsR+*UzyrG~!yQtvtx!z33O6@ZwZVQ#NjnGquM3Pi{12ni^RG9&`qzJB8
z1yTiuq&0lq$~P-bE^W|PZLvA+jv1r<+7c<_ygEHodyvTk@0ZDt{W}YCGQlnM0jxjb
zB*K+TeyVO80k4?ByoL027&t8ap1e63c)0}_2a@abH*U8(c@2Zz8#A&Czi&$+>ek-H
zn~m3JX%S=XEv|-eZoGk9sh{Z@xV5T(x3LtGjmmAe@v~`Dd@37;XgPK-m)$|MDjIa~
zR&Fi8qZ!25?j>_d2xQFVXffI&q8dAYe+Zxzn?CSLDSt@qk>PxZ_JO@c^Nf*^w5pk&
zy-Bp-Un}puF}(M$`hNM*PB@o9o!aq6a;l-N$VH!I?o^956TFQP(HB@&Y3b|FH#Y8?
zwbc?Y%2UX0D|EwOPe(Jx<JrY-L-+t%UT+Br*Fy>63Z&4*L>$u49aA>?Bvd{av>ur+
zJr7=za~CvVsyVxB8w@yb&~G?iK>_@{iSu^6H<0l_zwv!*m0LZ<MFWSmp7YvKw$T!Q
zA0wJmV)bTgqw>N@xSIL7H$<U03&@-o;}mCX+gpe-9;+UMjUeW6XB>(MGg@Zz>al(5
z^hwzDe`4`*rwg~g`0uNR{+P2xh_U&mL|Bdo+$1qR``;q0#B4koaU6cKlpfaZf6Lrv
zMVpQAzzuLuj*78dEr<yrp@$-@!P$dT+zCmaTG)yZ<zsG>Vt7J1xvmF&5=Hc%r0q%C
z0%6YPJVwJ|RH6h7>_!CdSx78r=VJZuDCF=hIiC7SIq0N@6>zPeFEM`(iYRyBk}TL^
z#Gp@S32(!Cjb~)kCSD(hfY3K?N*JIqKBiBG-@1mdCnni;j}^}?z+ileE4j?e14|mp
zAqkE6kajxl*rEA;i;~5pZ>yotC9Tqr?aD3T!s)|sj*5xPe(iKC3|X(H(p$-J0UVv;
z<<vYO5H2aZU|bPR1~QSM?b(QdjA(kRZOy7}zvaksUa5U3Imp>5KlP4fEaY*%{JSAh
zok5Zz8ite+=(0opa@g!CC|p=@|1~d?|EuBj<51KJ4kunyxRfTSj@`D0nJ~$Jd5(nu
zSz?dRJLpNg&aHp`+&^WGM35#aX|H7>8*tupJJ#X6hL4fVV?0e5Mc}pBoG=5Y;%qWO
zP%`EW6lH=dku1Q}S$A{<=@1yqXE@2l59_i#jrCG5=}t?CNtCa0?9ofY4((-n-m16c
zr3d7hWPZxE#R?u<N#OPx{QEMgF~g}m+GsnW>n+4k2A2`(0GD(COd93{KsfTFpb|Jp
zJGgWiS>VwHfFezp&Pd!){Qx|zlk~3j(g!jz($bX~q~)uRtOm{|n4H-JF_()#L<bxq
zXOK|E({R<Pb18o~q8*)sg;Xwo`)m@{h~+%tMV3(X?N}y3-;(xZT5>_Xfbrm!Y%_C^
zF0m;m^LrrM?o0B~U?48r&O0>`-82s5=V}Hx0*N9QKyxt!QH9cFo(yGD4-qR8-sMq*
z0N)?|&H=%QcvIuP2Gw#SK)r`HR&_yu@jneGW>yc0ASQevZdcXLe+Z+cD)DtS#Pw?)
zF8(hRM!P<qxclJc(U>0%OG)(MHFzWX#c`!w#BU;<&E-u$W2h{nJyDvIpPL-W39@aX
zXd@puypRxJiGx!F0G4CqDN|;~iYEDK;5a&~<l>`3Y}>5yXS!N3qzq4GlFpE}pW)Vg
z=F-KwPxnPAzRXutd<lZDoB36$hrw0+K#^rdtjQPnZPsO@{$B85kcc~u1AduKp(UQ6
z%`HX;&e)U@&;)+nkYc}aL^!UNkf3}=SrQ4L6?_|+#sXM<BnD!NFp^oNnuu3DQ<c;W
z$Zdd=SW&bPckJtUb+e^p#@bGku3*H5k*H>PtA<N)HH63T@a3?Nt6zO1CZ3{6d7{jQ
z`^$3}O$i|(q3A{I5H_L$l%}<T&k{3C@SUoJzH4*DQyY-IpRwj*|Fy1@?&-tdxTQ(T
zJcKt|4_Z27&Y>Ie!gi)E@j>Dsc>i2{`=PXU4`xLn33X&?{OI{_;kJTh1K|YFg6ohQ
z!0Dcqmqslehf|2aRdJp+aRIiU;F{7?LA9WgYPMn@<gWuqv>pLFEEFRG8$fPSy}5o@
zlm<-t18C96RG=$+*-r0(;DGqi))8CAAl{dS+(#~!hqw`Ub=+f5uw-*A9_ARfys+6c
z>nz$6uFwJ?P_dVFsk-pex1tt%Q~YbqNz99=>v7w!Qz$KLQ*8H$`WS027Lfx(&Z=GY
z89O2!Sd^4MQui<9`BaSw@f|ReFJ*Hz7dKfxQlQ{L70oO+ZrBf`+`YkWgSktV6Clps
zE1vuZmKZh(5aSX;Er2K933$m%p)82lJHu5A&fs?a3!ORP?+!gJOo~9?XwqQl5R!6$
ztziMz{?&vR4R})D0XIvZd2_zR4xF+Fez2XFt((T*?#qpV)So2Ig;bqke)L{da-pH?
zW#{^^Ga2B&*Ky!Ofd;4A`k?&eD1y0Wz?l5@_IyJmJI{zZGB|B^I^?K|%Tw95H)Wno
zGfsxZIi{GzfG-gA^)-vMwr9^(dxoIwBQGR{hw09Oc8pQOs#M(Qas;$vtIydB+p!HJ
zX_2xy9bxhcodu;ul79g!FlL?8AO!iW=E_n;TAW$FfkU_$GKsinpj?z?OB(ZU5fIgr
zl&9fOMt@>BF2P*N+3ha%TOBQcq3LBsE(gUMuZ6_Xz1FIUrC8SP!VYmbQ<~zF#E@ls
zpN5>ACga26l{1Zp?I<&%igZG7R=vp16j7aI=H6T*O?2dR+?8b+PNguQ$+b%DsYfh_
ztrv@M;J6_s#$<3(Z07Iho5JD{0w}}?w*KUpCB?Xiw4lY&RvQk))jL0spC)@QYc?|C
zMsF1|#u;khhz>Kyj;yGaV$kyr64OXVU`HiM&W4a)$EGRktJkb#k&A7xsMy(i<<{nQ
ze#jJk2>je~b32-jtROz4dYWo^h}rY@+P34Ftu+@~M*#9#c83MEy#PFJsY3)vu`qy(
zpt3q0#u`WPIOM0=8um|;`HzoqZ3^-QAeS5u7r9-fPDH%rvFakwX&3F?t+nm7TQ3xP
zr=XuBZZ}i$8FHmza|bmT!KTL%;~z>Y)rbUG9<?txqY@0{pR5IKkRSF|tlmmY!Up|<
zxzqLX7p5V!(*_Ym48+9Q1IK#9a?X@Dpu|ejl35%%oi&lD)O1~O9Heh+tc`bY!Nx@~
zURTWDY**zV*D3m?K)XYKB2V!$?O=l6NKS<$jvh{9RZB$gXfj9P%`gP<79<FWHSNy&
zPyxlIkoz<CYr{bh67H=UWB3yZTur;gqyy67A_J&WN+u+Kd;SWuUKm!GuMJu)<7lK}
z8X|;Yfw3h4VY`L&l5jd3jF=z$_FCq7A2@|ZI6Jmf-6?luav2r7lw;WE^sp3Ebw|kc
z3M$MHYu%%D2DFhpp-Q1-(4+F!1uZ+9qj}C6?t&zk{AbdnrT|8h3|^*b8i}{Lwb7(u
zNhgbwNuD$gMNiA^VhJ4#@{dTWB~H<l-sHeOee?J~ld2-Md_q1IiM`#{zb*`Q+CwBi
zdX{Z%Zb3qbJl-}T>JEY2j_<ZbDuWoC(1Y7yg0E%wS6>h%x)ETWOKt%nO}w_O+*_O6
z@L(PH_=9wN!R7_p7c1|*t82@aFD!Vsa({F4_WO6XdYjwG)DS-R`tRS~zJI^BdFRf(
zyLa%v{aah_-)?@2QupuOzI*51t$Vlc4DN2-y?yug`?qiJZ{o51y?yuo<}Li=vn_en
z?QRX^<8SWYeg8IlLp$%|U+?Z6{MKg;ZP#kuX05w@uXFoe7>0ded9>b(P~O`Hym#?$
z``#_qb7=3#xbf>2{%sRpj9sBG2oJvBH@GfntyZJQ8qH9lB>UcOz|^fqOcjKQZ<-**
z7!zD9_IU3ON`Tn+Kv7Z)SR33eZf!edh2o9x@AtM?-e_FK-krg{+j#Q+-CK9}@4c^d
z#P==yyDv0BpLg$~&*CoI7~p@sd$*)q_s#%h-U1C!^6u?Bpv67#+533A{r-J?BfNLF
z?}0C*_wBoPQ5Ssx3xS*NZrv`(nNrqT18uiZ663`4?&kf$0F=IcXTR9GzyJQNJNNG0
z5^CaEg2^qmdiVY|#<_j}?)|Mk{uTH)z_V?IhuHU0q=NU268G58y<+SATlenW-tTV@
zHV3!5i~X>Dhn~Epz2J$=7Nu%)8RNT#IdXN{cz@Pb!Y#{qG{7fZclZ9SO|;Ryeec%b
z&gT8wai)PrceV@27;3pYEt83@_uh4>L-{Wo)+?y!H958V-n(%hg?4<0<ws8L3V?EE
zwYZwKboJMt{^0li_?<s~hoAqt_mgM;{XhMeKm3#5d*>bg`)Bf0|MP$S@BAxbbfaIu
z0CtXJvb6F~zWT|t|NP(n-GBH375VRvDwQAMiB=AJZoU4CKYjLB|MovV{ue)f=N<n0
z!%F@C`-fg%5wl&Z{RgQ1;lKauzj=D?2k-FTpHyo9(|=N{9Wr<P`qLl%BNqK3{`ddj
z@An%&z<>YEU-KD0-+%Xy6PwKU-~IN{gFT$W!0tUig{BpfXzqpRsF37~Ml@(b<(_@%
zgc~~cxIvqp;<C)yp5WyB@7}8%VSfLAe)rFHn2Uy`@4vGpj2QU-yC0I*zW?q=+RkZt
Gn*YD>CmzTE

diff --git a/examples/example_framework/instructor/cs102/Report2_handin_5_of_28.token b/examples/example_framework/instructor/cs102/Report2_handin_5_of_28.token
deleted file mode 100644
index cb4ed5d6abfec70f738f205440eba8f73c909f7d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 80005
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
CGTn0k

diff --git a/examples/example_framework/instructor/cs102/__pycache__/deploy.cpython-38.pyc b/examples/example_framework/instructor/cs102/__pycache__/deploy.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4d9b529d6cae3250756694b95ca75ce15b33bf86
GIT binary patch
literal 760
zcmZ`$%Z}496piy}(np30G^)f0fXX5RT_S{#KuBy@0JE_oS;4+-O_MnCgPC?aEZFc5
zu;iDrLSn@)u;Mz^AP~Ziug>wk@jX61&+|!u<J+yGdJzV}cTfHtDUv6+%ts6&5Tp(o
zLJ9FWtivXv(SV~mZW5XdIIc%cO49)+bw)GD-i<#`VETp78RTNL3-t#`fLsMvcoIZF
zL^{muQ;a-?nHVnujFUwmreY>?ak7cT4WAXs>tH$mfog&!>C;!xDQ#B>7Y3~B*hW_Z
z*jm=W^pL~U?M-F3pqcAxRS9Ml<5kl+(}KlpW?I=XA@$2XW2~uU%h>Z}L`RKm<$6!Y
z>h0PYURj_iTmp9%4&$?;IOFEQ{ng>rL;Q?&0$OX1+i&_QW8I!td<%>n(tCwfJ7^DM
z0VrZ$bo*sYCq_BV!S|+_0AmMq%4?`v=DBPuD-~iaz}~#Z7RwWw51otS{Z<;^EueQ?
zEA8>}otE!W?W)*Hfsz>4fOPQ0=*Sn}{eSUaR_WMR&%Hq%=;GQao#1vKD$~auI@_nH
zudN#J{teDE8eRy`{4Qf(1D)d^L-@&_J}l1-Xj59Zh4Pu=uJOK=|7a@V5}&CCa}C&9
u<9QcK?@HMks~xvWmxCGQZ(sZDQKN*b;W5FU<|c+2InIpC!i-GFocscNIOT}|

literal 0
HcmV?d00001

diff --git a/examples/example_framework/instructor/cs102/__pycache__/homework1.cpython-38.pyc b/examples/example_framework/instructor/cs102/__pycache__/homework1.cpython-38.pyc
index aca3c8b22c11ae4d9d824d7ba252b4194f5db12f..d67337369ba5bf909f1eb07c3dda178779750fb2 100644
GIT binary patch
delta 20
acmX@Yc7%;Pl$V!_0SJ18^)_-_G6MiE3<KT(

delta 20
acmX@Yc7%;Pl$V!_0SG=G*4fBy$qWEA<pl8n

diff --git a/examples/example_framework/instructor/cs102/__pycache__/report2_grade.cpython-38.pyc b/examples/example_framework/instructor/cs102/__pycache__/report2_grade.cpython-38.pyc
index 5fb59bc9a735c474aff24e25cd7c318cc0869f8d..42fb3a4a526346eae8494f38ac29d254b5f30b83 100644
GIT binary patch
delta 3461
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

delta 7469
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
Zc=q>4Z<ZtZd4yqb<)!5Z>B&1S{|}U&Ox^$h

diff --git a/examples/example_framework/instructor/cs102/deploy.py b/examples/example_framework/instructor/cs102/deploy.py
index c585908..4e47e5e 100644
--- a/examples/example_framework/instructor/cs102/deploy.py
+++ b/examples/example_framework/instructor/cs102/deploy.py
@@ -2,8 +2,10 @@ from cs102.report2 import Report2
 from unitgrade_private2.hidden_create_files import setup_grade_file_report
 from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
 from snipper.snip_dir import snip_dir
-if __name__ == "__main__":
+import os
+wd = os.path.dirname(__file__)
 
+if __name__ == "__main__":
     gather_upload_to_campusnet(Report2())
     setup_grade_file_report(Report2, minify=False, obfuscate=False, execute=False)
-    snip_dir(source_dir="../cs102", dest_dir="../../students/cs102", clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py'])
+    snip_dir(source_dir=wd+"/../cs102", dest_dir=wd+"/../../students/cs102", clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py'])
diff --git a/examples/example_framework/instructor/cs102/report2.py b/examples/example_framework/instructor/cs102/report2.py
index 381cdb1..c7be1cd 100644
--- a/examples/example_framework/instructor/cs102/report2.py
+++ b/examples/example_framework/instructor/cs102/report2.py
@@ -1,6 +1,7 @@
-from unitgrade2.unitgrade2 import Report
-from unitgrade2.unitgrade_helpers2 import evaluate_report_student
-from unitgrade2.unitgrade2 import UTestCase, cache, hide
+from src.unitgrade2.unitgrade2 import Report
+from src.unitgrade2 import evaluate_report_student
+from src.unitgrade2.unitgrade2 import UTestCase, cache
+
 
 class Week1(UTestCase):
     """ The first question for week 1. """
@@ -8,9 +9,6 @@ class Week1(UTestCase):
         """ Docstring for this method """
         from cs102.homework1 import add
         self.assertEqualC(add(2,2))
-        with self.capture() as out:
-            print("hello world 42")
-        self.assertEqual(out.numbers[0], 42)
         self.assertEqualC(add(-100, 5))
 
     def test_reverse(self):
@@ -18,6 +16,12 @@ class Week1(UTestCase):
         from cs102.homework1 import reverse_list
         self.assertEqualC(reverse_list([1,2,3]))
 
+    def test_output_capture(self):
+        with self.capture() as out:
+            print("hello world 42")                     # Genereate some output (i.e. in a homework script)
+        self.assertEqual(out.numbers[0], 42)            # out.numbers is a list of all numbers generated
+        self.assertEqual(out.output, "hello world 42")  # you can also access the raw output.
+
 
 class Question2(UTestCase):
     """ Second problem """
diff --git a/examples/example_framework/instructor/cs102/report2_grade.py b/examples/example_framework/instructor/cs102/report2_grade.py
index 503237e..eeb50ec 100644
--- a/examples/example_framework/instructor/cs102/report2_grade.py
+++ b/examples/example_framework/instructor/cs102/report2_grade.py
@@ -4,14 +4,10 @@ from tabulate import tabulate
 from datetime import datetime
 import pyfiglet
 import unittest
-
 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: 
@@ -61,53 +57,6 @@ def evaluate_report_student(report, question=None, qitem=None, unmute=None, pass
                                           show_tol_err=show_tol_err)
 
 
-    # try:  # For registering stats.
-    #     import unitgrade_private
-    #     import irlc.lectures
-    #     import xlwings
-    #     from openpyxl import Workbook
-    #     import pandas as pd
-    #     from collections import defaultdict
-    #     dd = defaultdict(lambda: [])
-    #     error_computed = []
-    #     for k1, (q, _) in enumerate(report.questions):
-    #         for k2, item in enumerate(q.items):
-    #             dd['question_index'].append(k1)
-    #             dd['item_index'].append(k2)
-    #             dd['question'].append(q.name)
-    #             dd['item'].append(item.name)
-    #             dd['tol'].append(0 if not hasattr(item, 'tol') else item.tol)
-    #             error_computed.append(0 if not hasattr(item, 'error_computed') else item.error_computed)
-    #
-    #     qstats = report.wdir + "/" + report.name + ".xlsx"
-    #
-    #     if os.path.isfile(qstats):
-    #         d_read = pd.read_excel(qstats).to_dict()
-    #     else:
-    #         d_read = dict()
-    #
-    #     for k in range(1000):
-    #         key = 'run_'+str(k)
-    #         if key in d_read:
-    #             dd[key] = list(d_read['run_0'].values())
-    #         else:
-    #             dd[key] = error_computed
-    #             break
-    #
-    #     workbook = Workbook()
-    #     worksheet = workbook.active
-    #     for col, key in enumerate(dd.keys()):
-    #         worksheet.cell(row=1, column=col+1).value = key
-    #         for row, item in enumerate(dd[key]):
-    #             worksheet.cell(row=row+2, column=col+1).value = item
-    #
-    #     workbook.save(qstats)
-    #     workbook.close()
-    #
-    # except ModuleNotFoundError as e:
-    #     s = 234
-    #     pass
-
     if question is None:
         print("Provisional evaluation")
         tabulate(table_data)
@@ -159,24 +108,20 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         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)
@@ -186,104 +131,28 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         q.possible = 0
         q.obtained = 0
         q_ = {} # Gather score in this class.
-        # unittest.Te
-        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
         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)
-        # res = UTextTestRunner(verbosity=2, resultclass=unittest.TextTestResult).run(suite)
-        z = 234
-        # for j, item in enumerate(q.items):
-        #     if qitem is not None and question is not None and j+1 != qitem:
-        #         continue
-        #
-        #     if q_with_outstanding_init is not None: # check for None bc. this must be called to set titles.
-        #         # if not item.question.has_called_init_:
-        #         start = time.time()
-        #
-        #         cc = None
-        #         if show_progress_bar:
-        #             total_estimated_time = q.estimated_time # Use this. The time is estimated for the q itself.  # sum( [q2.estimated_time for q2 in q_with_outstanding_init] )
-        #             cc = ActiveProgress(t=total_estimated_time, title=q_title_print)
-        #         from unitgrade import Capturing # DON'T REMOVE THIS LINE
-        #         with eval('Capturing')(unmute=unmute):  # Clunky import syntax is required bc. of minify issue.
-        #             try:
-        #                 for q2 in q_with_outstanding_init:
-        #                     q2.init()
-        #                     q2.has_called_init_ = True
-        #
-        #                 # item.question.init()  # Initialize the question. Useful for sharing resources.
-        #             except Exception as e:
-        #                 if not passall:
-        #                     if not silent:
-        #                         print(" ")
-        #                         print("="*30)
-        #                         print(f"When initializing question {q.title} the initialization code threw an error")
-        #                         print(e)
-        #                         print("The remaining parts of this question will likely fail.")
-        #                         print("="*30)
-        #
-        #         if show_progress_bar:
-        #             cc.terminate()
-        #             sys.stdout.flush()
-        #             print(q_title_print, end="")
-        #
-        #         q_time =np.round(  time.time()-start, 2)
-        #
-        #         print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")
-        #         print("=" * nL)
-        #         q_with_outstanding_init = None
-        #
-        #     # item.question = q # Set the parent question instance for later reference.
-        #     item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)
-        #
-        #     if show_progress_bar:
-        #         cc = ActiveProgress(t=item.estimated_time, title=item_title_print)
-        #     else:
-        #         print(item_title_print + ( '.'*max(0, nL-4-len(ss)) ), end="")
-        #     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)
-        #     if show_progress_bar:
-        #         cc.terminate()
-        #         sys.stdout.flush()
-        #         print(item_title_print + ('.' * max(0, nL - 4 - len(ss))), end="")
-        #
-        #     if not hidden:
-        #         ss = "PASS" if current == possible else "*** FAILED"
-        #         if tsecs >= 0.1:
-        #             ss += " ("+ str(tsecs) + " seconds)"
-        #         print(ss)
-
-        # ws, possible, obtained = upack(q_)
 
         possible = res.testsRun
         obtained = len(res.successes)
 
         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"Question {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) )
@@ -298,15 +167,16 @@ 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") +")")
+    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
 
 
-
-
 from tabulate import tabulate
 from datetime import datetime
 import inspect
@@ -329,7 +199,8 @@ def gather_imports(imp):
     # dn = os.path.dirname(f)
     # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
     # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
-    if m.__class__.__name__ == 'module' and False:
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
         top_package = os.path.dirname(m.__file__)
         module_import = True
     else:
@@ -350,7 +221,7 @@ def gather_imports(imp):
             for file in files:
                 if file.endswith(".py"):
                     fpath = os.path.join(root, file)
-                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
                     zip.write(fpath, v)
 
     resources['zipfile'] = zip_buffer.getvalue()
@@ -394,14 +265,14 @@ def gather_upload_to_campusnet(report, output_dir=None):
     results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
                                           show_progress_bar=not args.noprogress,
                                           big_header=not args.autolab)
-    print(" ")
-    print("="*n)
-    print("Final evaluation")
-    print(tabulate(table_data))
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
     # also load the source code of missing files...
 
     sources = {}
-
+    print("")
     if not args.autolab:
         if len(report.individual_imports) > 0:
             print("By uploading the .token file, you verify the files:")
@@ -414,12 +285,15 @@ def gather_upload_to_campusnet(report, output_dir=None):
             print("Including files in upload...")
             for k, m in enumerate(report.pack_imports):
                 nimp, top_package = gather_imports(m)
-                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
                 nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
                 nimp['name'] = m.__name__
                 sources[k] = nimp
                 # if len([k for k in nimp if k not in sources]) > 0:
-                print(f"*** {m.__name__}")
+                print(f" * {m.__name__}")
                 # sources = {**sources, **nimp}
     results['sources'] = sources
 
@@ -438,9 +312,9 @@ def gather_upload_to_campusnet(report, output_dir=None):
 
     if not args.autolab:
         print(" ")
-        print("To get credit for your results, please upload the single file: ")
+        print("To get credit for your results, please upload the single unmodified file: ")
         print(">", token)
-        print("To campusnet without any modifications.")
+        # print("To campusnet without any modifications.")
 
         # print("Now time for some autolab fun")
 
@@ -453,8 +327,8 @@ def source_instantiate(name, report1_source, payload):
 
 
 
-report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, unmute=False, **kwargs):\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n            # for item in q.items:\n            #     if q.name not in payloads or item.name not in payloads[q.name]:\n            #         s = f"> Broken resource dictionary submitted to unitgrade for question {q.name} and subquestion {item.name}. Framework will not work."\n            #         if strict:\n            #             raise Exception(s)\n            #         else:\n            #             print(s)\n            #     else:\n            #         item._correct_answer_payload = payloads[q.name][item.name][\'payload\']\n            #         item.estimated_time = payloads[q.name][item.name].get("time", 1)\n            #         q.estimated_time = payloads[q.name].get("time", 1)\n            #         if "precomputed" in payloads[q.name][item.name]: # Consider removing later.\n            #             item._precomputed_payload = payloads[q.name][item.name][\'precomputed\']\n            #         try:\n            #             if "title" in payloads[q.name][item.name]: # can perhaps be removed later.\n            #                 item.title = payloads[q.name][item.name][\'title\']\n            #         except Exception as e: # Cannot set attribute error. The title is a function (and probably should not be).\n            #             pass\n            #             # print("bad", e)\n        # self.payloads = payloads\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\nclass MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n    pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        item_title = item_title.split("\\n")[0]\n\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 2\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    @classmethod\n    def question_title(cls):\n        return cls.__doc__.splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    # def _callSetUp(self):\n    #     # Always run before method is called.\n    #     print("asdf")\n    #     pass\n    # @classmethod\n    # def setUpClass(cls):\n    #     # self._cache_put((self.cache_id(), \'title\'), value)\n    #     cls.reset()\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    # def unique_cache_id(self):\n    #     k0 = self.cache_id()\n    #     # key = ()\n    #     i = 0\n    #     for i in itertools.count():\n    #         # key = k0 + (i,)\n    #         if i not in self._cache_get( (k0, \'assert\') ):\n    #             break\n    #     return i\n    #     return key\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n    #\n    # def _cache2_contains(self, key):\n    #     print("Is this needed?")\n    #     self._ensure_cache_exists()\n    #     return key in self.__class__._cache2\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    # try:  # For registering stats.\n    #     import unitgrade_private\n    #     import irlc.lectures\n    #     import xlwings\n    #     from openpyxl import Workbook\n    #     import pandas as pd\n    #     from collections import defaultdict\n    #     dd = defaultdict(lambda: [])\n    #     error_computed = []\n    #     for k1, (q, _) in enumerate(report.questions):\n    #         for k2, item in enumerate(q.items):\n    #             dd[\'question_index\'].append(k1)\n    #             dd[\'item_index\'].append(k2)\n    #             dd[\'question\'].append(q.name)\n    #             dd[\'item\'].append(item.name)\n    #             dd[\'tol\'].append(0 if not hasattr(item, \'tol\') else item.tol)\n    #             error_computed.append(0 if not hasattr(item, \'error_computed\') else item.error_computed)\n    #\n    #     qstats = report.wdir + "/" + report.name + ".xlsx"\n    #\n    #     if os.path.isfile(qstats):\n    #         d_read = pd.read_excel(qstats).to_dict()\n    #     else:\n    #         d_read = dict()\n    #\n    #     for k in range(1000):\n    #         key = \'run_\'+str(k)\n    #         if key in d_read:\n    #             dd[key] = list(d_read[\'run_0\'].values())\n    #         else:\n    #             dd[key] = error_computed\n    #             break\n    #\n    #     workbook = Workbook()\n    #     worksheet = workbook.active\n    #     for col, key in enumerate(dd.keys()):\n    #         worksheet.cell(row=1, column=col+1).value = key\n    #         for row, item in enumerate(dd[key]):\n    #             worksheet.cell(row=row+2, column=col+1).value = item\n    #\n    #     workbook.save(qstats)\n    #     workbook.close()\n    #\n    # except ModuleNotFoundError as e:\n    #     s = 234\n    #     pass\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n        # res = UTextTestRunner(verbosity=2, resultclass=unittest.TextTestResult).run(suite)\n        z = 234\n        # for j, item in enumerate(q.items):\n        #     if qitem is not None and question is not None and j+1 != qitem:\n        #         continue\n        #\n        #     if q_with_outstanding_init is not None: # check for None bc. this must be called to set titles.\n        #         # if not item.question.has_called_init_:\n        #         start = time.time()\n        #\n        #         cc = None\n        #         if show_progress_bar:\n        #             total_estimated_time = q.estimated_time # Use this. The time is estimated for the q itself.  # sum( [q2.estimated_time for q2 in q_with_outstanding_init] )\n        #             cc = ActiveProgress(t=total_estimated_time, title=q_title_print)\n        #         from unitgrade import Capturing # DON\'T REMOVE THIS LINE\n        #         with eval(\'Capturing\')(unmute=unmute):  # Clunky import syntax is required bc. of minify issue.\n        #             try:\n        #                 for q2 in q_with_outstanding_init:\n        #                     q2.init()\n        #                     q2.has_called_init_ = True\n        #\n        #                 # item.question.init()  # Initialize the question. Useful for sharing resources.\n        #             except Exception as e:\n        #                 if not passall:\n        #                     if not silent:\n        #                         print(" ")\n        #                         print("="*30)\n        #                         print(f"When initializing question {q.title} the initialization code threw an error")\n        #                         print(e)\n        #                         print("The remaining parts of this question will likely fail.")\n        #                         print("="*30)\n        #\n        #         if show_progress_bar:\n        #             cc.terminate()\n        #             sys.stdout.flush()\n        #             print(q_title_print, end="")\n        #\n        #         q_time =np.round(  time.time()-start, 2)\n        #\n        #         print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")\n        #         print("=" * nL)\n        #         q_with_outstanding_init = None\n        #\n        #     # item.question = q # Set the parent question instance for later reference.\n        #     item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)\n        #\n        #     if show_progress_bar:\n        #         cc = ActiveProgress(t=item.estimated_time, title=item_title_print)\n        #     else:\n        #         print(item_title_print + ( \'.\'*max(0, nL-4-len(ss)) ), end="")\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        #     if show_progress_bar:\n        #         cc.terminate()\n        #         sys.stdout.flush()\n        #         print(item_title_print + (\'.\' * max(0, nL - 4 - len(ss))), end="")\n        #\n        #     if not hidden:\n        #         ss = "PASS" if current == possible else "*** FAILED"\n        #         if tsecs >= 0.1:\n        #             ss += " ("+ str(tsecs) + " seconds)"\n        #         print(ss)\n\n        # ws, possible, obtained = upack(q_)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nimport random\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n\n    def test_add(self):\n        """ Docstring for this method """\n        from cs102.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n    def test_reverse(self):\n        """ Reverse a list """  # Add a title to the test.\n        from cs102.homework1 import reverse_list\n        self.assertEqualC(reverse_list([1,2,3]))\n\n\nclass Question2(UTestCase):\n    """ Second problem """\n    @cache\n    def my_reversal(self, ls):\n        # The \'@cache\' decorator ensures the function is not run on the *students* computer\n        # Instead the code is run on the teachers computer and the result is passed on with the\n        # other pre-computed results -- i.e. this function will run regardless of how the student happens to have\n        # implemented reverse_list.\n        from cs102.homework1 import reverse_list\n        return reverse_list(ls)\n\n    def test_reverse_tricky(self):\n        ls = [2,4,8]\n        self.title = f"Reversing a small list containing {ls=}"\n        ls2 = self.my_reversal( tuple(ls) ) # This will always produce the right result.\n        ls3 = self.my_reversal( tuple([1,2,3]) )  # Also works; the cache respects input arguments.\n        self.assertEqualC(self.my_reversal( tuple(ls2) )) # This will actually test the students code.\n\n\nimport cs102\nclass Report2(Report):\n    title = "CS 101 Report 2"\n    questions = [(Week1, 10), (Question2, 8) ]  # Include a single question for 10 credits.\n    pack_imports = [cs102]'
-report1_payload = '8004959a010000000000007d94288c055765656b31947d94288c055765656b31948c08746573745f6164649486948c057469746c659486948c19446f63737472696e6720666f722074686973206d6574686f64946803680486948c066173736572749486947d94284b004b044b014aa1ffffff756803680486948c0474696d6594869447000000000000000068038c0c746573745f72657665727365948694680686948c0e526576657273652061206c69737494680368108694680a86947d944b005d94284b034b024b016573680368108694680e86944700000000000000008c0474696d6594470000000000000000758c095175657374696f6e32947d94288c095175657374696f6e32948c13746573745f726576657273655f747269636b799486948c066173736572749486947d944b005d94284b024b044b086573681d681e86948c057469746c659486948c2e526576657273696e67206120736d616c6c206c69737420636f6e7461696e696e67206c733d5b322c20342c20385d94681d681e86948c0474696d65948694470000000000000000681a473f5066000000000075752e'
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"Question {n+1} total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        """ Docstring for this method """\n        from cs102.homework1 import add\n        self.assertEqualC(add(2,2))\n        with self.capture() as out:\n            print("hello world 42")\n        self.assertEqual(out.numbers[0], 42)\n        self.assertEqualC(add(-100, 5))\n\n    def test_reverse(self):\n        """ Reverse a list """  # Add a title to the test.\n        from cs102.homework1 import reverse_list\n        self.assertEqualC(reverse_list([1,2,3]))\n\n\nclass Question2(UTestCase):\n    """ Second problem """\n    @cache\n    def my_reversal(self, ls):\n        # The \'@cache\' decorator ensures the function is not run on the *students* computer\n        # Instead the code is run on the teachers computer and the result is passed on with the\n        # other pre-computed results -- i.e. this function will run regardless of how the student happens to have\n        # implemented reverse_list.\n        from cs102.homework1 import reverse_list\n        return reverse_list(ls)\n\n    def test_reverse_tricky(self):\n        ls = [2,4,8]\n        self.title = f"Reversing a small list containing {ls=}" # Titles can be set like this at any point in the function body.\n        ls2 = self.my_reversal( tuple(ls) ) # This will always produce the right result.\n        ls3 = self.my_reversal( tuple([1,2,3]) )  # Also works; the cache respects input arguments.\n        self.assertEqualC(self.my_reversal( tuple(ls2) )) # This will actually test the students code.\n\n\nimport cs102\nclass Report2(Report):\n    title = "CS 101 Report 2"\n    questions = [(Week1, 10), (Question2, 8) ]\n    pack_imports = [cs102]'
+report1_payload = '80049510010000000000007d94288c055765656b31947d94288c055765656b31948c08746573745f6164649486948c066173736572749486947d94284b004b044b014aa1ffffff7568038c0c746573745f72657665727365948694680686947d944b005d94284b034b024b0165738c0474696d6594473fe6a7e700000000758c095175657374696f6e32947d94288c095175657374696f6e32948c13746573745f726576657273655f747269636b799486948c057469746c659486948c2e526576657273696e67206120736d616c6c206c69737420636f6e7461696e696e67206c733d5b322c20342c20385d946811681286948c066173736572749486947d944b005d94284b024b044b086573680e473facac280000000075752e'
 name="Report2"
 
 report = source_instantiate(name, report1_source, report1_payload)
diff --git a/examples/example_framework/instructor/cs102/unitgrade/Question2.pkl b/examples/example_framework/instructor/cs102/unitgrade/Question2.pkl
index 634a7fbbe4bad27f24b2d894ef3c0b37c4f5dd94..b950c49faa2b91b7675ee266d63a13fe3652e3cc 100644
GIT binary patch
delta 119
zcmZo*e!;}jz%n&<B8&dS;0<CN8JrnBnvGMu8NHdjncJr%`qfU!5ST2<sO$rm;_zni
zW`ap|aqR0^R{wxw2Ul_1l%)14ZBt^WXaM!Hcypv?FlI2dP3d7vEG|whDgjE>PVr{Q
JP$@3e0|4%EC_MlG

delta 140
zcmaFC)WFQrz%sRTB8$E(TVio>YEj9Qwkfq!ycuGrXm~Suvv_l)7H2SKFikYrEXJF`
zmm#RxIK`V0D8t-7CDE^TN`~mfpUN(984jQhCYVeY$G)Cr^$$39a22;rNoofgoWTw<
Ut8GdTOG##KDp0_k0SZd>0H5?NtpET3

diff --git a/examples/example_framework/instructor/cs102/unitgrade/Week1.pkl b/examples/example_framework/instructor/cs102/unitgrade/Week1.pkl
index 7912698f036128bb2a8b616c2a66c58ac9e774e5..6b4ee502e9c67e2ff3aba1b11c4911bb88195e34 100644
GIT binary patch
delta 35
rcmcc4n99<?GBs)<i^9YJ>50vvg0)k;8Dghscr$x5c{8RKm+Aok$2|&n

delta 146
zcmYej&dAchGWE<v76nb#lFX8v)G2LKdL&))lZ#7=GV{_E((;QGN-{Ew6>?KcGV)WV
zWH4qhO;nT<%U}YkV=2kZ1!-_+fP#s(;`Tj!L8)b_Ma8KKi3&NH#U&sud~H)QINGMv
aPVr`louc8*?9JrOm|6^#;6XB=R1W|>sV&3+

diff --git a/examples/example_framework/students/cs102/.coverage b/examples/example_framework/students/cs102/.coverage
new file mode 100644
index 0000000000000000000000000000000000000000..a93b4d7e94a84f8ad080beeafaa98b3784e23e91
GIT binary patch
literal 53248
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

literal 0
HcmV?d00001

diff --git a/examples/example_framework/students/cs102/Report2_handin_0_of_18.token b/examples/example_framework/students/cs102/Report2_handin_0_of_18.token
deleted file mode 100644
index 63734376c0eae1c4df3121a0c656e90452e80cba..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/examples/example_framework/students/cs102/__pycache__/deploy.cpython-38.pyc b/examples/example_framework/students/cs102/__pycache__/deploy.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4d9b529d6cae3250756694b95ca75ce15b33bf86
GIT binary patch
literal 760
zcmZ`$%Z}496piy}(np30G^)f0fXX5RT_S{#KuBy@0JE_oS;4+-O_MnCgPC?aEZFc5
zu;iDrLSn@)u;Mz^AP~Ziug>wk@jX61&+|!u<J+yGdJzV}cTfHtDUv6+%ts6&5Tp(o
zLJ9FWtivXv(SV~mZW5XdIIc%cO49)+bw)GD-i<#`VETp78RTNL3-t#`fLsMvcoIZF
zL^{muQ;a-?nHVnujFUwmreY>?ak7cT4WAXs>tH$mfog&!>C;!xDQ#B>7Y3~B*hW_Z
z*jm=W^pL~U?M-F3pqcAxRS9Ml<5kl+(}KlpW?I=XA@$2XW2~uU%h>Z}L`RKm<$6!Y
z>h0PYURj_iTmp9%4&$?;IOFEQ{ng>rL;Q?&0$OX1+i&_QW8I!td<%>n(tCwfJ7^DM
z0VrZ$bo*sYCq_BV!S|+_0AmMq%4?`v=DBPuD-~iaz}~#Z7RwWw51otS{Z<;^EueQ?
zEA8>}otE!W?W)*Hfsz>4fOPQ0=*Sn}{eSUaR_WMR&%Hq%=;GQao#1vKD$~auI@_nH
zudN#J{teDE8eRy`{4Qf(1D)d^L-@&_J}l1-Xj59Zh4Pu=uJOK=|7a@V5}&CCa}C&9
u<9QcK?@HMks~xvWmxCGQZ(sZDQKN*b;W5FU<|c+2InIpC!i-GFocscNIOT}|

literal 0
HcmV?d00001

diff --git a/examples/example_framework/students/cs102/__pycache__/homework1.cpython-38.pyc b/examples/example_framework/students/cs102/__pycache__/homework1.cpython-38.pyc
index a099ef9f65bf987d85152d20d4dad941ae1d27bc..d67337369ba5bf909f1eb07c3dda178779750fb2 100644
GIT binary patch
delta 398
zcmYjLJx{|x47D#`M`*i%U}1oPAp^`HAqKt{Bo<)l5~cA8RkSI(q)4Dh9m2?hGNKN!
z@jv(#S@{u2OxP&{mh5|eXTRsK;M4D2ce^2QJg@8~7wV<AF+1aqfba?WK#ClG(I|3n
zl|3>Jc?QWRzf!L-R}~^K7Z_kp(-MU@ZiSUXpyf-5Iw^|wUkG+Mk2&)WmjVhbf#;ED
z@$o&}<fzwhz8$H?9S!rM(bn7>n;VL-?~fmZ`v5B{KZE)kPs3rB7j~K!6I-9Ctv&I`
z6&LWV$2D!S^c;dE+XFO%5=vYLF|Xg0*%4WG#-zbP>#-;<(~Xl5$;v|9vAW)OuFl=o
q#L7pb<2XykCXO5L&JMHUpMnV6Rz@F;Co~<I!}d_w(}DK1TE$<OSxc?}

delta 535
zcmZWnKWh|06rVS{x3^hy0gYmlz*xzFiXd1?8a+jYYmzkAoRfWXmm#}5GBYc=Gy&Jn
zDr_lf0v7oSru9>7YvX4~l{c4=LLa<&@BQAt--G#`{OPal4h9(``FQa}zKl-RHjY0~
zglxhPkbh$nzzAcqTt(PB;P$PGF;N`**l+j`cFG$7Mp&wVuocYk&OC0Q;lOZpn+*p?
z^K5h|%g==p&ey0aFLHzGnb_IaPRumnWM%D5DZS2*Wl=1|Tvf_SuTadaDTUux%StD7
zwG4FSysdL@>{HZM1!s}v5H7iq;B(T~q;8cSPZu@tm98RI(a~8ZNZ#o$suEHZ+IjJ~
zTon4`;`^J+hwlU5GH{*MRqnN^#Gb*$_#C?RvGKQQg(GW?9l|6D&CZ`Q8`HAOPwfGW
z(wl=_`wJco0`3AOme{2I3!C@;r`4`=^&(Io+fX^=9mo#$mNT!P9>HBC5kvF!xY(|=
vKl#qxUe}*a(d5&qO(;nyL=T>awg2{~uS$b;p|-**7d}87rD>X^{61U(O4)_n

diff --git a/examples/example_framework/students/cs102/__pycache__/report2.cpython-38.pyc b/examples/example_framework/students/cs102/__pycache__/report2.cpython-38.pyc
index d06f59685aba1b0e7100778b3122129ce8573306..e88ea2f06cb46d8605dea67d9293e601ee149b83 100644
GIT binary patch
delta 1025
zcmZuvT~8B16rI_R?ruNG%7+4i0)c47v|1$bK~0D;`ap<ajD`m`OJ~rv+isbeML~?l
z`f5nCubRlCFUI&AeDfd7KS1K6G4TcOY)uhElRdd}_U<|7-svm%r(3vRC}a`*?C%%-
zFYUr8-fB;m=Wioo5c3TpCN*06vIXZ1vEXc_XPY2mht9GCyhF0UXDNohEX|QzO=BBW
zr`Z;2VGMokPj}kCHhOe0ap1WL4_`^1<B2(a7wz=C(1bw@)%pO<qD8cX9-?jZ!Q9rK
zWC$LD2)i0qjJAzch?cgS%HBgoC;5y^6I(rxX&6RhPa_tRu`89m3*ZpEJ2*JlGoe~2
zTFE}1oRe17Z;F^vX*OBV5Hja;PMNs19{ZuR8gYG<GG5fB!D+b0Z1_~_Q7k?p)(`b>
zo=j;oD}F4Z&|mfFGr!&pX}MG?|1G^W=GQ5NsFi~T7c8!dh?T4S@})|d(PqR%rPSP%
zwxC>iJ|Px}@;m_2^4P^$+>3jY_u9@?#j!yJ1%RT)db@-QlBQt;P|19%#pnhEr*1;@
z#hH_;<8-&}=m$)Bs-5r*fQ=1oJIqR&nbE{FUSB^2B-nNRi+XA;wUBr6995IK`li=0
z_rt;DtMP4R2o%_`k};$y0ufR+0Vk+qSXO5qqchJq@XLD0D+*>hL#6uZWPSfm<_Q*5
zYn$WA4|8^DL|Kd~IHTaK0yR=<#LlVeFlJYfjlm1G8?NqEO|Idrow5tbzCN71&CI`?
zgjWkihy7<U1$4T(v|T#uG2CDfHMlg>+m-pIU#)pTUEMK1*8Mz4sDEX5?=EJFleXv8
z{h;A_#k?FDh#P@;#C$?4rNfeGsxc8(<?dk$HVtGd(MfyE$kM)6k4PNS8(2BJ0C}9p
O{hE8i?X$6K+V~Iu4&`V7

delta 899
zcmZuvJ8#oa6!yJ--6VEvNFPAUt15#9lr|ND0T@6CrbrdASP{m`y+u~+Bpf@1N(c~P
zVnLBtmM%#A27UrFi$^vV1`rENIQK@R6xGr_KIgl~-*+DV<-PLU2d-Py@VWTuLUd*1
zo+PhF=P%vo8aEO<u<vNx<klOFTf!LX0mInl3}dF^ipr}7Rm3a2ig;BJ%&Q59*E$ql
z2wl{M+K>?B8-2J-nxpSKGZf`aJh$*<>jjXNI(<&K!ObDvld0A{&9{p$WX+A=kH_P0
zGP&vN#W}jV;M3B`M6wMG!H*iu;OqCJ;w|00EuKYbKM~<JM5%b%gH9{%W;qPnc@J9c
zY-7FA0@3e5-dOAJmMj-p9!8v3WEmD3jXK0Dmh^X5YZ$;$X&f{@1$PQaJtYdW=#`FQ
z0kI<>6SKuveQU#$8S~S$gCBs67g9_qGGb6>72MdnegrWTnkxIc5-n+xO)5FaQ`XYm
za3UKei^Waz^TWE7oRc(0Y36aB2w27l{Q*v8(upzYWC`&=PqKzIo0E1Fzv`*}Z%<(k
zal5m7rs!Cgw-%(tqBO^(IWCP{juL{i(%Ua{N(d+LLJlO8JHws{B~_--;)k{U@)V*?
zzXJcUpGH`XOJxR?Cj(qq-0Nngsg@Zy{ixju<5aFRJ5+cDDSSMChfO>J5-V94rcvAt
zL*EUS=Lg+5e+&^9jkSFj<Zl`jKkY^kSP*r2FWs*OR`F6%O{zYm>ylkddwh_H8$?zh
T|0ahxWR5WE&3bi4Jd=?>ny|T5

diff --git a/examples/example_framework/students/cs102/__pycache__/report2_grade.cpython-38.pyc b/examples/example_framework/students/cs102/__pycache__/report2_grade.cpython-38.pyc
index cb391caf0c1bf2175df62b4c8789fee08d1961e3..42fb3a4a526346eae8494f38ac29d254b5f30b83 100644
GIT binary patch
delta 4043
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
JkXhs_{|n40T%Z5|

delta 8117
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
B=!XCR

diff --git a/examples/example_framework/students/cs102/report2.py b/examples/example_framework/students/cs102/report2.py
index d84e9c4..e4d6b02 100644
--- a/examples/example_framework/students/cs102/report2.py
+++ b/examples/example_framework/students/cs102/report2.py
@@ -1,18 +1,20 @@
 """
 Example student code. This file is automatically generated from the files in the instructor-directory
 """
-from unitgrade2.unitgrade2 import Report
-from unitgrade2.unitgrade_helpers2 import evaluate_report_student
-from unitgrade2.unitgrade2 import UTestCase, cache, hide
-import random
+from src.unitgrade2.unitgrade2 import Report
+from src.unitgrade2 import evaluate_report_student
+from src.unitgrade2.unitgrade2 import UTestCase, cache
+
 
 class Week1(UTestCase):
     """ The first question for week 1. """
-
     def test_add(self):
         """ Docstring for this method """
         from cs102.homework1 import add
         self.assertEqualC(add(2,2))
+        with self.capture() as out:
+            print("hello world 42")
+        self.assertEqual(out.numbers[0], 42)
         self.assertEqualC(add(-100, 5))
 
     def test_reverse(self):
@@ -34,7 +36,7 @@ class Question2(UTestCase):
 
     def test_reverse_tricky(self):
         ls = [2,4,8]
-        self.title = f"Reversing a small list containing {ls=}"
+        self.title = f"Reversing a small list containing {ls=}" # Titles can be set like this at any point in the function body.
         ls2 = self.my_reversal( tuple(ls) ) # This will always produce the right result.
         ls3 = self.my_reversal( tuple([1,2,3]) )  # Also works; the cache respects input arguments.
         self.assertEqualC(self.my_reversal( tuple(ls2) )) # This will actually test the students code.
@@ -43,7 +45,7 @@ class Question2(UTestCase):
 import cs102
 class Report2(Report):
     title = "CS 101 Report 2"
-    questions = [(Week1, 10), (Question2, 8) ]  # Include a single question for 10 credits.
+    questions = [(Week1, 10), (Question2, 8) ]
     pack_imports = [cs102]
 
 if __name__ == "__main__":
diff --git a/examples/example_framework/students/cs102/report2_grade.py b/examples/example_framework/students/cs102/report2_grade.py
index 1f9a885..e6318de 100644
--- a/examples/example_framework/students/cs102/report2_grade.py
+++ b/examples/example_framework/students/cs102/report2_grade.py
@@ -6,14 +6,10 @@ from tabulate import tabulate
 from datetime import datetime
 import pyfiglet
 import unittest
-
 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: 
@@ -63,53 +59,6 @@ def evaluate_report_student(report, question=None, qitem=None, unmute=None, pass
                                           show_tol_err=show_tol_err)
 
 
-    # try:  # For registering stats.
-    #     import unitgrade_private
-    #     import irlc.lectures
-    #     import xlwings
-    #     from openpyxl import Workbook
-    #     import pandas as pd
-    #     from collections import defaultdict
-    #     dd = defaultdict(lambda: [])
-    #     error_computed = []
-    #     for k1, (q, _) in enumerate(report.questions):
-    #         for k2, item in enumerate(q.items):
-    #             dd['question_index'].append(k1)
-    #             dd['item_index'].append(k2)
-    #             dd['question'].append(q.name)
-    #             dd['item'].append(item.name)
-    #             dd['tol'].append(0 if not hasattr(item, 'tol') else item.tol)
-    #             error_computed.append(0 if not hasattr(item, 'error_computed') else item.error_computed)
-    #
-    #     qstats = report.wdir + "/" + report.name + ".xlsx"
-    #
-    #     if os.path.isfile(qstats):
-    #         d_read = pd.read_excel(qstats).to_dict()
-    #     else:
-    #         d_read = dict()
-    #
-    #     for k in range(1000):
-    #         key = 'run_'+str(k)
-    #         if key in d_read:
-    #             dd[key] = list(d_read['run_0'].values())
-    #         else:
-    #             dd[key] = error_computed
-    #             break
-    #
-    #     workbook = Workbook()
-    #     worksheet = workbook.active
-    #     for col, key in enumerate(dd.keys()):
-    #         worksheet.cell(row=1, column=col+1).value = key
-    #         for row, item in enumerate(dd[key]):
-    #             worksheet.cell(row=row+2, column=col+1).value = item
-    #
-    #     workbook.save(qstats)
-    #     workbook.close()
-    #
-    # except ModuleNotFoundError as e:
-    #     s = 234
-    #     pass
-
     if question is None:
         print("Provisional evaluation")
         tabulate(table_data)
@@ -161,24 +110,20 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         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)
@@ -188,104 +133,28 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         q.possible = 0
         q.obtained = 0
         q_ = {} # Gather score in this class.
-        # unittest.Te
-        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
         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)
-        # res = UTextTestRunner(verbosity=2, resultclass=unittest.TextTestResult).run(suite)
-        z = 234
-        # for j, item in enumerate(q.items):
-        #     if qitem is not None and question is not None and j+1 != qitem:
-        #         continue
-        #
-        #     if q_with_outstanding_init is not None: # check for None bc. this must be called to set titles.
-        #         # if not item.question.has_called_init_:
-        #         start = time.time()
-        #
-        #         cc = None
-        #         if show_progress_bar:
-        #             total_estimated_time = q.estimated_time # Use this. The time is estimated for the q itself.  # sum( [q2.estimated_time for q2 in q_with_outstanding_init] )
-        #             cc = ActiveProgress(t=total_estimated_time, title=q_title_print)
-        #         from unitgrade import Capturing # DON'T REMOVE THIS LINE
-        #         with eval('Capturing')(unmute=unmute):  # Clunky import syntax is required bc. of minify issue.
-        #             try:
-        #                 for q2 in q_with_outstanding_init:
-        #                     q2.init()
-        #                     q2.has_called_init_ = True
-        #
-        #                 # item.question.init()  # Initialize the question. Useful for sharing resources.
-        #             except Exception as e:
-        #                 if not passall:
-        #                     if not silent:
-        #                         print(" ")
-        #                         print("="*30)
-        #                         print(f"When initializing question {q.title} the initialization code threw an error")
-        #                         print(e)
-        #                         print("The remaining parts of this question will likely fail.")
-        #                         print("="*30)
-        #
-        #         if show_progress_bar:
-        #             cc.terminate()
-        #             sys.stdout.flush()
-        #             print(q_title_print, end="")
-        #
-        #         q_time =np.round(  time.time()-start, 2)
-        #
-        #         print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")
-        #         print("=" * nL)
-        #         q_with_outstanding_init = None
-        #
-        #     # item.question = q # Set the parent question instance for later reference.
-        #     item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)
-        #
-        #     if show_progress_bar:
-        #         cc = ActiveProgress(t=item.estimated_time, title=item_title_print)
-        #     else:
-        #         print(item_title_print + ( '.'*max(0, nL-4-len(ss)) ), end="")
-        #     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)
-        #     if show_progress_bar:
-        #         cc.terminate()
-        #         sys.stdout.flush()
-        #         print(item_title_print + ('.' * max(0, nL - 4 - len(ss))), end="")
-        #
-        #     if not hidden:
-        #         ss = "PASS" if current == possible else "*** FAILED"
-        #         if tsecs >= 0.1:
-        #             ss += " ("+ str(tsecs) + " seconds)"
-        #         print(ss)
-
-        # ws, possible, obtained = upack(q_)
 
         possible = res.testsRun
         obtained = len(res.successes)
 
         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"Question {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) )
@@ -300,15 +169,16 @@ 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") +")")
+    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
 
 
-
-
 from tabulate import tabulate
 from datetime import datetime
 import inspect
@@ -331,7 +201,8 @@ def gather_imports(imp):
     # dn = os.path.dirname(f)
     # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
     # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
-    if m.__class__.__name__ == 'module' and False:
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
         top_package = os.path.dirname(m.__file__)
         module_import = True
     else:
@@ -352,7 +223,7 @@ def gather_imports(imp):
             for file in files:
                 if file.endswith(".py"):
                     fpath = os.path.join(root, file)
-                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
                     zip.write(fpath, v)
 
     resources['zipfile'] = zip_buffer.getvalue()
@@ -396,14 +267,14 @@ def gather_upload_to_campusnet(report, output_dir=None):
     results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
                                           show_progress_bar=not args.noprogress,
                                           big_header=not args.autolab)
-    print(" ")
-    print("="*n)
-    print("Final evaluation")
-    print(tabulate(table_data))
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
     # also load the source code of missing files...
 
     sources = {}
-
+    print("")
     if not args.autolab:
         if len(report.individual_imports) > 0:
             print("By uploading the .token file, you verify the files:")
@@ -416,12 +287,15 @@ def gather_upload_to_campusnet(report, output_dir=None):
             print("Including files in upload...")
             for k, m in enumerate(report.pack_imports):
                 nimp, top_package = gather_imports(m)
-                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
                 nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
                 nimp['name'] = m.__name__
                 sources[k] = nimp
                 # if len([k for k in nimp if k not in sources]) > 0:
-                print(f"*** {m.__name__}")
+                print(f" * {m.__name__}")
                 # sources = {**sources, **nimp}
     results['sources'] = sources
 
@@ -440,9 +314,9 @@ def gather_upload_to_campusnet(report, output_dir=None):
 
     if not args.autolab:
         print(" ")
-        print("To get credit for your results, please upload the single file: ")
+        print("To get credit for your results, please upload the single unmodified file: ")
         print(">", token)
-        print("To campusnet without any modifications.")
+        # print("To campusnet without any modifications.")
 
         # print("Now time for some autolab fun")
 
@@ -455,8 +329,8 @@ def source_instantiate(name, report1_source, payload):
 
 
 
-report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, unmute=False, **kwargs):\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n            # for item in q.items:\n            #     if q.name not in payloads or item.name not in payloads[q.name]:\n            #         s = f"> Broken resource dictionary submitted to unitgrade for question {q.name} and subquestion {item.name}. Framework will not work."\n            #         if strict:\n            #             raise Exception(s)\n            #         else:\n            #             print(s)\n            #     else:\n            #         item._correct_answer_payload = payloads[q.name][item.name][\'payload\']\n            #         item.estimated_time = payloads[q.name][item.name].get("time", 1)\n            #         q.estimated_time = payloads[q.name].get("time", 1)\n            #         if "precomputed" in payloads[q.name][item.name]: # Consider removing later.\n            #             item._precomputed_payload = payloads[q.name][item.name][\'precomputed\']\n            #         try:\n            #             if "title" in payloads[q.name][item.name]: # can perhaps be removed later.\n            #                 item.title = payloads[q.name][item.name][\'title\']\n            #         except Exception as e: # Cannot set attribute error. The title is a function (and probably should not be).\n            #             pass\n            #             # print("bad", e)\n        # self.payloads = payloads\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\nclass MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n    pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        item_title = item_title.split("\\n")[0]\n\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 2\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    @classmethod\n    def question_title(cls):\n        return cls.__doc__.splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    # def _callSetUp(self):\n    #     # Always run before method is called.\n    #     print("asdf")\n    #     pass\n    # @classmethod\n    # def setUpClass(cls):\n    #     # self._cache_put((self.cache_id(), \'title\'), value)\n    #     cls.reset()\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    # def unique_cache_id(self):\n    #     k0 = self.cache_id()\n    #     # key = ()\n    #     i = 0\n    #     for i in itertools.count():\n    #         # key = k0 + (i,)\n    #         if i not in self._cache_get( (k0, \'assert\') ):\n    #             break\n    #     return i\n    #     return key\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n    #\n    # def _cache2_contains(self, key):\n    #     print("Is this needed?")\n    #     self._ensure_cache_exists()\n    #     return key in self.__class__._cache2\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    # try:  # For registering stats.\n    #     import unitgrade_private\n    #     import irlc.lectures\n    #     import xlwings\n    #     from openpyxl import Workbook\n    #     import pandas as pd\n    #     from collections import defaultdict\n    #     dd = defaultdict(lambda: [])\n    #     error_computed = []\n    #     for k1, (q, _) in enumerate(report.questions):\n    #         for k2, item in enumerate(q.items):\n    #             dd[\'question_index\'].append(k1)\n    #             dd[\'item_index\'].append(k2)\n    #             dd[\'question\'].append(q.name)\n    #             dd[\'item\'].append(item.name)\n    #             dd[\'tol\'].append(0 if not hasattr(item, \'tol\') else item.tol)\n    #             error_computed.append(0 if not hasattr(item, \'error_computed\') else item.error_computed)\n    #\n    #     qstats = report.wdir + "/" + report.name + ".xlsx"\n    #\n    #     if os.path.isfile(qstats):\n    #         d_read = pd.read_excel(qstats).to_dict()\n    #     else:\n    #         d_read = dict()\n    #\n    #     for k in range(1000):\n    #         key = \'run_\'+str(k)\n    #         if key in d_read:\n    #             dd[key] = list(d_read[\'run_0\'].values())\n    #         else:\n    #             dd[key] = error_computed\n    #             break\n    #\n    #     workbook = Workbook()\n    #     worksheet = workbook.active\n    #     for col, key in enumerate(dd.keys()):\n    #         worksheet.cell(row=1, column=col+1).value = key\n    #         for row, item in enumerate(dd[key]):\n    #             worksheet.cell(row=row+2, column=col+1).value = item\n    #\n    #     workbook.save(qstats)\n    #     workbook.close()\n    #\n    # except ModuleNotFoundError as e:\n    #     s = 234\n    #     pass\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n        # res = UTextTestRunner(verbosity=2, resultclass=unittest.TextTestResult).run(suite)\n        z = 234\n        # for j, item in enumerate(q.items):\n        #     if qitem is not None and question is not None and j+1 != qitem:\n        #         continue\n        #\n        #     if q_with_outstanding_init is not None: # check for None bc. this must be called to set titles.\n        #         # if not item.question.has_called_init_:\n        #         start = time.time()\n        #\n        #         cc = None\n        #         if show_progress_bar:\n        #             total_estimated_time = q.estimated_time # Use this. The time is estimated for the q itself.  # sum( [q2.estimated_time for q2 in q_with_outstanding_init] )\n        #             cc = ActiveProgress(t=total_estimated_time, title=q_title_print)\n        #         from unitgrade import Capturing # DON\'T REMOVE THIS LINE\n        #         with eval(\'Capturing\')(unmute=unmute):  # Clunky import syntax is required bc. of minify issue.\n        #             try:\n        #                 for q2 in q_with_outstanding_init:\n        #                     q2.init()\n        #                     q2.has_called_init_ = True\n        #\n        #                 # item.question.init()  # Initialize the question. Useful for sharing resources.\n        #             except Exception as e:\n        #                 if not passall:\n        #                     if not silent:\n        #                         print(" ")\n        #                         print("="*30)\n        #                         print(f"When initializing question {q.title} the initialization code threw an error")\n        #                         print(e)\n        #                         print("The remaining parts of this question will likely fail.")\n        #                         print("="*30)\n        #\n        #         if show_progress_bar:\n        #             cc.terminate()\n        #             sys.stdout.flush()\n        #             print(q_title_print, end="")\n        #\n        #         q_time =np.round(  time.time()-start, 2)\n        #\n        #         print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")\n        #         print("=" * nL)\n        #         q_with_outstanding_init = None\n        #\n        #     # item.question = q # Set the parent question instance for later reference.\n        #     item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)\n        #\n        #     if show_progress_bar:\n        #         cc = ActiveProgress(t=item.estimated_time, title=item_title_print)\n        #     else:\n        #         print(item_title_print + ( \'.\'*max(0, nL-4-len(ss)) ), end="")\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        #     if show_progress_bar:\n        #         cc.terminate()\n        #         sys.stdout.flush()\n        #         print(item_title_print + (\'.\' * max(0, nL - 4 - len(ss))), end="")\n        #\n        #     if not hidden:\n        #         ss = "PASS" if current == possible else "*** FAILED"\n        #         if tsecs >= 0.1:\n        #             ss += " ("+ str(tsecs) + " seconds)"\n        #         print(ss)\n\n        # ws, possible, obtained = upack(q_)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nimport random\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n\n    def test_add(self):\n        """ Docstring for this method """\n        from cs102.homework1 import add\n        self.assertEqualC(add(2,2))\n        self.assertEqualC(add(-100, 5))\n\n    def test_reverse(self):\n        """ Reverse a list """  # Add a title to the test.\n        from cs102.homework1 import reverse_list\n        self.assertEqualC(reverse_list([1,2,3]))\n\n\nclass Question2(UTestCase):\n    """ Second problem """\n    @cache\n    def my_reversal(self, ls):\n        # The \'@cache\' decorator ensures the function is not run on the *students* computer\n        # Instead the code is run on the teachers computer and the result is passed on with the\n        # other pre-computed results -- i.e. this function will run regardless of how the student happens to have\n        # implemented reverse_list.\n        from cs102.homework1 import reverse_list\n        return reverse_list(ls)\n\n    def test_reverse_tricky(self):\n        ls = [2,4,8]\n        self.title = f"Reversing a small list containing {ls=}"\n        ls2 = self.my_reversal( tuple(ls) ) # This will always produce the right result.\n        ls3 = self.my_reversal( tuple([1,2,3]) )  # Also works; the cache respects input arguments.\n        self.assertEqualC(self.my_reversal( tuple(ls2) )) # This will actually test the students code.\n\n\nimport cs102\nclass Report2(Report):\n    title = "CS 101 Report 2"\n    questions = [(Week1, 10), (Question2, 8) ]  # Include a single question for 10 credits.\n    pack_imports = [cs102]'
-report1_payload = '8004959a010000000000007d94288c055765656b31947d94288c055765656b31948c08746573745f6164649486948c057469746c659486948c19446f63737472696e6720666f722074686973206d6574686f64946803680486948c066173736572749486947d94284b004b044b014aa1ffffff756803680486948c0474696d6594869447000000000000000068038c0c746573745f72657665727365948694680686948c0e526576657273652061206c69737494680368108694680a86947d944b005d94284b034b024b016573680368108694680e86944700000000000000008c0474696d6594470000000000000000758c095175657374696f6e32947d94288c095175657374696f6e32948c13746573745f726576657273655f747269636b799486948c066173736572749486947d944b005d94284b024b044b086573681d681e86948c057469746c659486948c2e526576657273696e67206120736d616c6c206c69737420636f6e7461696e696e67206c733d5b322c20342c20385d94681d681e86948c0474696d65948694470000000000000000681a473f5066000000000075752e'
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"Question {n+1} total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\n\nclass Week1(UTestCase):\n    """ The first question for week 1. """\n    def test_add(self):\n        """ Docstring for this method """\n        from cs102.homework1 import add\n        self.assertEqualC(add(2,2))\n        with self.capture() as out:\n            print("hello world 42")\n        self.assertEqual(out.numbers[0], 42)\n        self.assertEqualC(add(-100, 5))\n\n    def test_reverse(self):\n        """ Reverse a list """  # Add a title to the test.\n        from cs102.homework1 import reverse_list\n        self.assertEqualC(reverse_list([1,2,3]))\n\n\nclass Question2(UTestCase):\n    """ Second problem """\n    @cache\n    def my_reversal(self, ls):\n        # The \'@cache\' decorator ensures the function is not run on the *students* computer\n        # Instead the code is run on the teachers computer and the result is passed on with the\n        # other pre-computed results -- i.e. this function will run regardless of how the student happens to have\n        # implemented reverse_list.\n        from cs102.homework1 import reverse_list\n        return reverse_list(ls)\n\n    def test_reverse_tricky(self):\n        ls = [2,4,8]\n        self.title = f"Reversing a small list containing {ls=}" # Titles can be set like this at any point in the function body.\n        ls2 = self.my_reversal( tuple(ls) ) # This will always produce the right result.\n        ls3 = self.my_reversal( tuple([1,2,3]) )  # Also works; the cache respects input arguments.\n        self.assertEqualC(self.my_reversal( tuple(ls2) )) # This will actually test the students code.\n\n\nimport cs102\nclass Report2(Report):\n    title = "CS 101 Report 2"\n    questions = [(Week1, 10), (Question2, 8) ]\n    pack_imports = [cs102]'
+report1_payload = '80049510010000000000007d94288c055765656b31947d94288c055765656b31948c08746573745f6164649486948c066173736572749486947d94284b004b044b014aa1ffffff7568038c0c746573745f72657665727365948694680686947d944b005d94284b034b024b0165738c0474696d6594473fe6a7e700000000758c095175657374696f6e32947d94288c095175657374696f6e32948c13746573745f726576657273655f747269636b799486948c057469746c659486948c2e526576657273696e67206120736d616c6c206c69737420636f6e7461696e696e67206c733d5b322c20342c20385d946811681286948c066173736572749486947d944b005d94284b024b044b086573680e473facac280000000075752e'
 name="Report2"
 
 report = source_instantiate(name, report1_source, report1_payload)
diff --git a/examples/example_framework/students/cs102/unitgrade/Question2.pkl b/examples/example_framework/students/cs102/unitgrade/Question2.pkl
index 634a7fbbe4bad27f24b2d894ef3c0b37c4f5dd94..b950c49faa2b91b7675ee266d63a13fe3652e3cc 100644
GIT binary patch
delta 119
zcmZo*e!;}jz%n&<B8&dS;0<CN8JrnBnvGMu8NHdjncJr%`qfU!5ST2<sO$rm;_zni
zW`ap|aqR0^R{wxw2Ul_1l%)14ZBt^WXaM!Hcypv?FlI2dP3d7vEG|whDgjE>PVr{Q
JP$@3e0|4%EC_MlG

delta 140
zcmaFC)WFQrz%sRTB8$E(TVio>YEj9Qwkfq!ycuGrXm~Suvv_l)7H2SKFikYrEXJF`
zmm#RxIK`V0D8t-7CDE^TN`~mfpUN(984jQhCYVeY$G)Cr^$$39a22;rNoofgoWTw<
Ut8GdTOG##KDp0_k0SZd>0H5?NtpET3

diff --git a/examples/example_framework/students/cs102/unitgrade/Week1.pkl b/examples/example_framework/students/cs102/unitgrade/Week1.pkl
index 7912698f036128bb2a8b616c2a66c58ac9e774e5..6b4ee502e9c67e2ff3aba1b11c4911bb88195e34 100644
GIT binary patch
delta 35
rcmcc4n99<?GBs)<i^9YJ>50vvg0)k;8Dghscr$x5c{8RKm+Aok$2|&n

delta 146
zcmYej&dAchGWE<v76nb#lFX8v)G2LKdL&))lZ#7=GV{_E((;QGN-{Ew6>?KcGV)WV
zWH4qhO;nT<%U}YkV=2kZ1!-_+fP#s(;`Tj!L8)b_Ma8KKi3&NH#U&sud~H)QINGMv
aPVr`louc8*?9JrOm|6^#;6XB=R1W|>sV&3+

diff --git a/examples/example_jupyter/instructor/cs105/.coverage b/examples/example_jupyter/instructor/cs105/.coverage
new file mode 100644
index 0000000000000000000000000000000000000000..572452543e2092b38f99ec9afedd779fdc155f29
GIT binary patch
literal 53248
zcmeI)&2QUe90zba_L3%T=AlxeQB{37psZTkG?^;2A`ME{!?a1$#z2$E$Q<WM>n*l3
z+v&>zK{liv5kf*@ci`Uu@gMBSg)5ickU)Y1zsL5Im$uoWNz>HoYc+{uKd&D@&*M0c
z(~oalvqR3Bp6{3;yP%v=R8{$qF-1{w^vKggE*V<U<r{ic2i8Ze=9J})-}1(%%2fJ$
z#rQmb+gO_VF<+YeeQGEB-Q>@id)XH4zybjXKmY;|hy=PfrZR=IXVr&agl4_PL*KNx
zA3x_eZf>sM+GMxZKf1Qb;%)3)j?uET#MYVb?XouaS<`NDX1fjBGDF+lV&OKIp*sO@
zh%+8-qjR1JxE#e7Yc;z;u|mE@Nwj_2G5vjZpYJb50g~K8z8A(DC=qUNxgrERmqcG+
zK5ufLyA}`PQk=6J3%P|yU*<A}>1p*bkLqOl7X3{Q)rL0ot8%4D30a=s5T&pCrfY5U
zV3C=<8d@Heb1#f*>w8Wq^jOPwqiVW=9onAD_#U@9A#WU6!9{^47s4B?4W)HgROoIT
zGs$Z}ryu!<m`U&?a+3<@dXlvtQDjY#qcXc4r%vSeI!;?09EuTV9D1W-j*1(4NoB`A
zHb)%Getm}yrz96gG>+AA?FSv+JNS#NA9FFPhU+adQ3+}R?@p!*7pGN)S|#5L9<=C#
zSIz8%Ui7|32ftRPr>U>sn8+07=hep#qJ|=PYIQpddMnwXM$_9oqUnhJquY(>CBuzG
z^rBXadCjQHh}bMXIMkX4`%Fn<n7-&}%u51NNndMg6NRNRuzJg@54W|b#RQx>2#p0Y
zShM3=qN@a=4wkpWeRGR1Cwt>z;dM78YC7d?y0AGvs_FEaK&{+c&2`VFGlkh%^<g$@
zM#<4iUNS>XNFK=}hEci8;bzeB<v{YhK~l!(kCL*FBzvejOPO?GeRfoJl5n+hvNF-l
z=$XRIjM|NRgcz5^<J3?k#Fl;+IB+5uzxZu4+-8T%E;duai>K0s_h&{GToj>J7SHKN
zH&aoOA7>(chX#G|(1waEw)Bg9mG3X@m@OJj+NSMOm!&Z{J_9fjuwhbQv+i}msQrq!
zQS%h%o_=}b1p4o#J%w6`f>ZaVjDj`!h84HXKny-Xk<~q~#Z5OpB~ZXC0cB+eEXw-u
z$>@WA8o|CuV{4}v6-Ay?#OQvD`kL%kwBk6X+el7R;_MrzN<+TrlOmsZ?4XFONPRJ&
zo_QcmnP{?C3{*1x<u*}>R2{Ps_i}M822$MJ=7*AtPePZ?kcYOznFtaUCTdT+X22|;
z(@r{tE)=!r9er_-YGv^(u97Fj2bu1?nkk$=uXa00AB=~WT0rM=$CSlR-lm4y#(|yv
zW^$dzS^AJO*gS;Y0Ec)R=OD(k_z2cx1sN*&h?83o7x=32uR?!VAOHafKmY;|fB*y_
z009U<00Iy=c><c6QZwTEUpH<m#<#{pqe&}RAOHafKmY;|fB*y_009U<00IygTVP7p
z<_vjf#md{7HgiGTSx{N2l$Ta6F0E8pxx7}nxK?>DpVDThlX>~o<yA-3=epPB{S==S
zH`Yp@1au=rDeP?X(q+%;INS|`65ZGlZuxYdLyc}z+@Tv3N_@|B+ASW)mD;^ddq3oU
z$##R#?^vPdm#m<?vRZ2JcFWtRyCsTu#7+LX@l-LM8h;so8h?ykK?H;V1Rwwb2tWV=
z5P$##AOHafK;ShBOlfnf{Nh2M&}LNey@NKX&8o?l45>+NE-Sxa5cB`q>Aw}@7o$oq
zSReoa2tWV=5P$##AOHafKmY<KNx;%{rF(T_ts2d(SH;|VwKun3Jv6som2>NIMb52P
z`*Z8nXl}i_%lZAvvfbWy>-7|6a^+QI;`6rWhpRM$e@Uf0)EDN_uTo`TmEw!}f9>=?
zit(#)hhDHi00Izz00bZa0SG_<0uX=z1WuGdL+@UF@ny5Tw_aZM2XbYs>wnGCyH{RG
zCjIOG)Fr*EW?%mLAOHXFL^W$v1_BU(00bZa0SG_<0uX=z1R!uwKvOj(FXsPM<3EM|
zus{F;5P$##AOHafKmY;|fB*y_Z~_H1EuW2k|8IPw7(W?L=miS|AOHafKmY;|fB*y_
z009U<00OUGAgk$W_Dzj4V!0HpzLgSrzH?hWmCbf5FP(qyhy7n^PktybU+*QPN5B6!
zo+-w^^#A{#^|oUL0uX=z1Rwwb2tWV=5P$##AOL~mDv+jc6jV)%UQ#Jt&t{|ff91?^
ztq{r$0SG_<0uX=z1Rwwb2tWV=5P-lq0%HCj*Z<>4Aq)f{009U<00Izz00bZa0SG|g
l_zH;M|Ks}q_#Qu$90Cx400bZa0SG_<0uX=z1RyYu!2eEcGLHZN

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/instructor/cs105/Report1Jupyter_handin_18_of_18.token b/examples/example_jupyter/instructor/cs105/Report1Jupyter_handin_18_of_18.token
new file mode 100644
index 0000000000000000000000000000000000000000..cfb09b6ef919a3d4c721651cb236201490461fc4
GIT binary patch
literal 58736
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

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/instructor/cs105/__pycache__/homework1.cpython-38.pyc b/examples/example_jupyter/instructor/cs105/__pycache__/homework1.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..405a1c978c8bf2114f9b470bfd5312fb8f02188f
GIT binary patch
literal 187
zcmWIL<>g`kf`1XZiQ+)|F^Gc<7=auIATDMB5-AM944RC7D;bJF!U*D5g0odjXmM&$
zaZE{RMrw>pesXDUYF<fkOle+bNqSLYN@{#TQD#|UNoq`LMPhD2PHHiX5ua6BP+5{%
z6qA`(TvAk;T#{cDlU!_QU>cK=pPO2qUzBaAS5SG2!zMRBr8Fni4rKFZAZ7pnaIQ1^

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/instructor/cs105/__pycache__/report5.cpython-38.pyc b/examples/example_jupyter/instructor/cs105/__pycache__/report5.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c80ebb8aac0fa657aacc6cb4b52f65783b2e1ec8
GIT binary patch
literal 2312
zcmaJ?OK&4Z5bo}Ic*d`oWfNXnFmDYKR$?g^giwS*NE|HfhG@~qVl;Ml5-0QUcF$yq
zm0NO0;s6&8$uU>{1pi^Kobng;0#!ZnW3kz>rrcH4(_Q^lebonzMwP(x*YDfmpB5p1
zqq6*%pzOh`egnY?rxA&%Ph;jYiaLvo*z`?3HX_Tnz-C0YZ^OR{b1Qx&c6<l?mhXN?
zxXmk9gjWQ+H2f;)4tGI!wO#|g%4?w4L=F6P(CfSbdP7jq8=}dZr%e7TOwqU`mlRet
z_KCM~2eA>474{P`No7{J2R{gv^+F{)TD&37!YB_j5lHO~RF-p*WPSLc+6yOHF2~7H
zw{Yj<7q#a?oOV0o$$2sy;o8g39FY!K1@S2-J`)C~oc%$$!Obi4lKLjMxP3(cj|z9-
z-{uq|bqnh$EWOjerG+g8Y@Lkg(&9LF;qAezJ_3=EOY+M@N-}!Fu8qvRp%)~uo|0Yi
zm^>jrLI(E9E$w@@gyfOJ8OI1fGAx{anu%eWo)%`5hP*Hj$B`&lGK8ItQKW8(d>y`c
z@l)@M!GRJ|4YK@L48BQ6c?{sFL7t4WBN=iLOyu|s;2Vga!*~)2H5&vc`Q$tkaxhL*
zCi792%E3tOZ0`<Apm#fy^P;Lmb};Ehp;CA-h3FCH&}mBp(OI}xfUsev24Wiq7v%aL
z1OS@eFwSnE0AI3#g&Sx^P&~7L$Kbm=-0;o;;h9AZq7X9s_E{cA5^b^tqOjug!#n|C
zOeLa2jY}yWqSwiwmV%J;CTL~+bc;@#W&AVeO7ys|jvg18#d!i{GLMk;r;TF~MQQta
zDkI+RdZv5}CND*1oP|=pgEmaoQc!ihuM}sHIq?8|3J*)@^ubbC_inFJI6;tvu?T{q
z8U%65^9aZFAV4JUJ+%=gDHhpr%H<|*_Xx#%C>Fcx5gtiLi5Myr4rR1uI;OV%KV`Zw
zbw(LZeL%xEh4mlm*rHOB2WaGI+Ej{a|LYm0`w|Oj1@Ad+J^`<$&DM-I7vy9uabyjq
z-cv``VJsUcFwcdP%=lvj$xyzAjs*%D0K^FMwW#UMMU<~9Y-G7E4MYxtBPY-s%3xUG
z27yjQ5J)`9y6o$!eHVAuNoUi>(!R;ib7dR9d>_RJC_YA^SNjl07<l1KWI6#doa@z=
z&bG)fHlQtd6=LI16MmRwMkRVyvW&s(!K>Z`@luw7m(T)DZUQf@!hM_rqsD2{l@*w|
zlF2#maUEn1Kt!(@R>=*!!KRP=Hu@4{lQ_wPyJCsjz4AzJqk9c`bY0^K=A4-a)S1z_
z?^$a>)Rb7%!2&A})<djyF(6hFEh`uqVBEuLn2lwOgvr?<11=bc?1=fmfg`N`60v4^
zukCzaHr(k(Z@&$Fwq2UryLWhpYb5$B$uF#IoJFE+Dj1XRKD)<X74C5w3+O(lJAQo<
zj!uK}{!nYn;WPO7Q+O5bhDWri{f}u#v}1>f!*LP>-iE(9zdO2}#ZY2>NCd!tw6HEF
z1kekiAXQgl>y)3P(4@qhO=3~V4HUX>WBN40diOF_Ytm9UUzXkOE99KQf@#q@b>P=x
OCT%ra^_JDDIL5y&>)6Bq

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/instructor/cs105/__pycache__/week2.cpython-38.pyc b/examples/example_jupyter/instructor/cs105/__pycache__/week2.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d81c0675c7056e7e11ab8b96d289c407997be566
GIT binary patch
literal 466
zcmYjM%}T>S5Z>9%Ut3!c3cYv;cnV6voTUiTYcJv@m(XTbET&D_Cf1hT>I?W7zKjpB
zS5NUNoQV`WFf-rm%zod@W4GHDWaE$P=@;d1E>2BRaYw!$Q9zLhgalBcdKZb*5*>68
z61{;)ly)>600d>l8U4h?09!QaVf#Tuo!$9mIDXS6o3C{k598rYd)Ix|d0vE@!sHmn
znIxH`F=oFfUk4QSVh?>mOfdNrk+d+iFf%}%CfLqK>z8;qUu~B&>n^rW)$)S>Hl$!&
z!ZqWXud4a*`iDZs3`b+k?MAdmpd?uYI#Lc;T1|{cuQks_f1D9m!2dOjLoJqHRQVOb
zqx>1+N#t8UO|i(*)T-C1X_m5HQI)HzwC>8xm!*ZB;o%d?=EjCMxLp)j<$B~ZH81G&
N9SBqp0ti|T`~q1`QnUa7

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/instructor/cs105/deploy.py b/examples/example_jupyter/instructor/cs105/deploy.py
new file mode 100644
index 0000000..8acafa9
--- /dev/null
+++ b/examples/example_jupyter/instructor/cs105/deploy.py
@@ -0,0 +1,15 @@
+from report5 import Report1Jupyter
+from unitgrade_private2.hidden_create_files import setup_grade_file_report
+from snipper import snip_dir
+
+if __name__ == "__main__":
+    setup_grade_file_report(Report1Jupyter, minify=False, obfuscate=False, execute=False)
+
+    # from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
+    # gather_upload_to_campusnet((Report1Flat()))
+
+    # Deploy the files using snipper: https://gitlab.compute.dtu.dk/tuhe/snipper
+    snip_dir.snip_dir(source_dir="", dest_dir="../../students/cs105", clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py'])
+
+
+
diff --git a/examples/example_jupyter/instructor/cs105/homework1.py b/examples/example_jupyter/instructor/cs105/homework1.py
new file mode 100644
index 0000000..b01dcab
--- /dev/null
+++ b/examples/example_jupyter/instructor/cs105/homework1.py
@@ -0,0 +1 @@
+# This file is blank.
diff --git a/examples/example_jupyter/instructor/cs105/report5.py b/examples/example_jupyter/instructor/cs105/report5.py
new file mode 100644
index 0000000..38e9fbd
--- /dev/null
+++ b/examples/example_jupyter/instructor/cs105/report5.py
@@ -0,0 +1,49 @@
+from src.unitgrade2.unitgrade2 import Report,  UTestCase
+from src.unitgrade2 import evaluate_report_student
+import homework1
+import importnb
+from src.unitgrade2.unitgrade2 import Capturing2
+
+file = 'week2.ipynb'
+class Week1(UTestCase):
+    @classmethod
+    def setUpClass(cls) -> None:
+        with Capturing2():
+            cls.nb = importnb.Notebook.load(file)
+
+    def test_add(self):
+        self.assertEqual(Week1.nb.myfun(2,2), 4)
+        self.assertEqual(Week1.nb.myfun(2,4), 8)
+
+    def test_reverse(self):
+        self.assertEqual(Week1.nb.var, "hello world 2")
+
+# Nicer: Automatically load the notebook.
+class NBTestCase(UTestCase):
+    notebook = None
+    _nb = None
+    @classmethod
+    def setUpClass(cls) -> None:
+        with Capturing2():
+            cls._nb = importnb.Notebook.load(cls.notebook)
+
+    @property
+    def nb(self):
+        return self.__class__._nb
+
+class Question2(NBTestCase):
+    notebook = "week2.ipynb"
+    def test_add(self):
+        self.assertEqualC(self.nb.myfun(2,8))
+
+class Report1Jupyter(Report):
+    title = "CS 105 Report 5"
+    questions = [(Week1, 10),
+                 (Question2, 8)
+                 ]  # Include a single question for 10 credits.
+    pack_imports = [homework1]
+
+if __name__ == "__main__":
+    # Uncomment to simply run everything as a unittest:
+    # unittest.main(verbosity=2)
+    evaluate_report_student(Report1Jupyter())
diff --git a/examples/example_jupyter/instructor/cs105/report5_grade.py b/examples/example_jupyter/instructor/cs105/report5_grade.py
new file mode 100644
index 0000000..3e65178
--- /dev/null
+++ b/examples/example_jupyter/instructor/cs105/report5_grade.py
@@ -0,0 +1,336 @@
+
+import numpy as np
+from tabulate import tabulate
+from datetime import datetime
+import pyfiglet
+import unittest
+import inspect
+import os
+import argparse
+import time
+
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
+To run all tests in a report: 
+
+> python assignment1_dp.py
+
+To run only question 2 or question 2.1
+
+> python assignment1_dp.py -q 2
+> python assignment1_dp.py -q 2.1
+
+Note this scripts does not grade your report. To grade your report, use:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
+parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
+parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
+parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
+parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
+
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+    args = parser.parse_args()
+    if question is None and args.q is not None:
+        question = args.q
+        if "." in question:
+            question, qitem = [int(v) for v in question.split(".")]
+        else:
+            question = int(question)
+
+    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
+        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
+
+    if unmute is None:
+        unmute = args.unmute
+    if passall is None:
+        passall = args.passall
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+                                          show_tol_err=show_tol_err)
+
+
+    if question is None:
+        print("Provisional evaluation")
+        tabulate(table_data)
+        table = table_data
+        print(tabulate(table))
+        print(" ")
+
+    fr = inspect.getouterframes(inspect.currentframe())[1].filename
+    gfile = os.path.basename(fr)[:-3] + "_grade.py"
+    if os.path.exists(gfile):
+        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
+        print(">>>", gfile)
+        print("In the same manner as you ran this file.")
+
+
+    return results
+
+
+def upack(q):
+    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
+    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
+    h = np.asarray(h)
+    return h[:,0], h[:,1], h[:,2],
+
+class UnitgradeTextRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+class SequentialTestLoader(unittest.TestLoader):
+    def getTestCaseNames(self, testCaseClass):
+        test_names = super().getTestCaseNames(testCaseClass)
+        # testcase_methods = list(testCaseClass.__dict__.keys())
+        ls = []
+        for C in testCaseClass.mro():
+            if issubclass(C, unittest.TestCase):
+                ls = list(C.__dict__.keys()) + ls
+        testcase_methods = ls
+        test_names.sort(key=testcase_methods.index)
+        return test_names
+
+def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
+                    show_progress_bar=True,
+                    show_tol_err=False,
+                    big_header=True):
+
+    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"
+    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
+    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(s, "(use --help for options)" if show_help_flag else "")
+    # print(f"Loaded answers from: ", report.computed_answers_file, "\n")
+    table_data = []
+    t_start = time.time()
+    score = {}
+    loader = SequentialTestLoader()
+
+    for n, (q, w) in enumerate(report.questions):
+        if question is not None and n+1 != question:
+            continue
+        suite = loader.loadTestsFromTestCase(q)
+        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
+        q_title_print = "Question %i: %s"%(n+1, qtitle)
+        print(q_title_print, end="")
+        q.possible = 0
+        q.obtained = 0
+        q_ = {} # Gather score in this class.
+        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)
+
+        possible = res.testsRun
+        obtained = len(res.successes)
+
+        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun
+
+        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0
+        score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle}
+        q.obtained = obtained
+        q.possible = possible
+
+        s1 = f" * q{n+1}) Total"
+        s2 = f" {q.obtained}/{w}"
+        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )
+        print(" ")
+        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])
+
+    ws, possible, obtained = upack(score)
+    possible = int( msum(possible) )
+    obtained = int( msum(obtained) ) # Cast to python int
+    report.possible = possible
+    report.obtained = obtained
+    now = datetime.now()
+    dt_string = now.strftime("%H:%M:%S")
+
+    dt = int(time.time()-t_start)
+    minutes = dt//60
+    seconds = dt - minutes*60
+    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")
+
+    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
+
+
+from tabulate import tabulate
+from datetime import datetime
+import inspect
+import json
+import os
+import bz2
+import pickle
+import os
+
+def bzwrite(json_str, token): # to get around obfuscation issues
+    with getattr(bz2, 'open')(token, "wt") as f:
+        f.write(json_str)
+
+def gather_imports(imp):
+    resources = {}
+    m = imp
+    # for m in pack_imports:
+    # print(f"*** {m.__name__}")
+    f = m.__file__
+    # dn = os.path.dirname(f)
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
+        top_package = os.path.dirname(m.__file__)
+        module_import = True
+    else:
+        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
+        module_import = False
+
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = os.path.dirname(top_package)
+    import zipfile
+    # import strea
+    # zipfile.ZipFile
+    import io
+    # file_like_object = io.BytesIO(my_zip_data)
+    zip_buffer = io.BytesIO()
+    with zipfile.ZipFile(zip_buffer, 'w') as zip:
+        # zip.write()
+        for root, dirs, files in os.walk(top_package):
+            for file in files:
+                if file.endswith(".py"):
+                    fpath = os.path.join(root, file)
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
+                    zip.write(fpath, v)
+
+    resources['zipfile'] = zip_buffer.getvalue()
+    resources['top_package'] = top_package
+    resources['module_import'] = module_import
+    return resources, top_package
+
+    if f.endswith("__init__.py"):
+        for root, dirs, files in os.walk(os.path.dirname(f)):
+            for file in files:
+                if file.endswith(".py"):
+                    # print(file)
+                    # print()
+                    v = os.path.relpath(os.path.join(root, file), top_package)
+                    with open(os.path.join(root, file), 'r') as ff:
+                        resources[v] = ff.read()
+    else:
+        v = os.path.relpath(f, top_package)
+        with open(f, 'r') as ff:
+            resources[v] = ff.read()
+    return resources
+
+import argparse
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
+parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
+
+def gather_upload_to_campusnet(report, output_dir=None):
+    n = report.nL
+    args = parser.parse_args()
+    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
+                                          show_progress_bar=not args.noprogress,
+                                          big_header=not args.autolab)
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
+    # also load the source code of missing files...
+
+    sources = {}
+    print("")
+    if not args.autolab:
+        if len(report.individual_imports) > 0:
+            print("By uploading the .token file, you verify the files:")
+            for m in report.individual_imports:
+                print(">", m.__file__)
+            print("Are created/modified individually by you in agreement with DTUs exam rules")
+            report.pack_imports += report.individual_imports
+
+        if len(report.pack_imports) > 0:
+            print("Including files in upload...")
+            for k, m in enumerate(report.pack_imports):
+                nimp, top_package = gather_imports(m)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
+                nimp['name'] = m.__name__
+                sources[k] = nimp
+                # if len([k for k in nimp if k not in sources]) > 0:
+                print(f" * {m.__name__}")
+                # sources = {**sources, **nimp}
+    results['sources'] = sources
+
+    if output_dir is None:
+        output_dir = os.getcwd()
+
+    payload_out_base = report.__class__.__name__ + "_handin"
+
+    obtain, possible = results['total']
+    vstring = "_v"+report.version if report.version is not None else ""
+
+    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
+    token = os.path.join(output_dir, token)
+    with open(token, 'wb') as f:
+        pickle.dump(results, f)
+
+    if not args.autolab:
+        print(" ")
+        print("To get credit for your results, please upload the single unmodified file: ")
+        print(">", token)
+        # print("To campusnet without any modifications.")
+
+        # print("Now time for some autolab fun")
+
+def source_instantiate(name, report1_source, payload):
+    eval("exec")(report1_source, globals())
+    pl = pickle.loads(bytes.fromhex(payload))
+    report = eval(name)(payload=pl, strict=True)
+    # report.set_payload(pl)
+    return report
+
+
+
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            # print(self.questions)\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                print("q is", q())\n                q()._cache_put(\'time\', q.time) # = q.time\n                report_cache[q.__qualname__] = q._cache2\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            # self._stdout = sys.stdout\n            # sys._stdout = io.StringIO()\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f" * q{n+1}) Total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nimport homework1\nimport importnb\n\nfile = \'week2.ipynb\'\nclass Week1(UTestCase):\n    @classmethod\n    def setUpClass(cls) -> None:\n        with Capturing2():\n            cls.nb = importnb.Notebook.load(file)\n\n    def test_add(self):\n        self.assertEqual(Week1.nb.myfun(2,2), 4)\n        self.assertEqual(Week1.nb.myfun(2,4), 8)\n\n    def test_reverse(self):\n        self.assertEqual(Week1.nb.var, "hello world 2")\n\n# Nicer: Automatically load the notebook.\nclass NBTestCase(UTestCase):\n    notebook = None\n    _nb = None\n    @classmethod\n    def setUpClass(cls) -> None:\n        with Capturing2():\n            cls._nb = importnb.Notebook.load(cls.notebook)\n\n    @property\n    def nb(self):\n        return self.__class__._nb\n\nclass Question2(NBTestCase):\n    notebook = "week2.ipynb"\n    def test_add(self):\n        self.assertEqualC(self.nb.myfun(2,8))\n\nclass Report1Jupyter(Report):\n    title = "CS 105 Report 5"\n    questions = [(Week1, 10),\n                 (Question2, 8)\n                 ]  # Include a single question for 10 credits.\n    pack_imports = [homework1]'
+report1_payload = '8004955c000000000000007d94288c055765656b31947d948c0474696d6594473fed915600000000738c095175657374696f6e32947d942868048c08746573745f6164649486948c066173736572749486947d944b004b10736803473fcc28f40000000075752e'
+name="Report1Jupyter"
+
+report = source_instantiate(name, report1_source, report1_payload)
+output_dir = os.path.dirname(__file__)
+gather_upload_to_campusnet(report, output_dir)
\ No newline at end of file
diff --git a/examples/example_jupyter/instructor/cs105/unitgrade/Question2.pkl b/examples/example_jupyter/instructor/cs105/unitgrade/Question2.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..b08cef102cf660c34ffd24ee8633b7254630acac
GIT binary patch
literal 58
zcmZo*nX1nK0ku<lI0H*li%T-|^NgnSaFhU<@rfxZQ`)BVuq753rxuj}nYB~A8N3CG
Gi}e5+GZZuc

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/instructor/cs105/unitgrade/Week1.pkl b/examples/example_jupyter/instructor/cs105/unitgrade/Week1.pkl
new file mode 100644
index 0000000..9b6ff7a
--- /dev/null
+++ b/examples/example_jupyter/instructor/cs105/unitgrade/Week1.pkl
@@ -0,0 +1 @@
+€N.
\ No newline at end of file
diff --git a/examples/02471/instructor/02471/week02/week2.ipynb b/examples/example_jupyter/instructor/cs105/week2.ipynb
similarity index 100%
rename from examples/02471/instructor/02471/week02/week2.ipynb
rename to examples/example_jupyter/instructor/cs105/week2.ipynb
diff --git a/examples/example_jupyter/students/cs105/.coverage b/examples/example_jupyter/students/cs105/.coverage
new file mode 100644
index 0000000000000000000000000000000000000000..572452543e2092b38f99ec9afedd779fdc155f29
GIT binary patch
literal 53248
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

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/students/cs105/__pycache__/homework1.cpython-38.pyc b/examples/example_jupyter/students/cs105/__pycache__/homework1.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..405a1c978c8bf2114f9b470bfd5312fb8f02188f
GIT binary patch
literal 187
zcmWIL<>g`kf`1XZiQ+)|F^Gc<7=auIATDMB5-AM944RC7D;bJF!U*D5g0odjXmM&$
zaZE{RMrw>pesXDUYF<fkOle+bNqSLYN@{#TQD#|UNoq`LMPhD2PHHiX5ua6BP+5{%
z6qA`(TvAk;T#{cDlU!_QU>cK=pPO2qUzBaAS5SG2!zMRBr8Fni4rKFZAZ7pnaIQ1^

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/students/cs105/__pycache__/report5.cpython-38.pyc b/examples/example_jupyter/students/cs105/__pycache__/report5.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c80ebb8aac0fa657aacc6cb4b52f65783b2e1ec8
GIT binary patch
literal 2312
zcmaJ?OK&4Z5bo}Ic*d`oWfNXnFmDYKR$?g^giwS*NE|HfhG@~qVl;Ml5-0QUcF$yq
zm0NO0;s6&8$uU>{1pi^Kobng;0#!ZnW3kz>rrcH4(_Q^lebonzMwP(x*YDfmpB5p1
zqq6*%pzOh`egnY?rxA&%Ph;jYiaLvo*z`?3HX_Tnz-C0YZ^OR{b1Qx&c6<l?mhXN?
zxXmk9gjWQ+H2f;)4tGI!wO#|g%4?w4L=F6P(CfSbdP7jq8=}dZr%e7TOwqU`mlRet
z_KCM~2eA>474{P`No7{J2R{gv^+F{)TD&37!YB_j5lHO~RF-p*WPSLc+6yOHF2~7H
zw{Yj<7q#a?oOV0o$$2sy;o8g39FY!K1@S2-J`)C~oc%$$!Obi4lKLjMxP3(cj|z9-
z-{uq|bqnh$EWOjerG+g8Y@Lkg(&9LF;qAezJ_3=EOY+M@N-}!Fu8qvRp%)~uo|0Yi
zm^>jrLI(E9E$w@@gyfOJ8OI1fGAx{anu%eWo)%`5hP*Hj$B`&lGK8ItQKW8(d>y`c
z@l)@M!GRJ|4YK@L48BQ6c?{sFL7t4WBN=iLOyu|s;2Vga!*~)2H5&vc`Q$tkaxhL*
zCi792%E3tOZ0`<Apm#fy^P;Lmb};Ehp;CA-h3FCH&}mBp(OI}xfUsev24Wiq7v%aL
z1OS@eFwSnE0AI3#g&Sx^P&~7L$Kbm=-0;o;;h9AZq7X9s_E{cA5^b^tqOjug!#n|C
zOeLa2jY}yWqSwiwmV%J;CTL~+bc;@#W&AVeO7ys|jvg18#d!i{GLMk;r;TF~MQQta
zDkI+RdZv5}CND*1oP|=pgEmaoQc!ihuM}sHIq?8|3J*)@^ubbC_inFJI6;tvu?T{q
z8U%65^9aZFAV4JUJ+%=gDHhpr%H<|*_Xx#%C>Fcx5gtiLi5Myr4rR1uI;OV%KV`Zw
zbw(LZeL%xEh4mlm*rHOB2WaGI+Ej{a|LYm0`w|Oj1@Ad+J^`<$&DM-I7vy9uabyjq
z-cv``VJsUcFwcdP%=lvj$xyzAjs*%D0K^FMwW#UMMU<~9Y-G7E4MYxtBPY-s%3xUG
z27yjQ5J)`9y6o$!eHVAuNoUi>(!R;ib7dR9d>_RJC_YA^SNjl07<l1KWI6#doa@z=
z&bG)fHlQtd6=LI16MmRwMkRVyvW&s(!K>Z`@luw7m(T)DZUQf@!hM_rqsD2{l@*w|
zlF2#maUEn1Kt!(@R>=*!!KRP=Hu@4{lQ_wPyJCsjz4AzJqk9c`bY0^K=A4-a)S1z_
z?^$a>)Rb7%!2&A})<djyF(6hFEh`uqVBEuLn2lwOgvr?<11=bc?1=fmfg`N`60v4^
zukCzaHr(k(Z@&$Fwq2UryLWhpYb5$B$uF#IoJFE+Dj1XRKD)<X74C5w3+O(lJAQo<
zj!uK}{!nYn;WPO7Q+O5bhDWri{f}u#v}1>f!*LP>-iE(9zdO2}#ZY2>NCd!tw6HEF
z1kekiAXQgl>y)3P(4@qhO=3~V4HUX>WBN40diOF_Ytm9UUzXkOE99KQf@#q@b>P=x
OCT%ra^_JDDIL5y&>)6Bq

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/students/cs105/__pycache__/week2.cpython-38.pyc b/examples/example_jupyter/students/cs105/__pycache__/week2.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d81c0675c7056e7e11ab8b96d289c407997be566
GIT binary patch
literal 466
zcmYjM%}T>S5Z>9%Ut3!c3cYv;cnV6voTUiTYcJv@m(XTbET&D_Cf1hT>I?W7zKjpB
zS5NUNoQV`WFf-rm%zod@W4GHDWaE$P=@;d1E>2BRaYw!$Q9zLhgalBcdKZb*5*>68
z61{;)ly)>600d>l8U4h?09!QaVf#Tuo!$9mIDXS6o3C{k598rYd)Ix|d0vE@!sHmn
znIxH`F=oFfUk4QSVh?>mOfdNrk+d+iFf%}%CfLqK>z8;qUu~B&>n^rW)$)S>Hl$!&
z!ZqWXud4a*`iDZs3`b+k?MAdmpd?uYI#Lc;T1|{cuQks_f1D9m!2dOjLoJqHRQVOb
zqx>1+N#t8UO|i(*)T-C1X_m5HQI)HzwC>8xm!*ZB;o%d?=EjCMxLp)j<$B~ZH81G&
N9SBqp0ti|T`~q1`QnUa7

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/students/cs105/homework1.py b/examples/example_jupyter/students/cs105/homework1.py
new file mode 100644
index 0000000..80562c2
--- /dev/null
+++ b/examples/example_jupyter/students/cs105/homework1.py
@@ -0,0 +1,4 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+# This file is blank.
diff --git a/examples/example_jupyter/students/cs105/report5.py b/examples/example_jupyter/students/cs105/report5.py
new file mode 100644
index 0000000..e91cba1
--- /dev/null
+++ b/examples/example_jupyter/students/cs105/report5.py
@@ -0,0 +1,52 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+from src.unitgrade2.unitgrade2 import Report,  UTestCase
+from src.unitgrade2 import evaluate_report_student
+import homework1
+import importnb
+from src.unitgrade2.unitgrade2 import Capturing2
+
+file = 'week2.ipynb'
+class Week1(UTestCase):
+    @classmethod
+    def setUpClass(cls) -> None:
+        with Capturing2():
+            cls.nb = importnb.Notebook.load(file)
+
+    def test_add(self):
+        self.assertEqual(Week1.nb.myfun(2,2), 4)
+        self.assertEqual(Week1.nb.myfun(2,4), 8)
+
+    def test_reverse(self):
+        self.assertEqual(Week1.nb.var, "hello world 2")
+
+# Nicer: Automatically load the notebook.
+class NBTestCase(UTestCase):
+    notebook = None
+    _nb = None
+    @classmethod
+    def setUpClass(cls) -> None:
+        with Capturing2():
+            cls._nb = importnb.Notebook.load(cls.notebook)
+
+    @property
+    def nb(self):
+        return self.__class__._nb
+
+class Question2(NBTestCase):
+    notebook = "week2.ipynb"
+    def test_add(self):
+        self.assertEqualC(self.nb.myfun(2,8))
+
+class Report1Jupyter(Report):
+    title = "CS 105 Report 5"
+    questions = [(Week1, 10),
+                 (Question2, 8)
+                 ]  # Include a single question for 10 credits.
+    pack_imports = [homework1]
+
+if __name__ == "__main__":
+    # Uncomment to simply run everything as a unittest:
+    # unittest.main(verbosity=2)
+    evaluate_report_student(Report1Jupyter())
diff --git a/examples/example_jupyter/students/cs105/report5_grade.py b/examples/example_jupyter/students/cs105/report5_grade.py
new file mode 100644
index 0000000..b059908
--- /dev/null
+++ b/examples/example_jupyter/students/cs105/report5_grade.py
@@ -0,0 +1,338 @@
+"""
+Example student code. This file is automatically generated from the files in the instructor-directory
+"""
+import numpy as np
+from tabulate import tabulate
+from datetime import datetime
+import pyfiglet
+import unittest
+import inspect
+import os
+import argparse
+import time
+
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
+To run all tests in a report: 
+
+> python assignment1_dp.py
+
+To run only question 2 or question 2.1
+
+> python assignment1_dp.py -q 2
+> python assignment1_dp.py -q 2.1
+
+Note this scripts does not grade your report. To grade your report, use:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
+parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
+parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
+parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
+parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
+
+def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):
+    args = parser.parse_args()
+    if question is None and args.q is not None:
+        question = args.q
+        if "." in question:
+            question, qitem = [int(v) for v in question.split(".")]
+        else:
+            question = int(question)
+
+    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
+        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
+
+    if unmute is None:
+        unmute = args.unmute
+    if passall is None:
+        passall = args.passall
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
+                                          show_tol_err=show_tol_err)
+
+
+    if question is None:
+        print("Provisional evaluation")
+        tabulate(table_data)
+        table = table_data
+        print(tabulate(table))
+        print(" ")
+
+    fr = inspect.getouterframes(inspect.currentframe())[1].filename
+    gfile = os.path.basename(fr)[:-3] + "_grade.py"
+    if os.path.exists(gfile):
+        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
+        print(">>>", gfile)
+        print("In the same manner as you ran this file.")
+
+
+    return results
+
+
+def upack(q):
+    # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
+    h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
+    h = np.asarray(h)
+    return h[:,0], h[:,1], h[:,2],
+
+class UnitgradeTextRunner(unittest.TextTestRunner):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+class SequentialTestLoader(unittest.TestLoader):
+    def getTestCaseNames(self, testCaseClass):
+        test_names = super().getTestCaseNames(testCaseClass)
+        # testcase_methods = list(testCaseClass.__dict__.keys())
+        ls = []
+        for C in testCaseClass.mro():
+            if issubclass(C, unittest.TestCase):
+                ls = list(C.__dict__.keys()) + ls
+        testcase_methods = ls
+        test_names.sort(key=testcase_methods.index)
+        return test_names
+
+def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
+                    show_progress_bar=True,
+                    show_tol_err=False,
+                    big_header=True):
+
+    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"
+    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
+    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(s, "(use --help for options)" if show_help_flag else "")
+    # print(f"Loaded answers from: ", report.computed_answers_file, "\n")
+    table_data = []
+    t_start = time.time()
+    score = {}
+    loader = SequentialTestLoader()
+
+    for n, (q, w) in enumerate(report.questions):
+        if question is not None and n+1 != question:
+            continue
+        suite = loader.loadTestsFromTestCase(q)
+        qtitle = q.question_title() if hasattr(q, 'question_title') else q.__qualname__
+        q_title_print = "Question %i: %s"%(n+1, qtitle)
+        print(q_title_print, end="")
+        q.possible = 0
+        q.obtained = 0
+        q_ = {} # Gather score in this class.
+        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)
+
+        possible = res.testsRun
+        obtained = len(res.successes)
+
+        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun
+
+        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0
+        score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle}
+        q.obtained = obtained
+        q.possible = possible
+
+        s1 = f" * q{n+1}) Total"
+        s2 = f" {q.obtained}/{w}"
+        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )
+        print(" ")
+        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])
+
+    ws, possible, obtained = upack(score)
+    possible = int( msum(possible) )
+    obtained = int( msum(obtained) ) # Cast to python int
+    report.possible = possible
+    report.obtained = obtained
+    now = datetime.now()
+    dt_string = now.strftime("%H:%M:%S")
+
+    dt = int(time.time()-t_start)
+    minutes = dt//60
+    seconds = dt - minutes*60
+    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")
+
+    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
+
+
+from tabulate import tabulate
+from datetime import datetime
+import inspect
+import json
+import os
+import bz2
+import pickle
+import os
+
+def bzwrite(json_str, token): # to get around obfuscation issues
+    with getattr(bz2, 'open')(token, "wt") as f:
+        f.write(json_str)
+
+def gather_imports(imp):
+    resources = {}
+    m = imp
+    # for m in pack_imports:
+    # print(f"*** {m.__name__}")
+    f = m.__file__
+    # dn = os.path.dirname(f)
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
+        top_package = os.path.dirname(m.__file__)
+        module_import = True
+    else:
+        top_package = __import__(m.__name__.split('.')[0]).__path__._path[0]
+        module_import = False
+
+    # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
+    # top_package = os.path.dirname(top_package)
+    import zipfile
+    # import strea
+    # zipfile.ZipFile
+    import io
+    # file_like_object = io.BytesIO(my_zip_data)
+    zip_buffer = io.BytesIO()
+    with zipfile.ZipFile(zip_buffer, 'w') as zip:
+        # zip.write()
+        for root, dirs, files in os.walk(top_package):
+            for file in files:
+                if file.endswith(".py"):
+                    fpath = os.path.join(root, file)
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
+                    zip.write(fpath, v)
+
+    resources['zipfile'] = zip_buffer.getvalue()
+    resources['top_package'] = top_package
+    resources['module_import'] = module_import
+    return resources, top_package
+
+    if f.endswith("__init__.py"):
+        for root, dirs, files in os.walk(os.path.dirname(f)):
+            for file in files:
+                if file.endswith(".py"):
+                    # print(file)
+                    # print()
+                    v = os.path.relpath(os.path.join(root, file), top_package)
+                    with open(os.path.join(root, file), 'r') as ff:
+                        resources[v] = ff.read()
+    else:
+        v = os.path.relpath(f, top_package)
+        with open(f, 'r') as ff:
+            resources[v] = ff.read()
+    return resources
+
+import argparse
+parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Use this script to get the score of your report. Example:
+
+> python report1_grade.py
+
+Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
+For instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
+
+> python -m course_package.report1
+
+see https://docs.python.org/3.9/using/cmdline.html
+""", formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('--noprogress',  action="store_true",  help='Disable progress bars')
+parser.add_argument('--autolab',  action="store_true",  help='Show Autolab results')
+
+def gather_upload_to_campusnet(report, output_dir=None):
+    n = report.nL
+    args = parser.parse_args()
+    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
+                                          show_progress_bar=not args.noprogress,
+                                          big_header=not args.autolab)
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
+    # also load the source code of missing files...
+
+    sources = {}
+    print("")
+    if not args.autolab:
+        if len(report.individual_imports) > 0:
+            print("By uploading the .token file, you verify the files:")
+            for m in report.individual_imports:
+                print(">", m.__file__)
+            print("Are created/modified individually by you in agreement with DTUs exam rules")
+            report.pack_imports += report.individual_imports
+
+        if len(report.pack_imports) > 0:
+            print("Including files in upload...")
+            for k, m in enumerate(report.pack_imports):
+                nimp, top_package = gather_imports(m)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
+                nimp['name'] = m.__name__
+                sources[k] = nimp
+                # if len([k for k in nimp if k not in sources]) > 0:
+                print(f" * {m.__name__}")
+                # sources = {**sources, **nimp}
+    results['sources'] = sources
+
+    if output_dir is None:
+        output_dir = os.getcwd()
+
+    payload_out_base = report.__class__.__name__ + "_handin"
+
+    obtain, possible = results['total']
+    vstring = "_v"+report.version if report.version is not None else ""
+
+    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
+    token = os.path.join(output_dir, token)
+    with open(token, 'wb') as f:
+        pickle.dump(results, f)
+
+    if not args.autolab:
+        print(" ")
+        print("To get credit for your results, please upload the single unmodified file: ")
+        print(">", token)
+        # print("To campusnet without any modifications.")
+
+        # print("Now time for some autolab fun")
+
+def source_instantiate(name, report1_source, payload):
+    eval("exec")(report1_source, globals())
+    pl = pickle.loads(bytes.fromhex(payload))
+    report = eval(name)(payload=pl, strict=True)
+    # report.set_payload(pl)
+    return report
+
+
+
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            # print(self.questions)\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                print("q is", q())\n                q()._cache_put(\'time\', q.time) # = q.time\n                report_cache[q.__qualname__] = q._cache2\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            # self._stdout = sys.stdout\n            # sys._stdout = io.StringIO()\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f" * q{n+1}) Total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nimport homework1\nimport importnb\n\nfile = \'week2.ipynb\'\nclass Week1(UTestCase):\n    @classmethod\n    def setUpClass(cls) -> None:\n        with Capturing2():\n            cls.nb = importnb.Notebook.load(file)\n\n    def test_add(self):\n        self.assertEqual(Week1.nb.myfun(2,2), 4)\n        self.assertEqual(Week1.nb.myfun(2,4), 8)\n\n    def test_reverse(self):\n        self.assertEqual(Week1.nb.var, "hello world 2")\n\n# Nicer: Automatically load the notebook.\nclass NBTestCase(UTestCase):\n    notebook = None\n    _nb = None\n    @classmethod\n    def setUpClass(cls) -> None:\n        with Capturing2():\n            cls._nb = importnb.Notebook.load(cls.notebook)\n\n    @property\n    def nb(self):\n        return self.__class__._nb\n\nclass Question2(NBTestCase):\n    notebook = "week2.ipynb"\n    def test_add(self):\n        self.assertEqualC(self.nb.myfun(2,8))\n\nclass Report1Jupyter(Report):\n    title = "CS 105 Report 5"\n    questions = [(Week1, 10),\n                 (Question2, 8)\n                 ]  # Include a single question for 10 credits.\n    pack_imports = [homework1]'
+report1_payload = '8004955c000000000000007d94288c055765656b31947d948c0474696d6594473fed915600000000738c095175657374696f6e32947d942868048c08746573745f6164649486948c066173736572749486947d944b004b10736803473fcc28f40000000075752e'
+name="Report1Jupyter"
+
+report = source_instantiate(name, report1_source, report1_payload)
+output_dir = os.path.dirname(__file__)
+gather_upload_to_campusnet(report, output_dir)
diff --git a/examples/example_jupyter/students/cs105/unitgrade/Question2.pkl b/examples/example_jupyter/students/cs105/unitgrade/Question2.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..b08cef102cf660c34ffd24ee8633b7254630acac
GIT binary patch
literal 58
zcmZo*nX1nK0ku<lI0H*li%T-|^NgnSaFhU<@rfxZQ`)BVuq753rxuj}nYB~A8N3CG
Gi}e5+GZZuc

literal 0
HcmV?d00001

diff --git a/examples/example_jupyter/students/cs105/unitgrade/Week1.pkl b/examples/example_jupyter/students/cs105/unitgrade/Week1.pkl
new file mode 100644
index 0000000..9b6ff7a
--- /dev/null
+++ b/examples/example_jupyter/students/cs105/unitgrade/Week1.pkl
@@ -0,0 +1 @@
+€N.
\ No newline at end of file
diff --git a/examples/example_jupyter/students/cs105/week2.ipynb b/examples/example_jupyter/students/cs105/week2.ipynb
new file mode 100644
index 0000000..6bc411a
--- /dev/null
+++ b/examples/example_jupyter/students/cs105/week2.ipynb
@@ -0,0 +1,69 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Exercise 2.2.1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "hello world\n",
+      "6\n"
+     ]
+    }
+   ],
+   "source": [
+    "var = \"hello world 2\"\n",
+    "def myfun(a,b):\n",
+    "    return a*b\n",
+    "\n",
+    "output = myfun(2,3) + 10\n",
+    "print(var)\n",
+    "print(output)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "z = 234 \n",
+    "def mymul(d):\n",
+    "    return myfun(d,2)+1"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.6"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/examples/example_simplest/instructor/cs101/Report1_handin_10_of_10.token b/examples/example_simplest/instructor/cs101/Report1_handin_10_of_10.token
index 5d34d0fd91b71eecb9ff050591857b09f382421b..1884f587f74133902500c7b2e2ea1095e067afd8 100644
GIT binary patch
delta 8583
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

literal 77365
zcmeIb&2MB$k{?(-n%)s=QP4mb2+|w|uOpGeU?%zak@eBVZe~|jR#sP{v$DFA*;6wj
z6H&p47i1KJ5y5!DWU_J+*u5;UKpjiivvgnRq{Zr_g8*H15VU`TfYnLBoOgde`*8R7
z;swc^p4Dh~C%P*c@t(W6xw*Nyxw)D7|M2_&?D8G`y!oO1{g3C9d3W@~uipLDyZ_S<
z-~U0sn0JSx@`pD+{OTRP{?P?qegF5Tld>EhjtcoPIYgOp(dUmJ59h@xiv!SbjsoBR
z`0JuL+4|wU{QeKh$@#2TL|}jL-EcY>qR^-R=h~0n`Sq{<-tYgBAo3qy{PEtM@BaP2
z{LjDl&O7|?AK+=P+}hmQ=oiz`<T9UL4rY_nY*tJsv-wswJmuf)nf`q5U3qyv9?p+u
z-G0%T&W10$^I|(c9`^gixYL^z_}O90rPnQs`T4Y?<@utcunkr@9!{slEELAiPJcLi
z?_F!TJU*WfNAJCh2ZOBB8Fx>MPAA*l&03w#DQMH_w07QmH^XO1J8i>#Ejt~Khl9)A
z&%2|tSj#4dgY&WnZ2dv;s_32j&sDZasJF7ugfQ9sxX83$=jCvGlo{eX+3|cnEq69H
zjxZ?Q!@M^+odQhWpP%Rbla2ZLaj{`#4NvQ0&Zq2aTL+I{cUyVBA>+|n%lbt*4-fIY
zoS%cn^D-3Zjf(EL!(zj6cRrlpJ3u_2ouhljtKJC3clTF1o#|z-+dBr`R@SnWJNbNa
zQjGaE4Ef57q`#j}X4&awHn|vQW%mT2dXwp;bpLpAT3k$KC)s==zbBx{3@vp}rx@>C
zyEj1fK{gy``zyd%|8GS)gBga85H^P6ay~on%_lSI&Gv@F-U0^_w}ra>N$;eX)hphs
zR(xT+Ap9VlgYlSNwpVK42h!j7-i;IE-#!21z5noE{?)&Eib=u${$ZFHY1Mu)z|?qI
z%*vuO8kY0+=_UWH?qs)qGSL3FS}pzZ%i+snoOLr6$X2xA3Tn^KXXDbJ_a@^K@5xY;
zfe^I>iLzo;oN}m1M{6&e%=*PF&mQGRM(GM7`&(<<YxiEPX65nZeAKsgvi*B_y!9e$
zcfH9~s~zxEj0DZLf$V#~giP#ox8HAf*A8nP&9sm6i%B*<KRpClvTwTIWZiK;`{wW)
zbZ1y*gY$8Zyy=LQnAoFB#}6DdoMq+tsSVuy&{DRWb?+W#bu{tpCc@xW_UqXMQuH+2
z+R472L3D!R0hNp6VegnNWeMs!YLIB-d3(_M3kXyoS)PyP9GUIxF8<riUXu{pYul@D
zTA&Tt%qu(-w%|Z^v+}e%8VN-)jjO|iL0bD@?V}f~s2;iRUrhgG@1H;Y*Z=lEf%Ev^
z9|rC-LF{rlh~Diyes$rglCCbKlaig|VgzAZZhMX5Wp{K=iLK3aOvD%n5kz_5f3K8w
zXpK}1!kQ?}A&xjgy-~L;Gg+b9{ycw<mk+yTv1-Fj)?$SY$yyepfxnOmjNdtc6tnrG
zv-9q#?X+LZ-Z$beEw;Y3xw)2ou)3D5fBb=PF^h)gtP9sSnfA5qb8OA0l>iRC7jk*W
zZPl^W$Gas9H`u84a4*B6YwK#ZWg_G3oU$Au0Y&!PLc2ATTYbTG=<!%2I@t?cHYzeN
zol)d&ZDv?}`@^}*;c2&b($Pg!zzKFQZZ>y*JH{$T0Ypjf6ZU+Zk;N}DtI6b)CqAw=
znzzD(oJ(^Xr4J|NaDKVFZR53s-+Ya3S7*ic>7VTV>Gyy2@~>JydWZl0qx!5+tpal+
zi~+<D7Aqh(o*EO+yNBl^u()%t|F+kCyqXUoa!udx-vJ^Nq9Ldap0*O+X(6SmM_A3K
zMK2bal%aHYb~No`xd;!+%lMKFhZpl>C{KOT_Ey%Pj92E4(sOx{9rkicBGqEDVOgFR
z5aou{{H%W(>h&j?=xOpWEpS-$y60sP!K@1y_C%1JQRo`N`GeWfIeFmMM1R(Xn$epL
zr)1CFl}9EwvP%_{R1$M6+r@M^njGyyXg^Y|U?+R;-RF~R2Iiqi<Xo3UtqZZpN__v`
zyZ5sx*a~X|X8Z7H%vQHL{izIWs6QEF*$6zpjrB13m2X`QCtE+uwy$bP3MiDP6L5>H
zUE1Rk!vS@6Jeg;r#a23<p?3>U*D_EUlOkzQyStTe?0fHi4z+DGx?Ce@w%Emx4^rqD
z<qQKOD^NE(o%GK!?c1E$-J=4sjSDUHQU#tVy7+Z=KE%=$stRPQwI&tTPqT>(rN|B=
z{%Q9zJ1mI$;Cuwuq9RB=tvl{P3j}6KQ`Cfs9rTmWCOzR3=%ru=C`Q)OhGKQELyZ^{
zsK9V4%HLEAenUWAXMq&Yan?KTj*p5AdM)PHWClHSlC8uRRo4J_Rf&!6Rh!6-{2Y?9
zD1y!orLqKC<h^_{JKDIHf4m{;{YLM!Kf=x{Kc1gr_W_1pBdJciSl?zHS=)BQOnKJ5
zcwW4ke}TmnG}AH=csiwWtXdru6&kfy*3U3a#`s<CuKWUD=a<uB7rHRj{XrMn#_rR}
z806+ky}R-idESL4=nq1L8PG1E3GN8ruC6R?ZXNpIMe&N_spzA<tSj2sZmR@2iw>0V
z0$sD__E1(v*(+dISc3FaC#eZt(~NC>Zr)6HTwY)YAwr}#=@%F^**uk3G;}^b#rEn(
zJ&Ed@DrtG1ud<0#%o|}{ws}QUQ-~u>(CgZIa6X@4(1$%vW=uM$Jwevx*>7b!Wf#ZT
z4D^e`^P?k(_?)f2_b&AjAKjV?234H$aV?Cu@x>Xf0QOx;VLuF6`vob=;XQ?XM{}|v
z_kAuIqBEb2I>l_J&s;kpS7HS)zLh`Z+_G(}H$*_-K5!x#RYVZW<Y%14l#zUF3ITPl
zP(zj$lvA~tuK=%=w<trrP*N|g3o5YN)QYH`zg!iu^)juQm($U3-Uhr?C^@XmPl2ue
z5|{u+Sl+UX2de<7<8Fz0J_|$8a>ni`!wNZDtI~J&cmf&Hoge4Jl48-Sxgh|PU%0%K
zTCq~Y2ql=#x<jnfk6!f(5!3C~{p`_fHks{Y&mr%pvtr$G0v0lf*feIc<I+7WiPP1{
ztYxjRv=y(g56!cO$3^c%XQWADkO^zR2s#v&e(rjdyr7fvAIH5m=JvuyTz`dH#;6U|
z{EgMKpWdL(<`N>ai;Z0eidq+ASerg!%zRvT{mU9Rpck-MO^yJm>>PGyyBs{l&NysW
z_-rjx%{7>Yd~Vra1LZ=J3qhHua@Gp?5XA!iWKCP$wZ<dEk^`^)RHkqGLq<j+-OA>(
z%N=eSxQ5S)BMfbUjV-KJ^KRH7+>(Y8t+ry*b4V;?Wrnj+FCSqgIR^zB-oF}MppD8K
z(L*QGVm!TkHF7v#!vb_TnVd9$m_jsjYXRj2+e)^rSPGopWW?5GgJdY#qS+r(`;Nu2
zv)}avmG9c4?&)E_yOZtH(iO`=1WvG=>#D;#`zAcBRZ#C_Yb|S^t!156ikku(jADj8
zgHJ4HuhNC6)?^dV7qXLWXigMemAYp+pEXorwSIqp#i4eF<9_jK<wf3wk#yW|pKMjo
zXK{X5g%B5t`@Sn8<;A^)2>UFjarH|0u`pY^x;$2xSbURWm9x!7E9=9`$3m+jrG-i`
zO^zB7sE(6UV;R(H=}H6DSKe025@#|+zzVtm=NHgDVf<-rwD7MzBcb>#e>Ey!+1~wD
z3Ix4%L2QeHf?Z^iKGyv%Id9sBlG^QeV7M(tZ7U9fz@`iSbxdWrlT|GaYyea#pCTpv
zNJgAdr*6YSvbl)QNpT5eR-jUMR_;PCZJ$({X8Y(IO97C!Y0Fkb#dr*bUI3QZNwws@
zz}*C2aQ|39u~-1!*taUc>KLXyWI28gK}nY`>3f=<DR_XD%b+S{S)e>FiaAPn;hY-t
zOYGALSvyHeLKv+%9imj|_j7cc9b2GEfSqH2NA20<Vi%$XV9rm+yZCc=YgNgDwgDq;
zk1exJ)M*kYnEs^oVw0@b&@8~*g<NWGnlsbdPEiQdD7!BUXV1n0z0ssB0$IHX*?Kz9
zzLY)e)5-kv$@#edh~k&R-jy^ZFO|^kd+&Qy_JS*~D+1s@mtIXugcxvJF#o<BmRKsf
zBi9j3eIYo0+z`}``h;<#y~Pf9H&Hee9lq1uM76$ia(v&)qOvrgWyP#S`B5>SU<)&o
z(~z?5k9+5{84Mrt6#TQl^&+QEM_HpyAIYYBH%OL47*hGRJ(#WT@2uZ@L6H;;3?`Nm
zNhBIx*%mO)D+#(7l){Y<-0YPQ)-MZ@+LxFRhXpn;u1XaBJUbZEuw%MKrQ%wK{XUQr
zvk#31M102$=1G(H@85^YstDD|+j=~ft*D%bV8=GbMiHEXy&~n8?u7{#3O^Y`tJ_(I
zsfzlXo2+x{vh6eP^{wm}<AEd6_I`V~zjCqi0@G@L#gAU?rysuJbWCR7kRtCah%VP8
z0P1&vqKFfp@f6nX?rhe*Y#$pZT7QoBch)w6BmZvM-|ZJ`?4O$1f9of*v_m{QC$Una
z`>Qz(@A}+nK(ch8FbwCNj@ZH1vO82{@#oIT1;2So4p@1PbA$G39%|IfMqKt_egYp4
zyCXLGWP)?z3Nrr8!4nZo2^Qwjz*BH^X$a9=$Y&3Emf+=y4qwPwFhzyqwg9ABJu(>7
zW7O{faObpu?FYsHTc#>C&{?jfosNt22w}t;t}7BDO6P~<k1B-I*`%G~&7zo*w7MS3
z$h9BBR%oXt3#TJ2?H_4TmePj{cwyd;OzURxrq0z~EA8?U7KS#Kj@^2dT=dRF92z6C
zoYv)dbL6hwf2lbuHCy;@$`0addoA6jg}s#(l8uh*>1N5WJycqPR<q7v)IG9O@R9;_
zZsp_fIZ^pnAXj#Ua)5qC;fn19lQ4zm-w%gJIBX;93nt_NEjWgS4O<gCb;$A4mrC$O
ztd*Dox@B)T#CBCAAoN5#kHF%<V~Gwp55}i<iz48cbjlD*B|43*{p2(ix`$}Ebuez_
z-%fBilkJa$Yq2Y%-95IUmJ}L4p~jF~LBjSZhb{<txw@L&&o*CV#u|yX#-2+HK^EBx
zq^sp27pLqcmFP|fL(ZkS(=jmpIZhsBe+nr$xnNrZo{h9yxBDBnPd9G=MRxm(o!ejT
z+}`sJDb&{99Om(&zXRBJvjE1xa*~?HE(dQq0_c(NLfppIGK9>gV|DBybqsD@YBr8C
zy9;vCQoycA`_+2dn&J6K4@|fPC#I0Htu{|$*4N3hG7xHzFIQm@8z@%>Zq^-A%lm#S
z96F11?VAY*XYFv^0V#OqEGIHPVJaplGz}&&5=Gr75oqHl`0>+C?Er^{M-WhjFe14O
zi_^CU8zWx4expT4BJ1&>aS1>rEk;>6)=l-r4L8+fu3Om|K%e<^u}2;CJi;511KPsE
zyF}ogL41nn?R3_%FT`!hy2Dx^eX3jfxT~q}?pF2_U|@%|$rNQxcyhpv<J@#LJ}J+k
zO9L?_OU^&fAwSE{F-rWxl?^&cMET5*htG0vq$7`X9y-^;7!eHw^4_<&>>E$YsTFoQ
z319_7cP*Uhf^C0eeaLPPce2}M>vns57n>19Ai+qv_bjcBL%wkzCwxh%v)nZ&z&5ra
z0nTz)p=!_Jzy+qki2f2LO6YZ^FcMc!o^Z(Mn3oE{B*)6n6Y_!|Iv2zFaR<sYSai&z
zQ_*Jtd|&JnPDIt-u&+@Cj_+XpSA#^QU=9*@XvQ!4su?Aw<ll;FCC4Cng&=6I`ukS)
z1+-1uz_9~q)rI8-)fb-`h=d3!4E41^#j#H*wgROWkE9&A%d|kqCqILySfFAr^xaJW
zuIAY8w}oAkQN8uH5EDJd6i#Wb8Txm?HSF<-{w*1$Z=3eFHFKGk=D(b+9KcjW%Tx^`
zpU7@`@vY5a)=DODv|TJtV>9ejTV29=Npo-s!|5fB>6CX|JmdslIQ;Y+E@3!oRaO%x
z3+%9DD!cneY)-%3h+P|dv{ZZx;3y;#8uTzY#JK4t5Lw{Y#&!u_JYGBC#vybROe(G(
zfPI$N9^K+GnauuN4mhM7h#86r5xJGbG1HumLOD4Geq+#M&bI5|Nbxf`IbpljJWxS_
zQR4Dn|Mb}T2V(Mp4MENd+VkC}j^HGMez?1p*<YDJ4pXexoF3{aV7BXr-6<^TR0-f@
z`qk5w=h?GIUw-vxkFw`qJl@NmJbwD9iT)IMqII`d0)UlO?DlvpY6l8%(*w+hqx10z
z>~!j*QeKYd-B+9`<{!{s;!)yAM}FWF9w;=S<E5`9`IWT^1;fbQXmx#e@abO^tjlQ(
z8MXEV!Q^XNSH9m;W3vkhYnCK?3<R)o9ezh<j2>3u6qmg$kGnEx5T@#Mok-~_&CKQ%
zPVrJp7ZItJ<`bLcwnMs>WL8{vIoFnE1E!8<>GHjZ221i|rFUC*?rk<Qwib*3YK1}T
zYo2y<G=-RCaVK{6`V2ZGrp+6na3~|Ei%_EA1VBfq3rOos483oIsh?gDp=*2f90NQn
z=%_~g=w?%@4=$!i!1iJ&j+`e2PWA_I*B5J(_xIW+76{kGm2V|bd%YZ%L->I42x{q&
zz{d=Gs6G^<d@wpMkC&IcnS!^l1d;+2dz9udTg_<9Z9_=J9m2XSJ8PMrK(R(6n81;D
zveWLX_U0OPAM3K`tjg7F75k=ki~q;|2?rC}KA*PW`;T?IZ+j<0>^^kSd@F37P#^Oi
z3WFS5ac!_o(zJU?)f|froCV--+(^|h6S6zm_(@}tB}>iXQd(z%nmFS62vql|5r9R(
zm@r{Pj&zSKSrO^j$OGO%fkHj{1Cq}CC~s2DNtJiNhIa}!0C(=($<A&M^V`GKME{3&
zr23am(X^WjkZ-C6G_R+kc8AqnILVjOI?gE;(zTk=A<jY_q<Vd_4dMw_?kIa<_}1TF
zr%eMU#nlX6bPM|#g%~!L$>veezH0xdRfW;GcT^Y)l37bBx+QD@OE7?fbL~WaJMFG*
zhYYaLTbR)*xIuaa>uF~S!_XYYS2{`r3tZ(_-LpYnx|yNo)gXs9*i7w4w+S`J>3X#=
zu4kS7Z+T$&8V30tMe3p$9v#C8Dw^hZ0_J$?+e;J=9a~YF<B@(rF~<+jC^&Qw{h`@L
zzy~Y3m$s&Lk*c#jbk80qP!M|8i9F%h8;khs#ryRf!4{X#1WW{ourL)MYTq|;%jwWK
z8|pMLtz!vqvw4*<zkaZ{C&nxr8%Aw8+nKPX82bFd<0p?kGh-oZ#|e#=l;A4M7v>R5
z^Mm%p7}sv;(jb*;D?_~(tmiWjteC#Oz?5`E87QVPco=m%Mxxm=miLl)50wzhGfX_#
ze8&O_0E!(JD$jd})+>v$0tts4h;@*)uUZHqEIbvZsAT6H81)i*<X|e-QHV&uW@s}W
zc+&ChqRc)C&nj~<!8a82XIB+Gy;MDbmD(5JvQR182rXq`GA_db8<>-o8DKby=z3L0
zHi3q(Tlr=M<WhhfWPZfJv_Fp01?T9gOyN&&5>mpy;wgniiAQI!76t*Kb~3Yi5`M+f
z<+WpPDh4v|dD`7_3mqNEs{9)_&7Hl5P3}!HFA%oFLe!wWi8mXsFVZ5$&|6&d;0k#s
zYh$&OwQg%w|88T+Bl7@QGL~9TPpsJ=exhmE{cZLK(Qs(k!7IA8fKQAjyk;iJuoxOn
z78~*Gl$(2h2&9#o-tkH)e~3~L9x$s)+=_X%gB!J~t9x-8IP}VU2Zk2>tG-`;aud!S
zP^Wf$k(^p6ls@gRoFVDLVK#Q_BeZ*L<+;lA=NlUznnBf6TzLwKZH4am>*;7V!aMbI
z%Z6B|ZLw1^C`z+%MJXbANK1B9j-3~k4+gD==CaR&mE>Fn089aAb8W)`2MYQP$0sO&
zpLgK^fcJ(n9_Tl|Z>>_nR$4T0SnD}sqzR)X-bXfQJ`$^U;fIyJ@F85y{5T$hP@EU2
zM~Kx1leg{lqg>~DZxPs33uu70`CRoONZn0|xBgEII_?1C78d_~)5s!o{0K2T-<A`s
z8fLCZLWmB(L*$A*o(_8_BiK2TQhE-1_}vAg9NPrK!!+Q{Fkc32(!L1o4v{_Frh%(9
z@R_GpRBhdrQw&QeC$7(ElOhpLhp;UPBn-*LoCjn$W=a;~L0)ZF23L;s#kB7cXl)?u
z2jLhYHJpH7{pg6k-6*1bp{8K5*3)mpVOXp2^o!cV>r<S0=y}H*-?|L|jF0Ia;>RF}
zsT$+4d*#8YPhDqh&XGt{k6dXe2fqg~qrq1qHfTQQP^nh;H($^>LR(w{le*^(;m~zE
zoQ`6(WSe$q6}rpSenn$~R>Za~2Vlw2T-~EcAVZfjU%^>lL565lt8Kcfu-~dzImkRe
z2ElZ&o0_$wJm-dLWA!1tVdGa0O&w;^qEW{toTXK8%<L&fw&?mZE0X`y;q-Gbpgy*O
z!-<y?bVkFIqBA-C7Ea9|_HdGadI`b*_$!28cK}9w+^v27JUky@qhBp)uVwPqT5iWW
zn9CP9B*fgsvxG%%@wd(3gbirsoJ}U!cwwGE878t4FatVWbVnzU2w}4LtmZiK!@4X_
z3yaiCn$r?u=H#m!``(h6Lsywzw(5|)^nm=5%t>)yQ1l2T!P{%_@5`jd3}@_s(e`1k
zLx^D$E*H`cE@>cAP7p-U01E2x1_`&nf>K0sg{mjM+ZfUZP+VZ$GMCgynwDD0?*-_U
z`6{I=PrN)+4sdg#VwX!p7(PcCLS~SR2PPG)w{U%`jmx#1;UsoK4uU7F56<5_gM<}f
zIX8HbC1d$^%#x6A2|SsOTs^N~xs{pD$U(ZCI+6Tu7_|MD<e<SooWz}LYC^fG7lX=Z
zC+J2LQDiADSGONkCFLwKlSw)_5J~`<hd}~)fAl*>7W+w|hr60~LtCl(5g<r94NFE8
zl_V&E9QwO>+}Zr^;&H3-xa;GId;eV*==s^OWat^pMtUxsA%^U#P}MF1Ly;2bI<R|;
zx@8b4%2G;m`x4_rkFand<oF!fnGhX<c#s~r`Mew#^APKXa~`A|lH@-;wfA+D`mXJt
z#!qx9pj$7V%FLW0Xp!OCeC7hhT2D7UD89_cQ;fgCNv#rJ8mz~uccz<MLrKVMI4WM@
zZ|P#N`d8ZZK?s3-><9cQ{rM8d%qk@R6&)`nCQv}x=$Xi@TS)9TPWZ;v5)#z!BuhdL
zw1V#u)1U*Ze+yB=<wU&2<lskFYdsQ`yblt}t2z}TnSJ4|?xl2?v6%DpA?-$@h2gE5
z4#h_hp1#AE!#=#me4iyQo=JHU$-4XLC2XK%L>`$^;%YJ}L26BW^WkrVBwO-MwLjmK
zIjOn)%ht|VbFuwe(@FD;7HHhJBxN4JB~jCm^*5jl4F^Mnug6Akj(d11m_k48!o5Qh
zEoHJAe)jygI0eLNfxrbQymidofRt=WX?9-P4<8{SSEYHntG$BSn(>9C7E)59R_bH;
z>&TI;C!h`s#c-qslwCRyEB}nKXjk+EOnQ?$x}2Bo(?oUfY6=|zY>W+liHuki<Wr+r
zA?~wX^Y$PY=)LTVM^A=bEzB`jYgI%M;bY?0y4a$qzRO<foN%Q1SAo$0pgMEdQ!f^^
z>9v1C^^5fui^ypoXVkv>dYy0#Sd^oFA~O*W3=m>TVDVnc;%WnKGHRsw<6tmaQ10BZ
zAB@~!v%!ufE6M(fy_T-p_xEh00tDmYLEoU7lXLP?#uUTXyXbSZP%_xrIbARzhjDx!
zrb8InKwH`dJ4ojN*#V=r)>pe+w8}|+LtBk^W+ixuEjA|tj;=c|TX&7G-T4~bs6UB5
z+kUR^ZHhIEfNqza+r!RefPZh}+=k{dIKtMu<Oe_z$u&d9W`x7@osVoTBjL!{G{k9#
zqt-1?xi3GoZ9u{kYURuONM^+2A}R#fga@jlyH|+!`btH{v1bU_!U$TTDA}o-qHIlA
z*p><zU4%e%Xgr*=Fa=vD5{Q(@Y5$T}Xe_8IB40rh*r_gQWP(&yQBjH@i*w5NX|1Qs
zL_+@(3bqo72QyobnZ=EWsM%Bb8Jksl0K?k|7En%W_kiE(XaNkKdU?3?qe|0mG38@x
z)r3(jdo-FHVl58QsZ(0kZA`>fq<u&`O-?KDaq-Go#zO#=6;VYRAv&vGWOs_7QL=JR
z)gB`#U2SDCMh;6@$HX6{J@ruNu*+f*cAWpy3XU@xTfxl7dssLR#s_2ZD13eplSm=6
z+W>(N@DpMBupZ4bAQ_yS>Pdr==nMj)DOa;cs-0J@RcaCvyK79AKs|1C=U_}8Fl4Cl
zfq~18QcvGC8)Cs>0&mp-D3AN3ve?Bw4BGmhjo{_!2@DNwJPx(g;Tha&JkR8RlpN9t
zE}RMORx3_Q^11cu05kIds=HadW2?13=`0OoVOXv984KZVYxLb|x3wI(&!DdVgzu}Q
zw%!J8ywfm@JAxST-ni2azvWO>2MQD)3}30(3-1+wW2G8ZL!kvk7?GZ|apmCRpy9Ey
zpm3Sz8iTN6%%(8}7DBA^B3cqg!&&1IL<G1|eC!n0-?_6~+$=N8GJ=we=-C=amrs`P
z!wmeezzr<Vk5SeK-xywkKH4y_`11v(VBKav(JD?Z!Dm!wVe+6HLei{5{Ht?ISR?Ds
z8~B@T@MAC@YbGy_dd9pG*aZ?I{Lv|5V<w}c0%4?d+g8oK$EaJ)z|}{7QiQe)VIY<q
zuop~L(?`Zw!)grwO<S9t`4t1lp|C08PbmP!NSR34_P`2>l`B%iN>WqNd4p)C7DAek
ze^*j^=GmYAX~rL*`6>P&8CdHp$)ba!PkV(8^fAAKcF@vH5~9xCvOLyQzMtUNvUI+|
zlRIZK>+9!J@#`iwf(ba6Ih1o}dYzV>O9x|{2OcXC9wdni!!!8$9E=6jaN@A`L=SrW
zRVaigeou-Lp3OiRYbazDj8Bj%F#f<28-BQu_PGk*!uez}0uuH_*B0~hfCRGB=2tt>
zAL`XA9eCWuJU<xo9KTYO=lZWOw5Nm71Z#T@iaeC}y7p*RX9)Su;iVpdA!L@SCe0l#
z7rDj)5F=yjr(`Zmyb6lBP!L7UpED^N7HThUDwY==mRx4MtT(HUN+@%RJjp0f#u5t0
zSk>!k8)Or~(xT5y_;8_xOI2YxNf-E?t81+KWO8(buxed)93O&k!@WgN>yeQc;B=GV
z3G*SQUK1V4Vv|w^i5&4-0kC0KW(%qZun4xBSlgM3FcF{?_;$49#THvwC=lCG&t-y3
z!Q-G-vI^6!8O<|#TcUr8q7T7HWzqaT?upFBe)MpN#9)`;M0S85x+6wPh9HWzW^#@Q
z)JSO&@71W|7%Ly)3k9?o2&i9@x7S6|r?l>LU?79_&m;7E5;9USb=zcCT4*um8}fxx
z*Mk+1MjuVbD9T>aZ9xmJ0dxz$YTPXp7a|9NoF;ABiM+<tNP3uzJZT%b3AK$$y<u+P
zhLZ$RO|UQ2uU2%ruo!TtlA?|VBZSZq&?$BmKjJXN#<WcADad(RoHEzs@r1{i^H@m`
zsx}Pp)d#V(&3;yL+;xUR8>uB-NI6^@K^g}fj>;rvKa_OIsbM8ZJ0U4nW*wbSi5=yF
zgshk6Q{72v_adT|L35&$O=1xr^lD%0R2Oe$qj?+wcHTwaZyv*+E=^6LVX)qRak>Rb
zb#W)^bf?6Qulj64!L_N_Rh`KBJb!;%Um@NVaRHK1vhUlf3ZRhr%bbAiCFu2-(~h}g
zXx_$|J2fuxwdelXw&XUq)JGXrw@{BZQF{QJEq{3^2}&zg4N}_6Sn|etZjFS@J`Ol6
zpdCs4K4iq4PHw}ALq{rBia_RbaMauM$@Vid-^CimC^Tc#e_N=MuiHBu5U^!hIc&*F
z&B8Em3HQJ$i)mkNaFP*hei1t$)t#sq8UI?r=z2L!T=)spVBAu$lEvm&Mw)c?l^^V_
zHz;FXb_YcV{G$OG3+ueMQsG*K2=de5BgVOEvx$s>Uroa9QZbfI%h@Y^Nz9ZJo+6Qi
zX$?MU5Sd_^V`=3X348ifHNub);fU0Ln!GW(OhyqE7=P%X#cVf+Wg8x<G3|}FyNa--
z?tER!SVkO2WL4i~iOd_%s9*w2d4_Z*{L8RVX$B5r+p8!VTbH4Mh^nUj1BkQ`hJrxv
zv(w4sW0!RgHGq9;o*~f<Bm{ShvaKCqw?xazYt(x4GmIEOKnM^K4bRCg;DGZQkm0Eo
zF-oC6(t97)bwd>@q86brJsvVSwt4wLwZ8O9hf$_p+bNlj;AwfZdp+W6jUZByHJ)t$
zx560kd`<WzGDXS{ONMv~HT_kabgVE0$2xiSyA1j+M!jFWgcXv9AUfCy=-q{3b7uP6
zANJihYv9ZUWR=TOM)1|*|4j@bq5$617<z;aw6}`&pW-lre6&;m+4}|I19M<9^{(VJ
zgD(u1)KPw;h!T86#^{+)bxJ#LTqkJiqQL9@?emndd*q;Wb#faw379S@=`vMW&a8q9
zX>w$Q=bFL7lFD0PLZ)P@ZFXt~Z4NeY-jBqiI;u`(#&kT$doNo^EYe~#HjnAq_-NIX
zJrUNne{>mXvewiTn;7XfvC>0H?2JKu%%u3d>7dXwi0u~fz@`;Q(STZ&!+f`N%BApy
zB~2M@SOtRUBL%68c*q|HB3klOrwx~}!D)lRfxf)h!?d$JYLT?*p#toTAqQ8ITrRS^
zJMmM8j!(S}JdN7{r+FpruoF6(QbL9b8z<z(LY~3wFEI9Y*ojnxv6)!R8w@n6H0E^Z
zwEf!^jXg58$r^-`gXD@k2)o0kl1UXMnIb$@BnYhkGq5J?xN~g!>^Nq135ua<p9n<J
zv|-Rm1|Ngdq&CMMFB-fdlXM6fE$|F#jpY2tECJexG<gL*2)qKWRP_fZSU5~dW(2X|
zM`aH}sAFS%?1Xg;?YB=D;~xE!RK1B=oYE9HdcuTiyKLJESc-(j_bg**9~_K#|E526
zQm{FGTuMu#1PlmIs6cPz;Sq79Igql0mDe()+)BJTSW&meh8zhyF#5agQsKvcWu`da
zaHa@zBxH_7!?E3b*6kIC@N>C}UZGG9s~b)Yn7J57rdL&I{Y{g1w~4;Ch#-|fh%y9L
z5ihWWPZYBaSPK0scDX^~8PkH5ovZ7h)8J`dQd1FCjk}2!I4|u85lo@fDplS!ji}dm
z44dlvyF_+I3N=cItLIr*cY-WNPGco++=Jjzo%`Nmk}sXZ|CQ&j&)w%-uhr4R?pu-t
zT<$%q&)jg$0wxNsp7Z%=rldR*Sh6i$ko=sV+GNuduW(o6VEX*NmTg$DdG0s}e~T;;
zzGjD+MTJ8AuNSniMQ)1Bl8B3&aDpLVroRMX=ncWd_-iiuVrLX<qc77$&{)zYF*Ho7
z2gJq;5u}{qd6$1_hoC;tdUYTq1*A1jOsQ!x88RFr0iXBxtYwEd6V=6>M<uZ1vMf!3
z;nYQM5Y^V@QX1F=E|3(Q0Xo)2O^_a^B(i`&YVp3O3AjNN2YOx6;*So5n{!+|9Tua>
z#cB>ark>C;4R{|;M2ZIVjBvOMdluwFYzSI%6mFdda=C~RDjBRfK<wgHNx1WbUKu(O
za`$lZGUZv#TSxFx(SHskEKwA3$!s%PH%MqCuouT8vQ3o&^pQf>UV-)o6YhjRug$Uh
z6;L}$=ABGWhGE80f{Xf3E<uhbL{dhwRG4Dnc9uGqP=Uv!#+X}Iz%bNN^z2^xQSAc7
zzcxlTt-dq8f3cH^TsN*knG{Zy-3?Bvtfy=*UJnmFCs{3_7&%kBk~GROQFf6YRa;x+
z84kQGb((-y!6iJ!_p?*fi#N2ik<@@1=_weARFQOSbi2>v$T%Cp-|7{05+o?ryGT(v
zmJ$pbR&nJWu#a<2tYS267_Ej%E`7e@Ev-fWAy<Jf3%L`u%{#uF(x1rDuO3{+0mmJ^
zaOlDu4<~(8`5;Pg(2c~`3pgc*{<*dInOqZ*f`k`F6F4}d5ILr{P9dL={9;}VuRZT|
zY@X+<hukv@VhLVk1wep1^dS!6<*Hhw`|HG-0qFh#ZX}Kc#4DB87s$-xUqA;W=rH_2
zr2`MztYo2W9eQQ)cg%DOznmAbDH}IZozAD%Qz2P9EcwDO5h^`xW0bmr_in?eI_=!%
zj|9x}wI5C!;FChKU|5+3ZFJd@<&k%N$o^X2&OK%6CeJ;d)8i3$Nis}(jE-9ZH8m*0
zBM@pi4kf{1KZ7u2ekjNl9u@MaYINyF3am-he2ei&tRZn;f{eJn0l&E4?nwTN@JMm~
z1TztbV)IM=Nr@%J7FN=rX&V%UTw@!ZncmKRGLWPm&MM_zVdQi@nyYa}IAR|gQi)V&
zb=)B^*Bt#Q19nl6k;}+Ucw@}8kE_FFSa}Zz?hi*~yC3zpUc6vg_f{X4Qm#$ta9qYx
z8S=ItVX;y5qJ}W1$YUa5nAdvCJ|#W&)Ee32a1+@sU#I)1R1WEQxQzcqsFs5jzyeK!
z0h10dT5(>jHI8AG*8$w(xKa!)A6C9ya{8lv)B-*pLQKSzdceM7Or$DZluEY(QvA8l
zMLx9k3|(04pEZnk4oA2Y6KbJ1%oqZJCKq3ddc~QAWzB4bh+u#pFEX%kU}eJjX(HJ~
zF2_t3Blj&~r@X}u=BA7rBo?P8?)P0lg1|YLfqP|SYrF%_6c$FgkRW;?6=tmt5h1Kt
zfl?*)=U@qbs-+qPg?k|RQuj=JmT|v<j$;sn>YA*{QB4NAqkbw{0x`gbKI_xKnB;K`
z-|-lw<R$V2GFv&M=a=1A!&7*hF?T(V<@)nuAN=N37lVu_y56X=!g3^V-<MwZg?E8)
zRFjob`Y%QUL=qW<jNAu^O#w8lM73fpe1@o9HWie-W_(WRk_mizDGZw$E|MVjLMiVZ
z8BJ18EU?v*%3K<?Y`{ohsGFZea)cP0MVLqoK<7J9T_$-tX2|M**{#_tLY{|6HU{lm
zRrjm|AeqblDpA=m^RVzCuBaCOkLME2uOddM0e!y#fGP~sYrHj{$x7V{Y`HvV)v|e@
zXjx1vXlVGn;m**41TXl&$(2SGz1x=)p<QtJH><iGWh@+~^M)mu0ZAV?J<$Is;_bIN
zdOw_MDG3_Rxp{XPn#X#gNiR8K^K;~tNZl#<dQGm0s<fU^!2B^xzpq|snII|tl+swe
zT}J){iQ4H;IuK(L3IydR$6Xky@vAcb1X>UjwV8!Xo}BvHy(gIedl1|><Bc)^2M<TM
zm(%A7ry^#p4S=`}LcMHoT@a8URXA9(Dq$$;kp=ZRa`r88w@(mM-%zyXLuU8D3Ft;j
zrjtIVz*|5iIui?bExBg&Doja+n(JNC9w<7%ZKGdzXUvOx^?jo_GxqK|hhEXYH>9}T
zNUNJ;x$BC2ug?EZzj`iw$jv4UGth!*T6u=6q_AYl;R$`zal0D>s^9^S^y#_=+vTLW
ztv2jn>=DL5hihSUSdO3ic0S!VMmS4JMi6F60!JuMP@FQgut@+7N`V{d?pAe}kti@;
z7L2R6c@99OqTikM!^J>yd;}j8#DT)WB&hjp*BrB>J2@ZnLr;9k72~hucA+QoG+q5U
z-LTpPy<^#AvxXRw6}g@b0o(fRARzvO>}UedTqu;UbY~}mM<cq#cvb^)v#T<ym6D#N
z7hJU?vBS6Y4uUEWi82Jwvt!753#}3k?CED+dswZ-9M<A;F4faP@2G^eJAW4zPnjOV
z7~&^i9e!*YL`BZN<^2FK^kK1w%86^?VJp$x)X;0XmoOPdbX40yRsdW!fPTDw6JP1r
zW;Ynznkv)bC4UNXi9*Axz+$14p`3QOi$rk3eqWeIHu_4ph@lrwJF#EA#e{LU4y#(R
zHX&~a>-E9Pn30Jj7Y(P?0pmO%Ur9j6HnQIwtn5(lO{i)*Rf=-T0O_*9(GH=9ura9|
z(u46-4%~R4oDiUiElFjaT#k#A1HQk>-omcZNJJsasgQ%9wB*>fQT8TyiY2=P*;UnE
zqJ2Jo(Fl^jsef@r`BcTW>j7}bk*j>WP;{`XMx+i5>16sqenH&j5wl*hoj2<8dVUyR
z1k~Q-+2=Eqi7N_m<*#&Qh#ls)rq!WZg1@d>A*!Vtm@+OQEE-n|{_>BOxw5i!bIIX;
zl^<k0^a>pPdaz<cd9YHmRz%zc{DS4kS-?j*fl6<5IITbq!h*7u=tAsMgu8IpM}>6-
zzZ*irP_?4dPak<K$LTDn_nN*851}|9riLlfVM68#3e~+xt;bbl`Ag}XG~`;~^+b;T
zw^tB)@i;6JOWH>_WiNe`4l*bYrnuwow4@0`x`}CYeJ?{#ecOJ;NQ(%E>+=<zYCgQ<
z2;km2OhQOS#3n*(K16C$z1TrjKy4l>L6?EuA`y5xB&x$9vh6@P98b<ieX)ET7H;As
z`utQ$r`8vJqyJXlhv;&IP1al{Y>(qqNXD81Rb$cWhZ8)XGO-8a1MfncO%Azqo4F&;
z9!zP}AJ5SZ-HUJ)$MFT$AKac?xS{tYPMap@NUVv|3&izcp}-0i?hX=TIV+Zzr-ul~
zv&DZbSM&i<H=a<=%WZzZs}diQh~}we8XV#BKtz|cZl@csGX_;8#$XZ<Q;s#5v7);6
z4pG*j{3S?<Qn<gkRtARD5TuY69-?RiOg1P;sG*5J`2h~(ptHIsw)Wo*s3U9KR_ElL
zNy~|5POZFtNK_d_{6NQ=##y_DLn7q2=|Kv^^hdh{P4B32u(H2?_r))=_AiiZ7XKX_
z^zYywT#|dxzYCwyzx1bf`Scg`B4x4tN5zY5|L!_!TESl&tY}NKS45<c?H#Q`jV;p_
zk^kAFXP<tx_sIIskbYErB_oU<ZT3$=>Z^T3SmM6Ot^|zZTqTEJ5d>+Mi+rmPnS*y+
ziSSs;k*~T^W;C+p17pI3CxFO-{9rR>4_)A5vmC?v`q>JLd>+3|FL!*~$#8=SHc&WT
zwsX0kfXTec>QDm-ouaBc*RF2z2`ct2OKNDFGFb3s^I~^}iX_@?onCU+5)K+$YvMQI
zk0jd^`P1RDccRpjagu;3dDekHm)tJ1FtN0X#FKFELE##Vi}FtLMC1OF+G8>shXu~X
znrz+L-cTg^^Yq|A-YuXH2n)|rrO_oJ#T0Nuv~bRUkn<DyBIIx)_jC*FJXk@fSQ8N1
zHur|n>d7&Xvd!C~gjx#{pt&neZEC<XF+ZkPCD#1>xqL&)tr=7n?EwbHxQKn=M+qq<
zb44;Kpf927Agm5u!V1e#3p++9A3F$%fNa>%G8Q^%f=pm}Uu!*Bm?wM4mN2E>(go%4
z6)ig}$}xDBO7IF~V7MsErNqMM*O1W8Dka3Gmk<JdaHBVi(e6D3qex-|EZS0)53Vz=
zu}pqG<vqCV`nnN-<aU*OoC9H?SYIrtPI`H>a9c{OY3o8VXb2_Io+iWU&^VA_k%b`)
zs4bltnq6c!hE$5H6wYyx4FnE}xEK9p;hxd`qU<R<iUfcU0?zfz-L1{dwTL)7w)jE!
z?dIQIxSEY9mfpPPKYy9+zlME!3RjaiKYtzWw|et}Lj-k6ubakEbQd?*^&tW&e*wdC
zwd;02wochE_5*}A9Vtua<8>IZ01C-V7<3#MUc9TA7-Dq!GwrCTIxt^+{PAsuDC39?
zXXK+;BQayJi#M1cEEWc#nLjE;Fi!C>n{WJc2;l(t*4R_N5bh{PMKP6;&mm5$1!B_)
z?-GjTX&^D_5{3{oY$Mz{*BO@3VB`@?>N@r1<sQq#SXg;4RyuhhBz{WO8FzcYJ1iR`
z#9a>{Nl7e?h*2(b#m|o&$+vzg3G)li9U-r9^SwXwRf~J_*1FvUecGM2V<v}J;dmBT
zLHPk^%&Q<bn)@PSlS<A$*fhkeg>}+u)xjg2#P#ixb-Gg=I|Ae@9IjETNKUp0oTc*N
zslxH%92{_myz|pz*5&z}-_l-_Vul+^D2eR1a)akJLh6i}I6bt>li_rC+uMV;*Dtwa
zk)#k*y}QuZS(uH|hYt9|lhe+Az=v?C$%)+rDLw+rd_$n$(4V8nG=wDr$}d!@!I3gF
zEYayXJ~Vr<YzFT_M3{n%ma>RV25{Wq=2C8V3#5RF5h?kPY0DY`mTbed7nR4ChIuPP
z?l!PX0QUfi0#B!NY_KG}oDy4U1U3V$35v^&p~?*&ehE7vK84pZDWu>Sr?04<u)~-F
z!g)4<@I$P`n+U8TWUY&4sMATw)$Hf09H7Kj7)u*9XvL-%>wZcO4#2}wb6<eJz}chs
zj+DY%-x%o$9UeGpAh13|UM_CW1e{@dEBglT2;m#qrD0c1p25)I%t6})rI<MkJJ~+0
zSUj!6{*K&;T>(-CXy4$>^VMfxwdY0ecs>~qPcWbPUaS#n=Z8lVP6*sditH^XiJ|Yv
zQ^*l#iXLp%^ktZw0b5*R0R+@=%<_S<l<CMkAliM>&3qtv8b|4IHsakqg~SQ3IicPS
zJ2TnR!Gp)l$(c@#nzG&*p0ksmTiKug`JeA_eu%RwZ&?Ne5D*5}DmaYTeAtuuj8g(K
zFjiya(qRrL?SR4)umB(i@x(&F8nIkTrly|4exan`;k3-v#0kX+$*2m#0hd%k@C9~Z
zA|(QCLuuTia<KAq9h>{G6_W@|a3!+_=Q#)v9+{gI`;uY`cCaSt;~0z|ve|OVYJ<0M
zp7L@s1fhnr-uVdH6*7FmVgiLr84_B>iHSKFJdWq{X^AXG{Yek$uPz~!#`$D+w6UFk
zv@seU&R}uf@R@KtKONn|fUWbqZ3d$k{^iw;9{Rz25(zzI$HaGvn9WYyG^8$_>>lW;
z(lssyOkva!OxuHyvj+lQvxONdKAcQiyO!a$CH!B!lW<zC*CUu*0bG=kS0&+j#amn?
z)oLOV8u@q_7(|0GI%V!VklcI_$vrf>ao~u4ALFUa;&4q!5ij)u<2MK!IzD;XWX>w%
z$})ikq6Y^~D#<n#CC8cA=`19iscDmLdYi)c6j$P31fGnP5M!wWToc(8NMO~X4p75O
z--l#dxJg;%MzvWlHN<J8A`tY4H3?L}enc+Q#Po(RfX#|w@T%2#jdY<=c=E3?42KZL
zzyvJ)Ic;Xry^|6*^eW&hayTR$bEFNXFYJ;p3l1*aG#Q6I7-I@nxeXqJy}+pOF*%>2
zE1ZMDok{s5t{HZTowBjv#u=PpbmSofD}O6mOd%-;ALKT?v6PbfQsz2ba8Oe`aa8%*
z$u<ov-?Or>UsRU(jJ$HxBLl#j0t_@OkaCJ`y4pe-gIxtEE5ODBqawcWNsSj!&WC{|
z#0iqH#354X&&qsKt7wfZRJJZw>kAzk01yb9Eq!?tbbUzqHhydZN^zQ-qIM9=__qo(
z@S#1B%AB+SCg0V<<xFGhd*W8@yaOGUQ5}>)<QL`g-#&*G@tGuMjru#EF^or_`;eG-
zn)Xa>Ss2-M=8E~^K@Zn++rmf#c{tM2a+pKx!NPVO^`m`+YWJeMQPDlc-7VN&&W4)#
z&SQJwg5a15?0OOu=z>?)jUz;f7Vj}MZq?VsNvwd6Bu$m>qO<k;GOZJ4ki^LXr;qKC
z#L5X!sL2mTskv9J_}Zc%sA<DS<MiNJpw*2Ny<YVIJAu@zT%{a4=H5=dPT1MD?Y>4k
zxs7E7rP$Rc%+7JJ^61&Kubxqi$!m$~N?l5tD}9b@FhiYirK7L3Bx$#Ak>UgZ3n_RF
zp>?xlMFq3SfQD^ol_wRU)f|96*E=Jjo;r|Pr+Qa)KMr#O>Tew@GBiJttvGdV%1JE_
zKx$2+OBbYtj28K`!nkZl-sps}G<F9opM%{ZB@=G5a&{eeZCLm8I#8J?I<Pxpml0C}
zRR}Q);9|pKwQ(BhsLQ}QC{|4{QC$7jQ5U+kLg0Lp2N>2RfV4|`_bVoS;t{XsroM`=
zS$4w&2dyfj!vh_=KekRSEoG<V&;+sf*=<$FMF%;W*!+_7Iw&YFb=Rb%Nb;2cv;U^<
zMy?|l?nXvhVs0~p*nT@QY_N8zC13e>s-1rCA)kjEk`L^PWIohEU{Uu;<Wn%~(p!@0
z&Ld~RhJ^e|++%e7Zgx*{?4|H$MdpBU^nV;1ioeQRmWMb~hPFJ25t>ii#ibLP6xYsV
zE))C$wuVj~R{(ezZzsIWT30ckyr&K)kT_cDHS7^nmNQ=G(pN7CTZkReg*%%CAhe40
zB^NhWVc+s$2P(-~5}U<gc)SXA;a$U>%~i;?JDzPQRIL(OiaVXFH83ib+nlR!iBi1B
znPws|Vbev<)oLy%j9mzY%pz0&Ib>iWQ&Yt!in>^`CJn#M%r*}wywEweD?`B2e9V})
zgnGfnV2{Fwn-K1iSXeIYh(Le=WBmOzhZcN{QB>^M6Q1@Zx@N9=p)VdR5gEpL4SM-!
zQSp-nKH=L+`S`<p-!&0IVn|zPLOKG(XO%{{8~jv)kYt-JW5TYtfs9&>#NRG;-hi2e
zH0dGsSF~m>ZpgSF>C-rI&`G%@`Rw*Ezdc;dZX>1hZMetMX1JDptAAp*5^!j&8WXpb
z1d&&iboLq1NBqOj+sYEbyVnDzwUg-iZWRYC^c1AZWD#eLn}uwvbB7jOc%1eThxRqe
z_I9$RDpr~VQhG&v%7@ZxD9kXqU{i}f{*seXT`cz`^Q>+L5-gp*jDUSfFPP`3{ZNu9
zEXym1bLdW$mT1&+e(Ipfu%&x}X!zq=cUBR`%^^E!5rEeYx^|OSAp~Y&>kUqPd|ask
zfUTdyH$V(dG7+*pCTMlfQ<&}ULwZIoB!pXwFyvwk8Dki(gq<j5s@0l#QBLz~RCJE4
zp!(P1M4}rf0ybgR72yVWfWphEsPF?ihkO0{YGub>SR^O%)dt}i`}Ecf!|sS-*Dy*~
z^$3<Ihmyg)LZ7_-+Mmoj?lU>j8&p}giFLr#)Kntrn?-zT=hv*ch}?oWBQ(VbSG;FI
zm5}K!2QZxKj;CA?->wpd0PN;(F3XCS-Yjkh$E)xhg8#6R`aZMp#@of^;F)hV3JF#$
zb)LorbaK@Rj#KDvRMGO;VpvOeiS+mhL|y%y6^Hb=q`-|e9bWcPjK-fK?JsUFnBeSe
zY5M$%Er&7(YdJtQ*mLB$D-XiKRX?ID()BKFo!#R{w}lV~dvXYetA7)D?z^#I-?5go
z(yspDtxqQxVx6wcGUlW=6BYU1@n@rCIhuJ~tl2LZz_BgEWgS0>gC7e9--?Ep3v|bk
z9vevdVs<#0f)D^Osfj7g3aVuyuUf36Yz*OG?@0ZN8BfG!?ZIT?o#Nxu?$NNfu)5sv
zpj(;>7U;Zk$gLE!37zx^?Q3&N5NRLF3{G7-9Z(jp{g)On3P`!Y$h1Yu9ShFF>Q~UQ
zPT~}V<JdtegthG1lL?Prgr^!Tm9m&1x{n8torjEXcsw33iF<s}ZiVM?r`vBG;{*U-
zS`5m<eRurUeN_&>qepj(I{^9qLgpQ5ELt21kCg%z<$g7i0Vlx-!Nn+OIUgwPy&p>9
z#*E|hL%KC?=+V?h&;B05WWK=@(Tyj=!;L@~#$d?$8V;HbNAyh1w;Z69F*ul*6`T^u
z<VaKwCYC@B8X0uyQfG)e&DOGZ>l68j-s|X*avdH;`5?3vsLnSd0_0`F6}Kd9MHBRc
z6@^~25QXJTF~J$}95g7I5+j^vvxg|h>8YGrE!##}p9(C>j~o~&8%jqP38GZh(zaS_
z#7+lEg$UA<2gHI6s*Sgk;svc=P>L0e_oc8twI{~soDYdWh60G~Kq`v$iFcBjkHA4Z
zKp_i2pgl;#Ni;{3C>eT0h18z2bvJM@n2MFf{Q}3cLB}ZRk&ZJD=4Hjnif&w}fC#m7
z#al__4Ws2}a57w<jNt*G#j;0ZdhF04LoTQ2j$q+O_MaIJ_mLdB1WRH0qX4Wx+)hA3
z6Pm4i?kI0uoBu?lrXLS;@W}aoaG*MCJ)+%6ZN4%TPZjTQZ1>=+frA1>zJbY-Vi``i
zg}$;p>x(4m3Py|wG^2zrF2>fI4q~yTYw$Y2A|zZ*A1CZ|b(lR`o(E9$dV*eP?oM*%
z4L<<{Zo#<#YXkFX;uIxM4TOSdl|vL$Vk<9&rbh6lS3VeIN>(C`>ziKe?<Goeamk@`
zs4w01TIur6nUAtc<3v2MMZU1P&h5dM!b?xVI}u$Q)-re;HDS4c9oBv-d$LtisGm)G
zKK{%2A~qWFs`o6=BN2w8_lAxL)tLal4P)zq@C|lF2x7F7K(UT0Fc3|@RCqHI;S)@>
zT5cLCzd#5lAE{CA3r9)&{E1XvNIw!mx{yr9FBOFprC0Y=WMXI!SGj=K#C314nEzJ&
z5MAuK0sVoB6zINiuEF7O;j)GYwvcFunpW&nTY9To_6I&q>;=5myx`(2R#Y&He>;`!
zcq&#LlfPb9$>0isvr#2Qpn&urOyV+rVc={bRH_D@joW&!f)zF#CWZpJzg;%tWLks`
zek@%HsZF_N5wvqn7(+@lon?Y9G=}iN2bIJSqe<#c&WHRceG6GpY;m@$>}YcP5~?92
z4aQ#u8ipUsRd5O=0Lqxf`R;-}VOkcxWowtLhyf&A702}OzzV0zDR${l;-t`wet>Wt
z>u~{rr+pL@g!gvbA*JgxF-nzGBHYS8XHsIgFIvyV;|z-F%tGk7YJZ|V==)wUkthjb
z+xv~O2r~l-uE<D?KW0#M>>3w$HFDX|CXmhbn(yOy!d9O|hPVV)aYzBth=GV0AYfag
zI$^L_hba?joz9!ped(q)Lj{*T0q(IQ2^mD^YrsR}JAs6CEVK#tM(RrVKLTc$4Nh1a
z%PT!$vpqQcF>W2Nc^4oOK_Y;CIRAyV&FK-)A`<CbpygB%i*qqe^%iVxVf&h_WsNIj
zySK)jsJ5+A4Td)8Og5uHn-mF^OedR;N5IsE*=3*YA}UWA7H4*4Ek>3c(r*WL3B62D
zP2R!HNQ-d<edmCdaq2T%s{m#J%;lkIO8}P+ovf(s6GRsrtVF(bn#KkQ!`$BaRbQAu
z8#;CP#-5>rPBjr|H@14X@>924B!&t$!;kiZ$trX(QvFEZX^(uUU;$uYTw=So>13nC
z_cA?!vHR_qbG!OiMGnN(YLuN-v6?ah@w3HdxhYwzFIjN}sT;00R#x^gDHU#r!S+=s
zK%Z^aGHYv|;6UY<?oLq&vgHgG1<~F}qcv`G>0%^QUdUynL)S!L<7(1&$yzE%h?is9
z1nMP2CuKxtCCI2Im8@wu!a@s0S)(+N?KcQvJJyA!eVcB}IxzM5#-81%;W*1E9~#lH
zNojvvHN-e<GXhoY1d9mhytb{@W2yuqg}IITMOFX17R`!?Kp&SPio=&kBJSxsI&BR*
zo5Qf_Fgyx=xr^3_WZ2kHvjHVYH*Jihw&|f=QML%Asf`MY*LR@exheS~EHM#mKdcrT
z5SYLxZGjROrI7yUO;QpL+Foo?XhndAF-l|D1$xr=8{ue54??($SBfvpb!;6!hW!L1
zq~vEP2KLXqr4W20(`twdePtAql5vD^-Lni(sJl2;u`dF2f7qvLA@$;`lwQH0B;}K4
zwa_B9>`+~yQT%8Tx!dZYF_pBplfk(cIoQf0`35v3pZ21!p|n)zOuGY5zy{6)EMOR$
zwgp1+%n?dD(QOWU5-d;42K$|az<^IewRi#v%?&GjYa^WYZM5)PNfG6c1RTJUjFS2E
zWE4&VMHnZkcj_qJvaCVa6v!beZJ1Cea)b_vO2$wlUO_USq{s0+;u+XihDkFDCWB>+
z>z&m*as8KfT>!17G$Ko*6iuioRJNDYaFVk)TDoq<<$70}H}TqTL4xWKuW(;_Ww+fm
z-9JCIaKB_jCluHQPXtzghXZt2US-bQ4c!q^G+=LRQxWrQH0<G&&+nO)QA*UB`Y54?
zI^fb!*pERednlQSx+9#Q^pQ1!3A>O4?Q15qgsqasGCqSonawYTJr4jR)%a0{jI)r>
z;6E>y4n0B$mv{rWTTcY6A+P3AURUO=qGM>%6!@bFT{$M>U&uxE1jx@#7$%(Gu{i?K
z&hh{Ql1e!xq6(5YYuFxFOI$z7S6<AH5aTWwyXj(a?TP+dpMHueG$B-vI5rr-t1HS+
zq=MeX&asl*_DN^;2utpH<_U+hu*nfV;yfVtaK1b%j^I&@j1%LdaHPpyF2e8P8K=Vt
z=OgUUGr3NkSyg(I=_LaV>(!9*@py=<D4-l5CJk}9upDtk!gha_L@dF0-M+*9pD>T|
zy+))Fcpi4wG;oXEjUiuZG)Gpx!}<lfQ^uTNGngw)1J3L*c8W<a6Y8)-oEWs#<4&Tq
z*r^ys6Cni~#w$dmFyYD&))6GjhT3GO!N{l1JZgGt!U>{$p&TJ${0Ye;ve8Ony-aWY
zea6MDM)bCf9?=3Z&{+LFBE8u>t#QP;{#v43C;e3<r($j!xf6;3(vj1iC8Wg>Ueaea
zO5`K%p@XqH&Lt4@H9SHl0_FoDwxptbaKEvbZ7|{G(upcC8Gq=E<D=vl*!c6A3+WUe
zENpsC)<CB4PBE)hi$|qZj;@}Y-pas$kbe}r2%VzKiwsul`0{92jE6l;FOF*p90%N#
zmWaD%gnEhT(nS*2VjVt4u<I}p6f`9+iInF-umZYpECviKH`p5%R&gC+T6{7|h$e%H
z<8$on8RfhtFeEseM-f9@ORhn72>69ALd-C$L<y%SH%x%AP04u?&JyLOZcafC5G*~o
zmkvfJz3ml=E{6zVLdtPt3mb&ApBxVg6OewXyx@CT#YC#ed?~+%0WZ!qSYf%9vsrSr
zJONd8&PnX{!zX)c4E*fT!>^t_c>dKh=I%rfBPU|IAtS~F1Pm=;^2hhF<|$JraSXE7
zEDF9@t@Sg|ErCpiV6P=yH2|+vZe_TQvx?6$I>`_)O+y8{YSdW78UfdKTY^!eN>RHH
zWHS4WW&Bq9dfYsxAw)vPK)tLIiOV;-q9i(`rXrVgPwfG<N5l>xO4r#GL!xfn;T+IY
zL<RB6#&G%EVPS(#30IAt&t<0z56on_P1LYzWvW(z;EReF>Q&39vJ6YAb6V0A`^}H`
zy;?hw?pi3zE{6rgX0;fZivP1AgRd+WK5*k0!RF#KG4CECcs8bG@Za{DxkzNT8vy?u
zAWkm_!z1Lk2oF5WCTZ11Efkr++-mSJ-620pFt9y<|9JS$hT{*<T!Vqesz4EDRWy@L
zcG$})j*w?&IKZZyA_81%WtgldR_tT(fxabqd>o3DI4pWyoQp>|>n3Ur#)9Sy4DKlB
z4@^}3njM(66F(iK4tYe@AzdL%8JawWcQCR_L1&l_N0TE&Z?v!`^SVnU#u`7@Tkd3G
z#9@et5lC98#rFr}`<Z%#aMK6L%{wx;I{m3Qf`s}aLH*o2+va&s{Kd3MSHa2F&*(3@
zydf!|P@dxEMit*0O$Yyg2`r3M?j%WQrPmpHx9}7>R>UtiX;8bn)seE+vCp|ykFc2q
zXtqf6`5=YPbpk^pD^b^y1!Txz&^zfK6;RO_56;C!f!j@z_$Ajl#;O9@YUygUj(e(Q
zV<1Awh>yudVGPu9D=N5)>m9gT0+O+K;utnIC7VYol4B%=>B*v2Zosu0%z`9og5QQ>
zbq|Isa>BeouNCEQss+DcH@nUPDV`8m$IL<l>!fE$hX_1aiA{bZG{CA2$&yeT{j0Wt
zGe<J1a0zq3x^of_vVd2Jn7@~Qydk+7HhQOh%HN#v^0=(81)T#j6)8ZlxappKH%yji
z-3!LueStLfAexqe4AWV~;JXfr3Xu@ov3|yxGRBh<QwizcFeGrTqH|x>yt;<08>1=8
zd_`XqTuGsGP85s4`E6Ku@*UycRmkO~jjrQ3>B5aeY?D#kOi|PlubIvqF*4|)H@Sz>
zGTvTg0}?>)2!%ccPnK(&a^IV`Xi76EEB`YJ8AB-736@tjrk7jYuo*>O6g#;HPE1E=
z26^ZD!pv;<%I27N2b1>t_8y$iC*TBbvM_qA7Sn#`bbaR4!;)g8UmTtvL2t)lDhE(E
zgFf7d`zGTes}JrjMjAN%xfVp97~=7h;RN>GuKS`N4^t8A)x7!(!WG+^j#)m%-s7pM
z$R8bCH{U^gY1PY*oQkEvxLN*?pF`{hBtu|F%w+K&qGV#3{EU;EqLYu4<v-MrH3#LQ
zrUiJ&FG11bg_3&I2mG;h8@TN=L*7fh5a?xE)5BcgE(G5?S0)-Z^$ruj2+M!Uc(59f
zas!nQLCbl(qns<`Y-z>__SkJ3b`OA7qaP%UqsWn@l}f1<D>aNz()$Io&izaxuCGqo
zk9qC5c+&nWk%4VFtaxIW$+L%&n^cy26VM<NmIlki&r=2^FX*KF$8oQXxxKIvw}~r*
zf?CF?4b}XO)w7@8piXIQXQ14TijEn7YSU+N+V}ut3r5CIgR*uxc#54*ESX*&Q6I9o
z`P{O<2FfKSmj~P|l89X^;2aPO_>(nlb=Mk?4C{=${BLFYraxq46cQq^X2`e+Rgp`3
zy5qt~&V37^M?j`p28%U=lwLyRb4W5LES<}2)XPUWb-;c*co!w_UyUvx+$wKGL51~b
zJiUB{O}oPR8fm)^ClkAZxPr!%o_7$S&}rcOM%emV;52wfW8>>*!D;b6k42Jq;hcD%
z9?uc11n`UA!kJ3>V#32(1@%r4eTGYeGQBmZz}}-k{6S%i7OxQU-Idm46VM{E6BwE)
zu_>xzT}#!zScTR4eIzw<uEoJTPJ)n~+2guTJf&i6CsblXixoV!wV{HylEBwMjtY?o
zpC3VtZ6w9{Q$jzM*T7PfRM@0|<-BttO9<R_N-@t)OQ?9z2(&t8PM4){tHrVKYD9`4
zUVZ1Sr3`W=69$Z7a+KHK$O#Y6b?liO!|*KU)u?=B5n2{ys5D29T`b!Yp<oxszYi?{
zCjeN3`%q-zIYHa(sBOhT63Lk4J_HIqS>xgm2S9$@&jG9;CEQ82)bx+YOu4y;kDk}!
z0<7~f?q<9T&9!~vWFkcQpnEI_P}-_3V-Xpa0`s5{4-@4gN-YUSC*)1?hZ`vtz&G}<
z3bHzm>G%nP_$PIaN#FB)n4$=Hxm2oBmj%k>0ye{4xo&`kb86HtD-x2_gm{t@=IUJU
z_x-NT1-b;-Ij<{h&n6eU5H<jFemcf|+9TxBR<fXN5HH1>{bHM_(<ESw+KU6qdJWA2
z%w0&T=B8!JtI$kQAQ+(r&m5ga8w*r&y#^+<V}~y#Gv3q5{BzzF{D^5~DE?iAR4$@g
zx_$5c6gt;pR}H{{F3OtJ3fTd)em%oA0VQ@qFq@m!fFJHQLBhDz2<e1f!!T~Nw{nge
zUn)9$r?#zX{nR3;?-8K~cv@>fBTQll6kDpeER@WhC1=dlyi}|ETQ89M8$o@+SNzD1
zc3ryAS&wg-J56prqo@j&2op_-G_u1u0pq+9yVJs;1j`Tig2-~o<7G<kOH7Ev0%;Rn
zx!_4A?z*Q5$PB!0-;kQvpCFSRY*Lu-vfU)+mHW_*MECFChZd_C)#=-MtaT;O0y{Z|
z2ZB{-=!XykSZJbzD<K0;Xfv&w_Q<EY?>eV?+dlJd-^z|LAm1TWV!u6vTtX_27noW2
z=BX6IgP3{ag>FQ|3-ByRFjp}E@OOu$G$3vWT*aM)vl&k9j*Ts?Z^!#PYn#B9f4A)K
z_6sB$4skagd@RYW{vQa2yn$Pw<FW^%70)EQBYIHFX>}zs)1Udk@Mr@^HZ07@p{HPP
zy<-y_0edDs>|S1`DqhIR73GHGwg9ABJu;i-FW`xerMC?S0+kv(%7QN)LT(_Nu}4ls
zg&ZNcDoKPWsvmM)s6von#AMgUqL`kv)*gzBNBf~>ab~rcD5zG0wc?@0!v(w`1UyqN
zixO77bEdQVYo%RY!X80qsNH&%T(r`p!^Vg#r*(anUAsL~b46;^@XeOpsi;w+VJoJ)
zxUluILb4C?&6OECY>SnapqZ^R7<G^AUVxI)bZ+G%1CR{<5y+KIBlCD*Zh3+9Z@L}3
z5-N`WI>*rOidjf-qY#;*RXh{qyduX>S4Y4Xu~xzX-Lf|vBE^VELnw}Rl7W?i2O5@1
zyp1cYhx1>~(4v?((P`}b;j591;UOAM?$*fmN5Zz)wZSJQX`~WKM0RDE`N-pp<o1sj
z?$Mv<ZlsemK}^IrZtIZ>{zEQR*-NU`oesvF3w5Vs==Et9qpJkP;N*gB4S1}AYfkzb
zw@){2|3!BDi=EqF?%dw<9@%oT$1wV$zXRBJvjE1xa$cJbuP*sAsOXXJP4p$KB!-aL
ze5{T=q{hJ|v1S928`IGv?TWNtt)~NScs^32FS|%gVdZGGd4#jRPM(#4P&<C9(fGn?
zft_nX_U@cBaAzR1K*@0tNWr^B<Rr&uOvOZnrm>Ja9iz4bV!24GWFg?#@aUov7onY#
zThZ~tZ?2<z6V_~m#5XMh7!|EXX*t$i_XPqM)19*+?%H1EdS4{b0O&KHFl0F9)vyE9
zg*y`}?-G&AJL*LEGCcT;VIS7mWR`$CyzzA4<#b|vcZ=>`{yv$c#D%`A!?B<E^NFN|
z2g*v8oPVA}f|j4-RF7Y{-a$iAqOii5uqitk><$(eD)F7pwy;(t76gwrQ6{P0z?Xnl
zK$@ZkEwp}P$J^QM;SQ7W+-{?LFp~+m1Se%+W`{r`46Tmi!Fp!5v)t7vz)oEJ&vMtM
zYR?&G|N0FE@RwbjM$K^K1$(xvpw#kYeDa9>t(a5qx$VnHFAgzX2O04NCLPmLO+p<2
zT(3Lxv630ajSibI^Nd?6#8lt~7cS*atj%dYrwT#PT=h3j`JsI#zF2A1g(U~o7oQo3
zga|1NO(%tlm{O5UP=fJD%8|dGsU`>!bvP+`gDJLvswWG5cN2ikw`?+f?^{9iV|C~<
zm5i!6wgt$<2}&oN^&M~xn?4;*N``NnHoP^9nwI9joUb~rQA*2X^#NU&#oyX2X02oj
zM{~yFM7BL`wbdn@m#!9IP<U>`OO5^F`XR^vvX60(8J;S^GKterx}?e^bNg*<PQRh6
zT!*e^*Tx<#72pCm@=rno#&Qwkrk6lufnOWjCHSUnMS#6<x1eMZl0BZ^E(hml5EFc?
z*}sH{Jh{e66q3s!_Ll;nJU?w``)AvEC<jS}nxy#Iw#@eCfeJc|5|{t_=XXrIl(2Xt
zs2I3|5#BB354%$s+o=`cPL{8p9;`gio;~{Vt3P{`J^$kIUiRei(??AMAnwvsy>SX1
zK*02gv<s&&blb55t}OuAhokc`auu6tzPv>2$t%*;oD2F(JW`w%u?Kuoy#TTLj_<Ff
z`cgJwZGJG4aE*}&CVjv@G<{GI>mfY+Ie#?14Qy3S!nZJQQ$WaON;9;}32T<kJq7~U
zzap86m@+~MKkQ{M%VS*phjD{|gtJ5s4ueet#rDh&_Q+khQ|lMsFLuu+x^0xMC7Bi1
z&Ca!@*`z6@Vy@zEeiqTt=b`j&>&`t-bAFQwgVxu)cY~uT#3Z$xl)MsFWZfH~a43Ug
z_6aZJfX@K$0ONHQdgG+4t2b#lU1P58)pK!$VeT5@M;{$YE>iW)5I0kL1=C#^>6gU-
z<>a}xi3P$namriCROb5%ca=4Y8zOgAlG7^EH`DPNXOpE3+YM>gAS7b=H1DIRr#Wi`
z6FAZ{oP`8u6~#*9Z`yzTd}iW-30l8RKC?(G!!qVHTjYV|3TbUMtusMQ9C3-noZO>Q
z02T#f!jci^kGpe;#HDAXTr7eF0^>?tiK0$9m+J3;ttnvd+_{q_`8aJ000l`^FrA_)
zf7Ow`G1oRPsUm=@3pcEOl3KHlbBcvfy=Ho-4^q88Hr;LPn&6pp2T7>fh`1g<S$}_B
zQs|Y;1J$spQJ7(Wnd~72@vF9xTJ`S|W<wi^u1nFqLhW+8Vl9m9|JM^{+oZgy5`Dd}
zznP#{;ng%R^d?!CyqFj_$WXl?#Z3#*+0v+m)Y48jq^UML7sV1&`d89W#|e&>mL#K&
zWn}#`6J5J?lZ@1{t`e%`y$`9pyMWQojU4d9I%EvD_>|a56OEa%yqAQmg^Gyfx}J$T
z0YD+dLZv79uRy{%DDqE;6}DOkA}u_X6LMT~grfih7Ve>70)Z+D5ldJSV<K_7%UzV&
zC*fITW+wQCg8uBPf~S{y+bt`#FOUp0RLV9&OBs?Ab1NUP!L`-O46r3dbiFEwDmWz2
z@O3NStbkk!&{u7-Iqi=nO^hYy$7y?dBDj;u18<iJ_We5xax%fGbqCfTadF|wB|lZS
zjfhvwU=AUD9XbvRzh4NDbiCX`mj{wR`!{a4J9`a--5WEq3%_qmA?nuN#G8%R7ike=
z?Jcf`aLv4f{M%1-4cuDQzuQ;}$wuY2+xQ9E6rak5AzF^zM`wQ!t%`;ne63px_-Iy2
z!o6lr$p9I1IazG%5jT#Vzdr=hN=@&0rIbIU_Q+sF#45qwV$SklB&}+uX9o!g{<ZSn
zf#JP>)%VMfcEY&?>eP-ml2Z+ZB9}*#xl=9LOz_r6#ExKDrCqK+-`M!jtgV*JSDr$C
zTcJDtdODghn$Ru_9m0dr?uyV<z;Y-dT!FOgn219fx?>t(pM=T>gVsZf1mM9-a_#~E
zrkb<4w&8#S2mOZQ6%@eFyYLpkdqWuy^c&x|R=L$vS~PH2>p8EoCXAMNE7_p=NUYv%
zZB$<P5F#0rQ4gX}TpeJ3rc)ZAamKbCLX`2)2pK8`F^|(#6cJ`bHYxIL)#)I0StaiJ
zKe70@%ZS@w{P#@*m&{cpL<oIbBB;p2g^~!R!|xCjV>TX*mkvK!N?jrjzhh>~qD>$?
za0A|x6P$kVMqo?`37iyR4bC2%<DOyJjZ18i9UzP03FQzxF>9kul8D})v^@zd49vxx
z$7t}>NR)tq-Lm5?%Mi=SzgYh}ia9)EPN#m(k8x7N3b@wKmzXySMRW{s@gnRnV$i3n
zhr_T|;~5#XiPxt%^r7cWr}M^52?GG*V|tYMO`Zta;>8W_Z{wK}m`Z@dPBKkBET*9x
zvL=ZKY^T$X4Vve=C|Rq>*tr_oTmqF|csGVL1p&i3Dkd)5wbQN8WoiHiD|*u<E)}Iq
zznq#U19Wx2BAE<j5<}rxk3o!RdaG^Cs<7X(XF13{KbCtf*eE~shNUm$alZVoGemU;
zNxEnhQbwS|5&6q;v!@v0!cr65@*?>^9Zo+FMXlg);x&a!X@ct54X&68ll;?5ECk3r
zetOwKOX4$c?epj1IkVwnXp)llS|+j~=PkEm9nNcbNXb0L(}Yn3Uz^PdGjJ--CKH5I
zGf@auee^`)a6qYx?&t*4Axs>f;T$f0SeNB#te1L8b6P@<dH5>F!DC6>p}kBmTXjfY
zdO)5@=I6J_g8}zTqDLqR-d=-$UnVtXIF$#CknyArAqHZ&j7U4UqybRUC?^Oa3;_jo
zfP=JyLz)c>{Lz3=91|u05+_<e08i^At!usXfh}1kPtihU25I@~quL^;f|$!i7(_=L
zB4?0{isy~1kIuFHQJ+zRg+w%e^K25<h~+%tMV5@{+p$bSz9sNvT5>_Xg7M%}Z8LL_
zF0m;m^Lylumy+UXAP(owJ2esA)DPZM7{@z7I3kH6S738B22q7l?jl2()I+?D1gCin
zB&LBs`klj>5w8b>D$c(&B-r&H+E~>E0m0d6Ff?<LNc=PL3sJ|acK%%uFja|fssXy+
z@Nn_}M?t{r<B7WuULQ;P*|3x}C0+yRS7%p8#dZ;Wiex<3gWhAHFJo0vnv<WK9LNc>
zZK7!7jtO`nAv_cZrwCsx$4G~#%#0OHvg^R<byi6VNrl+9S>q?VS}`CFPi2zMa1{)L
z#re#oi#4C_i%@)-uc-JE1YbAvt5gqzoA`kuM+|IUb9MPt{OYo>`S*ekgTxE6AMnfc
z5nAF2+6*x|a7IuzfF?idh7|jaBSLpVvnP^Lz)6<GG3aaGMy8Pr)&kNRF~J#!Sx%00
z)z>psNj!nf3^?f&MGH~WzK&NnTS`W(?Q}R1idZ)i)eLXd)+nxq@E9Jx9QKiH+Bah2
zDVmfg$*gmqG9NWDBqkKSh<w6ERFKl7Jn&g!ehj`-mC$!>PIzhqviCFATx`GAbkaN{
z5E{2MNtp*s%?&Lb&ZQgBjfR7vBwq1O;vo3&QX&)RJ$p36r3O5olcn*q=f8#93YHB7
zLqH3zV{QnidsgO5T-pyGAtG0$c?#kRYCp!+*XKfNAtlvpr9OtgjvUE)0_w0(jAv{>
zxk>fr`dv{PFzJt=MI+CGuIyzyy;q1G;zyw)G7jgM2)pWxCT4kv8*x|1J#q%BF#F;`
znqkWen@zLMqAlTCMj!$Ocv+LG3om^uYO#ajUjru*JEE?~ZU3Sqa{c>+`WS027Lfx(
z&Z>R&89U)Puqa3VMBTrTa8@-YM5n+^zLd??T-;>&NP7Ses%U1pbH{%0@*OrC%w4ja
zfN=I+>Eu7K#1JG<j7tc$fSSj2@=`_?gV?)3a&u>JyHbqKobY#to)#uW7~g2pVBix{
zih!+Q0oV4`gcl8XQr{6bOP_gjzQhikvIl;!otLe<#^3JCjgHixB+i9Yone0TR#kEV
z(CxBwd)S!_@b7IL_)wt1skYuJKRJqMt{E~Wza5@$h-Bv(Nk;~!%}%=<RdIPL+xDis
znQ6YvusFvAndtBpg5HF7mdXlyhHx;9A_Zk1SuH6%Om`NtqmLRCrs77IBaj_iea>Fk
zj;$Ny9)n2Poc1tzg~o!?B9azVfidfn1|i626&j_8v^cYT1BYNY<Uw)IK)HO;mNaG$
zBO<CNDNn<njQ+%MT!Oijv)f(jw>nw?UDFHjTn>siUJDt_d#zOyOR?+`?#IHa9Ab#3
zG{q-rEz9;H4LLbY#>d4gXBrPVQf5RIX@uykdXe2JVp7S>Jyn2=pmf}oWf@MTFrdj*
zeeJ2oTZgR|i?HLkbu7kYa8hjMALpCG;$p?_m0O!z`7zV?At-dqjoG;M6VVS4*vPSm
zgg|{n^h0I<X7JV~Xt72j3u<w)wftHrs;E38?Es1-33j@2{KeT*k3l8hZ<~d-*R~<;
z-%mKGvDi8SpVzVvP;~v{4`h@HF*IjgxW37>ukHP<we7WgF93A^9=>h)*#bcahWiu>
zn9f^-TUf*e>0u-inmTo!X;P!M{`J1gDI$mC;a-LTKxR-O?v|bTxicMA@%^?Ccn#%n
zSp<;KMV}e@sP19Ld1;xYTbnj#-EA>dB?wNid$ID~yUIsf&O~^(^3%=D_dovN-T)Eh
z$>*c~$M65NxB0;bAAR@%{&#q9>*M$J*>>;4;={rA=7;w_+`@l9{qTeB&5!P})b{2F
z1AhDH{f|EQ2;cF(_~_n8fbh}wNB2<U;|~jz{Q&hp{^<P=Kl*4JCEow=gL~WC#YdYT
zeT)`=it_ii3t-B5vD-3Aw%&W!aR<sbp47G8uD<tfl)QlBGTCi@et3X#rsv#jf3^DS
zU;XI!{^*@QdWWC?_~MWE?tJ&}|K)%Fy?5T>fB!(9>OcS6|H!{G7|7cMmH85ewY2iT
zd;Z6J|KY#<tAFzp75U#ktW^Fdf6pt2xm&CMFQ$L8_s^gH>wo*7P?!JxVWs~6@?)=W
zgsIiuKK+xuKmGo%Uj9|<NAK{ze^jaczyAGN?GUN_>tFr&zhlwg$N&B>{QW=f{s{m6
zv;UpX@cH5U|31;;e)#_R!<_@zZLm|GpCdnINE&t!{Ha4y6RO=<bjkz!(kU_B@Oyqh
zi9S2Wjg7Mdq2~|ZzgMw&{_sD4|Btnoi<;;U-~XX=hNpe|;rrhw!~O96j}_W^d7l5@
Dq5~IP

diff --git a/examples/example_simplest/instructor/cs101/__pycache__/deploy.cpython-38.pyc b/examples/example_simplest/instructor/cs101/__pycache__/deploy.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6e14e2ac2aed2a082d17689ac69828e53aeba409
GIT binary patch
literal 911
zcmZWnO>fjN5Ve!+Ci~TvqG~T3I3X>EEZYi!5JE^)9612JSOF`IXS?nuaj+fQjS&B!
zC$1dYBY!DZPW*+Qm}JXGTRR!O@pwGr_k1uK^$CtIcf<IbOUTd0`G5H6yu{y}qY*^V
zlw_1q+F&PjGMBk6c2h6wuuhA;w9C2}_fntv;2#I)J?LLhHh`h%EFJwFT%e+RHT^Tp
zg3fUV1|k>}w7oGAeK8P2F*<U^#+iqwZtjy0_t*%!=Nq_VtKD}8?PyFc97;ZY72Z2C
z+5UxHk_oN-w@@f;X9&jzY+3Ll9Sh)dnF7~s3`2p*Wx<8iZ|Z>aES5RvuO}YsW-^!a
z73-<Pd1;c^0^Z{kk`jS;SjnR5O~Y`SnAxLQwbMZSj4cJ^)~uJ`*8|RrRT3u);Jor5
zhE^>huX+NCRIS2dg?0Kyl{$f@0~QD{wnaNh3USUGU*@ru3NdcL4w4j0Ox)_}x*}RQ
zjk5x;G}mzkCrU4;GB;M2iB-C7WOuqy>&OgiR*!FG3Y9ED-%Q)Pp7!Kc+B}Wz&7@ho
zc&*;(+BuhWI@x5SmbY-N!c04;7<*9W(yk>cwET>W?}iI0kWijzK(|%SXndlC`HgG^
zXzev#*DOja)7nv{_KMgpY9Hy!k&i~yR&dUo6VZ6hD(5ww*IuHE)eoXK@rc%3eth*T
zIxwJ3WXlCa`zk53M$hP0Yta?!<`3XTHYyk!{bN6BZyEiSyAGabN|Y(QpjgsuqZ!g>
PZqcC=&~5j=8@Rs#9|je(

literal 0
HcmV?d00001

diff --git a/examples/example_simplest/instructor/cs101/__pycache__/report1_grade.cpython-38.pyc b/examples/example_simplest/instructor/cs101/__pycache__/report1_grade.cpython-38.pyc
index 3b0930bdcddcda845eef8dfac07d6ab732a2473f..aed06f7cf667b51f32903bf52b3c17138bda2777 100644
GIT binary patch
delta 2862
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
Mx6{1|g8yFkKk?5%NdN!<

delta 7319
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
V_b+p#1V<c(=d1SZp>_Y%{{I@N9*O_}

diff --git a/examples/example_simplest/instructor/cs101/deploy.py b/examples/example_simplest/instructor/cs101/deploy.py
index 3e9682d..b51f79c 100644
--- a/examples/example_simplest/instructor/cs101/deploy.py
+++ b/examples/example_simplest/instructor/cs101/deploy.py
@@ -1,16 +1,19 @@
-from report1 import Report1
+from cs101.report1 import Report1
 from unitgrade_private2.hidden_create_files import setup_grade_file_report
 from snipper import snip_dir
-import shutil
+import shutil, os
+wd = os.path.dirname(__file__)
 
 if __name__ == "__main__":
-    setup_grade_file_report(Report1, minify=False, obfuscate=False, execute=False)
+    setup_grade_file_report(Report1, minify=False, obfuscate=False, execute=False, bzip=False)
 
     # Deploy the files using snipper: https://gitlab.compute.dtu.dk/tuhe/snipper
-    snip_dir.snip_dir(source_dir="../cs101", dest_dir="../../students/cs101", clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py'])
+    snip_dir.snip_dir(source_dir=wd+"/../cs101", dest_dir=wd+"/../../students/cs101", clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py'])
 
-    # For my own sake, copy the homework to the other examples.
-    for f in ['../../../example_framework/instructor/cs102/homework1.py', '../../../example_docker/instructor/cs103/homework1.py']:
-        shutil.copy('homework1.py', f)
+    # For my own sake, copy the homework file to the other examples.
+    for f in ['../../../example_framework/instructor/cs102/homework1.py',
+              '../../../example_docker/instructor/cs103/homework1.py',
+              '../../../example_flat/instructor/cs101flat/homework1.py']:
+        shutil.copy(wd+'/homework1.py', wd+"/"+f)
 
 
diff --git a/examples/example_simplest/instructor/cs101/report1.py b/examples/example_simplest/instructor/cs101/report1.py
index e00853f..447cedb 100644
--- a/examples/example_simplest/instructor/cs101/report1.py
+++ b/examples/example_simplest/instructor/cs101/report1.py
@@ -1,5 +1,5 @@
-from unitgrade2.unitgrade2 import Report
-from unitgrade2.unitgrade_helpers2 import evaluate_report_student
+from src.unitgrade2.unitgrade2 import Report
+from src.unitgrade2 import evaluate_report_student
 from cs101.homework1 import reverse_list, add
 import unittest
 
diff --git a/examples/example_simplest/instructor/cs101/report1_grade.py b/examples/example_simplest/instructor/cs101/report1_grade.py
index 8972ab5..7f2feaa 100644
--- a/examples/example_simplest/instructor/cs101/report1_grade.py
+++ b/examples/example_simplest/instructor/cs101/report1_grade.py
@@ -4,14 +4,10 @@ from tabulate import tabulate
 from datetime import datetime
 import pyfiglet
 import unittest
-
 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: 
@@ -61,53 +57,6 @@ def evaluate_report_student(report, question=None, qitem=None, unmute=None, pass
                                           show_tol_err=show_tol_err)
 
 
-    # try:  # For registering stats.
-    #     import unitgrade_private
-    #     import irlc.lectures
-    #     import xlwings
-    #     from openpyxl import Workbook
-    #     import pandas as pd
-    #     from collections import defaultdict
-    #     dd = defaultdict(lambda: [])
-    #     error_computed = []
-    #     for k1, (q, _) in enumerate(report.questions):
-    #         for k2, item in enumerate(q.items):
-    #             dd['question_index'].append(k1)
-    #             dd['item_index'].append(k2)
-    #             dd['question'].append(q.name)
-    #             dd['item'].append(item.name)
-    #             dd['tol'].append(0 if not hasattr(item, 'tol') else item.tol)
-    #             error_computed.append(0 if not hasattr(item, 'error_computed') else item.error_computed)
-    #
-    #     qstats = report.wdir + "/" + report.name + ".xlsx"
-    #
-    #     if os.path.isfile(qstats):
-    #         d_read = pd.read_excel(qstats).to_dict()
-    #     else:
-    #         d_read = dict()
-    #
-    #     for k in range(1000):
-    #         key = 'run_'+str(k)
-    #         if key in d_read:
-    #             dd[key] = list(d_read['run_0'].values())
-    #         else:
-    #             dd[key] = error_computed
-    #             break
-    #
-    #     workbook = Workbook()
-    #     worksheet = workbook.active
-    #     for col, key in enumerate(dd.keys()):
-    #         worksheet.cell(row=1, column=col+1).value = key
-    #         for row, item in enumerate(dd[key]):
-    #             worksheet.cell(row=row+2, column=col+1).value = item
-    #
-    #     workbook.save(qstats)
-    #     workbook.close()
-    #
-    # except ModuleNotFoundError as e:
-    #     s = 234
-    #     pass
-
     if question is None:
         print("Provisional evaluation")
         tabulate(table_data)
@@ -159,24 +108,20 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         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)
@@ -186,104 +131,28 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         q.possible = 0
         q.obtained = 0
         q_ = {} # Gather score in this class.
-        # unittest.Te
-        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
         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)
-        # res = UTextTestRunner(verbosity=2, resultclass=unittest.TextTestResult).run(suite)
-        z = 234
-        # for j, item in enumerate(q.items):
-        #     if qitem is not None and question is not None and j+1 != qitem:
-        #         continue
-        #
-        #     if q_with_outstanding_init is not None: # check for None bc. this must be called to set titles.
-        #         # if not item.question.has_called_init_:
-        #         start = time.time()
-        #
-        #         cc = None
-        #         if show_progress_bar:
-        #             total_estimated_time = q.estimated_time # Use this. The time is estimated for the q itself.  # sum( [q2.estimated_time for q2 in q_with_outstanding_init] )
-        #             cc = ActiveProgress(t=total_estimated_time, title=q_title_print)
-        #         from unitgrade import Capturing # DON'T REMOVE THIS LINE
-        #         with eval('Capturing')(unmute=unmute):  # Clunky import syntax is required bc. of minify issue.
-        #             try:
-        #                 for q2 in q_with_outstanding_init:
-        #                     q2.init()
-        #                     q2.has_called_init_ = True
-        #
-        #                 # item.question.init()  # Initialize the question. Useful for sharing resources.
-        #             except Exception as e:
-        #                 if not passall:
-        #                     if not silent:
-        #                         print(" ")
-        #                         print("="*30)
-        #                         print(f"When initializing question {q.title} the initialization code threw an error")
-        #                         print(e)
-        #                         print("The remaining parts of this question will likely fail.")
-        #                         print("="*30)
-        #
-        #         if show_progress_bar:
-        #             cc.terminate()
-        #             sys.stdout.flush()
-        #             print(q_title_print, end="")
-        #
-        #         q_time =np.round(  time.time()-start, 2)
-        #
-        #         print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")
-        #         print("=" * nL)
-        #         q_with_outstanding_init = None
-        #
-        #     # item.question = q # Set the parent question instance for later reference.
-        #     item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)
-        #
-        #     if show_progress_bar:
-        #         cc = ActiveProgress(t=item.estimated_time, title=item_title_print)
-        #     else:
-        #         print(item_title_print + ( '.'*max(0, nL-4-len(ss)) ), end="")
-        #     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)
-        #     if show_progress_bar:
-        #         cc.terminate()
-        #         sys.stdout.flush()
-        #         print(item_title_print + ('.' * max(0, nL - 4 - len(ss))), end="")
-        #
-        #     if not hidden:
-        #         ss = "PASS" if current == possible else "*** FAILED"
-        #         if tsecs >= 0.1:
-        #             ss += " ("+ str(tsecs) + " seconds)"
-        #         print(ss)
-
-        # ws, possible, obtained = upack(q_)
 
         possible = res.testsRun
         obtained = len(res.successes)
 
         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"Question {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) )
@@ -298,15 +167,16 @@ 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") +")")
+    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
 
 
-
-
 from tabulate import tabulate
 from datetime import datetime
 import inspect
@@ -329,7 +199,8 @@ def gather_imports(imp):
     # dn = os.path.dirname(f)
     # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
     # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
-    if m.__class__.__name__ == 'module' and False:
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
         top_package = os.path.dirname(m.__file__)
         module_import = True
     else:
@@ -350,7 +221,7 @@ def gather_imports(imp):
             for file in files:
                 if file.endswith(".py"):
                     fpath = os.path.join(root, file)
-                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
                     zip.write(fpath, v)
 
     resources['zipfile'] = zip_buffer.getvalue()
@@ -394,14 +265,14 @@ def gather_upload_to_campusnet(report, output_dir=None):
     results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
                                           show_progress_bar=not args.noprogress,
                                           big_header=not args.autolab)
-    print(" ")
-    print("="*n)
-    print("Final evaluation")
-    print(tabulate(table_data))
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
     # also load the source code of missing files...
 
     sources = {}
-
+    print("")
     if not args.autolab:
         if len(report.individual_imports) > 0:
             print("By uploading the .token file, you verify the files:")
@@ -414,12 +285,15 @@ def gather_upload_to_campusnet(report, output_dir=None):
             print("Including files in upload...")
             for k, m in enumerate(report.pack_imports):
                 nimp, top_package = gather_imports(m)
-                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
                 nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
                 nimp['name'] = m.__name__
                 sources[k] = nimp
                 # if len([k for k in nimp if k not in sources]) > 0:
-                print(f"*** {m.__name__}")
+                print(f" * {m.__name__}")
                 # sources = {**sources, **nimp}
     results['sources'] = sources
 
@@ -438,9 +312,9 @@ def gather_upload_to_campusnet(report, output_dir=None):
 
     if not args.autolab:
         print(" ")
-        print("To get credit for your results, please upload the single file: ")
+        print("To get credit for your results, please upload the single unmodified file: ")
         print(">", token)
-        print("To campusnet without any modifications.")
+        # print("To campusnet without any modifications.")
 
         # print("Now time for some autolab fun")
 
@@ -453,7 +327,7 @@ def source_instantiate(name, report1_source, payload):
 
 
 
-report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, unmute=False, **kwargs):\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n            # for item in q.items:\n            #     if q.name not in payloads or item.name not in payloads[q.name]:\n            #         s = f"> Broken resource dictionary submitted to unitgrade for question {q.name} and subquestion {item.name}. Framework will not work."\n            #         if strict:\n            #             raise Exception(s)\n            #         else:\n            #             print(s)\n            #     else:\n            #         item._correct_answer_payload = payloads[q.name][item.name][\'payload\']\n            #         item.estimated_time = payloads[q.name][item.name].get("time", 1)\n            #         q.estimated_time = payloads[q.name].get("time", 1)\n            #         if "precomputed" in payloads[q.name][item.name]: # Consider removing later.\n            #             item._precomputed_payload = payloads[q.name][item.name][\'precomputed\']\n            #         try:\n            #             if "title" in payloads[q.name][item.name]: # can perhaps be removed later.\n            #                 item.title = payloads[q.name][item.name][\'title\']\n            #         except Exception as e: # Cannot set attribute error. The title is a function (and probably should not be).\n            #             pass\n            #             # print("bad", e)\n        # self.payloads = payloads\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\nclass MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n    pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        item_title = item_title.split("\\n")[0]\n\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 2\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    @classmethod\n    def question_title(cls):\n        return cls.__doc__.splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    # def _callSetUp(self):\n    #     # Always run before method is called.\n    #     print("asdf")\n    #     pass\n    # @classmethod\n    # def setUpClass(cls):\n    #     # self._cache_put((self.cache_id(), \'title\'), value)\n    #     cls.reset()\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    # def unique_cache_id(self):\n    #     k0 = self.cache_id()\n    #     # key = ()\n    #     i = 0\n    #     for i in itertools.count():\n    #         # key = k0 + (i,)\n    #         if i not in self._cache_get( (k0, \'assert\') ):\n    #             break\n    #     return i\n    #     return key\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n    #\n    # def _cache2_contains(self, key):\n    #     print("Is this needed?")\n    #     self._ensure_cache_exists()\n    #     return key in self.__class__._cache2\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    # try:  # For registering stats.\n    #     import unitgrade_private\n    #     import irlc.lectures\n    #     import xlwings\n    #     from openpyxl import Workbook\n    #     import pandas as pd\n    #     from collections import defaultdict\n    #     dd = defaultdict(lambda: [])\n    #     error_computed = []\n    #     for k1, (q, _) in enumerate(report.questions):\n    #         for k2, item in enumerate(q.items):\n    #             dd[\'question_index\'].append(k1)\n    #             dd[\'item_index\'].append(k2)\n    #             dd[\'question\'].append(q.name)\n    #             dd[\'item\'].append(item.name)\n    #             dd[\'tol\'].append(0 if not hasattr(item, \'tol\') else item.tol)\n    #             error_computed.append(0 if not hasattr(item, \'error_computed\') else item.error_computed)\n    #\n    #     qstats = report.wdir + "/" + report.name + ".xlsx"\n    #\n    #     if os.path.isfile(qstats):\n    #         d_read = pd.read_excel(qstats).to_dict()\n    #     else:\n    #         d_read = dict()\n    #\n    #     for k in range(1000):\n    #         key = \'run_\'+str(k)\n    #         if key in d_read:\n    #             dd[key] = list(d_read[\'run_0\'].values())\n    #         else:\n    #             dd[key] = error_computed\n    #             break\n    #\n    #     workbook = Workbook()\n    #     worksheet = workbook.active\n    #     for col, key in enumerate(dd.keys()):\n    #         worksheet.cell(row=1, column=col+1).value = key\n    #         for row, item in enumerate(dd[key]):\n    #             worksheet.cell(row=row+2, column=col+1).value = item\n    #\n    #     workbook.save(qstats)\n    #     workbook.close()\n    #\n    # except ModuleNotFoundError as e:\n    #     s = 234\n    #     pass\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n        # res = UTextTestRunner(verbosity=2, resultclass=unittest.TextTestResult).run(suite)\n        z = 234\n        # for j, item in enumerate(q.items):\n        #     if qitem is not None and question is not None and j+1 != qitem:\n        #         continue\n        #\n        #     if q_with_outstanding_init is not None: # check for None bc. this must be called to set titles.\n        #         # if not item.question.has_called_init_:\n        #         start = time.time()\n        #\n        #         cc = None\n        #         if show_progress_bar:\n        #             total_estimated_time = q.estimated_time # Use this. The time is estimated for the q itself.  # sum( [q2.estimated_time for q2 in q_with_outstanding_init] )\n        #             cc = ActiveProgress(t=total_estimated_time, title=q_title_print)\n        #         from unitgrade import Capturing # DON\'T REMOVE THIS LINE\n        #         with eval(\'Capturing\')(unmute=unmute):  # Clunky import syntax is required bc. of minify issue.\n        #             try:\n        #                 for q2 in q_with_outstanding_init:\n        #                     q2.init()\n        #                     q2.has_called_init_ = True\n        #\n        #                 # item.question.init()  # Initialize the question. Useful for sharing resources.\n        #             except Exception as e:\n        #                 if not passall:\n        #                     if not silent:\n        #                         print(" ")\n        #                         print("="*30)\n        #                         print(f"When initializing question {q.title} the initialization code threw an error")\n        #                         print(e)\n        #                         print("The remaining parts of this question will likely fail.")\n        #                         print("="*30)\n        #\n        #         if show_progress_bar:\n        #             cc.terminate()\n        #             sys.stdout.flush()\n        #             print(q_title_print, end="")\n        #\n        #         q_time =np.round(  time.time()-start, 2)\n        #\n        #         print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")\n        #         print("=" * nL)\n        #         q_with_outstanding_init = None\n        #\n        #     # item.question = q # Set the parent question instance for later reference.\n        #     item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)\n        #\n        #     if show_progress_bar:\n        #         cc = ActiveProgress(t=item.estimated_time, title=item_title_print)\n        #     else:\n        #         print(item_title_print + ( \'.\'*max(0, nL-4-len(ss)) ), end="")\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        #     if show_progress_bar:\n        #         cc.terminate()\n        #         sys.stdout.flush()\n        #         print(item_title_print + (\'.\' * max(0, nL - 4 - len(ss))), end="")\n        #\n        #     if not hidden:\n        #         ss = "PASS" if current == possible else "*** FAILED"\n        #         if tsecs >= 0.1:\n        #             ss += " ("+ str(tsecs) + " seconds)"\n        #         print(ss)\n\n        # ws, possible, obtained = upack(q_)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nfrom cs101.homework1 import reverse_list, add\nimport unittest\n\nclass Week1(unittest.TestCase):\n    def test_add(self):\n        self.assertEqual(add(2,2), 4)\n        self.assertEqual(add(-100, 5), -95)\n\n    def test_reverse(self):\n        self.assertEqual(reverse_list([1,2,3]), [3,2,1])\n        # print("Bad output\\n\\n")\n\n\nimport cs101\nclass Report1(Report):\n    title = "CS 101 Report 1"\n    questions = [(Week1, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs101]'
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"Question {n+1} total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nfrom cs101.homework1 import reverse_list, add\nimport unittest\n\nclass Week1(unittest.TestCase):\n    def test_add(self):\n        self.assertEqual(add(2,2), 4)\n        self.assertEqual(add(-100, 5), -95)\n\n    def test_reverse(self):\n        self.assertEqual(reverse_list([1,2,3]), [3,2,1])\n\n\nimport cs101\nclass Report1(Report):\n    title = "CS 101 Report 1"\n    questions = [(Week1, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs101]'
 report1_payload = '8004953f000000000000007d948c055765656b31947d948c2c6e6f20636163686520736565205f73657475705f616e737765727320696e20756e69746772616465322e7079948873732e'
 name="Report1"
 
diff --git a/examples/example_simplest/students/cs101/Report1_handin_0_of_10.token b/examples/example_simplest/students/cs101/Report1_handin_0_of_10.token
deleted file mode 100644
index 5ccd4e5495ad2bbfe4c3cc09832916b356f0d31b..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 77002
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
ATmS$7

diff --git a/examples/example_simplest/students/cs101/__pycache__/deploy.cpython-38.pyc b/examples/example_simplest/students/cs101/__pycache__/deploy.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6e14e2ac2aed2a082d17689ac69828e53aeba409
GIT binary patch
literal 911
zcmZWnO>fjN5Ve!+Ci~TvqG~T3I3X>EEZYi!5JE^)9612JSOF`IXS?nuaj+fQjS&B!
zC$1dYBY!DZPW*+Qm}JXGTRR!O@pwGr_k1uK^$CtIcf<IbOUTd0`G5H6yu{y}qY*^V
zlw_1q+F&PjGMBk6c2h6wuuhA;w9C2}_fntv;2#I)J?LLhHh`h%EFJwFT%e+RHT^Tp
zg3fUV1|k>}w7oGAeK8P2F*<U^#+iqwZtjy0_t*%!=Nq_VtKD}8?PyFc97;ZY72Z2C
z+5UxHk_oN-w@@f;X9&jzY+3Ll9Sh)dnF7~s3`2p*Wx<8iZ|Z>aES5RvuO}YsW-^!a
z73-<Pd1;c^0^Z{kk`jS;SjnR5O~Y`SnAxLQwbMZSj4cJ^)~uJ`*8|RrRT3u);Jor5
zhE^>huX+NCRIS2dg?0Kyl{$f@0~QD{wnaNh3USUGU*@ru3NdcL4w4j0Ox)_}x*}RQ
zjk5x;G}mzkCrU4;GB;M2iB-C7WOuqy>&OgiR*!FG3Y9ED-%Q)Pp7!Kc+B}Wz&7@ho
zc&*;(+BuhWI@x5SmbY-N!c04;7<*9W(yk>cwET>W?}iI0kWijzK(|%SXndlC`HgG^
zXzev#*DOja)7nv{_KMgpY9Hy!k&i~yR&dUo6VZ6hD(5ww*IuHE)eoXK@rc%3eth*T
zIxwJ3WXlCa`zk53M$hP0Yta?!<`3XTHYyk!{bN6BZyEiSyAGabN|Y(QpjgsuqZ!g>
PZqcC=&~5j=8@Rs#9|je(

literal 0
HcmV?d00001

diff --git a/examples/example_simplest/students/cs101/__pycache__/homework1.cpython-38.pyc b/examples/example_simplest/students/cs101/__pycache__/homework1.cpython-38.pyc
index 1149b3ace2379ce11502c3e4633382e7f8d4950a..7dbbdac7ae33a6d3d1764a740a5f47ff3e00b252 100644
GIT binary patch
delta 374
zcmYk0y-EW?5XWcczSc8ICE6%xA##Pig;*G|5iI;@(i~@Ik;8oG-bGLXDb5#=EhQj!
zK8J5{rSBkum9rNM2WEEmzw`gienuZ*=d#_7LE`IdCp)F*&id?FZVZf1&;us+<U~#E
z-;g=f9tRpZ<glU_m{WxaqD2}+Q@q6SwO?UH2)uj_Nvn^J{THtHB)gJDOG*hPPC@2T
zX7TYY-juMbINwgF_6K=U*2?I6Z3@i^_QK(V)84^2%1>s$@hHwmMQJAea%^muw%Tq-
zK~f+vfxV-Rj*@-~Q(ObL#J-Z=b#~c+S&df>Yf*fWYcFGVmIcH!%I<j=C%y?pGwz{Q
mX*$Y=I!)`~*5sq|AHji5gHij#F;52ip!tyVsYnHiR`3_qMNBUM

delta 534
zcmZWmJ#W-N5Zzh(d_I$lL<ph*X{pdjfRG|lAsUh(D6Szi*H|0R-encri+0zDOA`sx
zrAk~P8bp(yfGG1XT+&d}regLIQNT#EGxO%_jrJn>Ib44`9%qc?_r*i`G&)_sd;FRr
zWHW|<{1cl2Mi`UjD#F1bx4SCFL~$JAu;riG7v2Ie!cql<jWEL-i@1fB1H-j9Y%)Gt
zWIG>Z^{!OH`36<(MPX1q7JCQUiMb}6tZclgq}Ro<EX$=>s9IU+6^gkvmGB2@Rq2GT
zSAnjbw@u-VeT3So;4HHO!X?)dd`|j;)UDCu>7o`s(pAJNI{KOkl9&3us)ZD#c3wQF
zmZd)Zak71R=T+ca1+Md^F1$9i*f+SGo<o0YYW&}{!X0akoxm&!&CZ`Q8`HAOygP*L
z^!i}eeTVzwfV)76B{u1P!M%<DX>}W1Z3XI68!9Kf2ie2^YUb55Ah?etVrae^7u!+y
ujqlwY^us(yQ{=f#C}~G$(d{Q;>%Z;kv&vvos^?*o3;!QSX__V}--JIUYKDLS

diff --git a/examples/example_simplest/students/cs101/__pycache__/report1.cpython-38.pyc b/examples/example_simplest/students/cs101/__pycache__/report1.cpython-38.pyc
index d7c0fcd96cc7cec28f9155fb61bec8c3bb6e00df..83e9e30d8000e629914b0160acf822078d8a3b78 100644
GIT binary patch
delta 163
zcmdnVd4`iOl$V!_0SF3D>Lk8k+Q>JXk+Ep<Dn?_|#L|-doW!K~)QZI1f}B)+Jw1IW
zGrl+zBvM?WpP5%&QdF8;l3%2sTx@7ysK5C?<8nsfTbzZZK<Ui<yy9D|V2N9kcQUIn
z3QT^$EYEmr5=)fyEsoN>%#sqIs#_c(K+-v}IJJlk=#C<($)zl|?3^5o0<0X&0RDJ3
Ag8%>k

delta 176
zcmX@Zxs#JGl$V!_0SN9M)=A`M-pDtbkuiSqDn?_a)QZI1f}GU&;!F@#ToRL+S6ot5
znp~1!6q8(RXkZw#S%_&lqi_^wVJT2LGe58R7AsgHYVsLoH6=lyp~Y-Kf`gHTk&CfN
z49L925g(tMn3)$JugM!FI@y3lWU>Z}t8^4cX<lYY3DA@%ju0T}oLHP%1kze0Ik|(y
NmYs`(QGk_$8302FF&+Q_

diff --git a/examples/example_simplest/students/cs101/__pycache__/report1_grade.cpython-38.pyc b/examples/example_simplest/students/cs101/__pycache__/report1_grade.cpython-38.pyc
index 0aeda2d66a25eaae02e31a9c629a9a2887fb7dbd..aed06f7cf667b51f32903bf52b3c17138bda2777 100644
GIT binary patch
delta 3389
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
QmF?JWv%?1snMJ<xKk62%OaK4?

delta 7949
zcmahuZEPDycDocsQ?w-OizfADjYvr(Wr>!Q7`Ym8Vq38jBaZT6C%I5o*%fCgt+d>w
zc9)jrEW_AxeEB##K2ICeNe(9gL6Qp!v<>^GP41FhalN+4H9hoC>o!TR{nG@vYlA~u
z;LvOP-YhAuEID35vpX|y-uJwD^Z3?>b$|G)x?PVqH3bBCzWVbKDH|2Pv#Y!GZ=xVj
zAtg|edQ>sxfp?u+m#a(Fi8$s}y*Y2n%fCHpeX5?r`BFaq-jUkD-~N=JzZ+5w{2fRI
z_<Lt+Cx17l8u_~^)g(78G}C(OgZD1F<8rAk)grenv{FB9klUz-2I$Vq^`gMX8fg=4
zrn@c!E4<$V{Z?1M4f^e_eh2h}PM=QD5Di}xQ|+{qc3l)w9rp{goAz83Xpih$2(H$p
zcEd<-iSB`+Juno4p)kFJ650>TI)UF?>!B)lSE`H4Rh7Rx)y?}osh*AT2#o^yUOGSr
z;k}2CgPtmSC=FE<QPo2XWQe<DN<e?OBGa98FC78q`sgT40y0APrTXbuDniFoQJKh5
zxnGWe7z46@VQ_6oj;)KSxZEcX$njMVn9y@lNbEm17dU!W%H>s=m{uV~Wz8ZPoytja
zYF;r(R)Gn{WWO8^kC3dP=ZG~g^HGy18t*8YX&Hr#r5mGEF=YH$36wiLy*@F+Cj9sL
z0WYF8*|YwrI8lDX|5%+k%Km$2OuVDq*XR|+=h#3~PF!Wzn*LFIk!j6Oi!YSFY<@`;
zudp*Mrg)is+0xrQ434@3{wLwzjIdzqUx=63KehgD2Mrhd>^%$JMPl{9yLVMA_OoZ(
z21~D4<br4u8eH^V6^%c!`t44;zeAv%9fD1|g;i1W&|ncqVchPuyJ^?!^>)w>-7P>r
zobIp*wC%Lp4$;<-@S5;lPccG!?C?UzYv3z(CyaQDQOjpX=pMTrs7F@CumJBUzDGKQ
zkYGncKu8oUAML@n-L@8?eKmwtWbBdlP-&n@iv3o<HDHrf5yT+;yPtpe12aOp9T*eR
z9hR^rt_#H`yJ^i&$+}o<0m#O+#&yB&2m`(1pgl<YyM*G9J!lV65IQUrW0d<|F%G;8
z*exM}4g!C1m>*j8Kri+f@5U&22Xqq-<D6meIBU=r7CKf%nCT4(yw{GsInO$Z1?*)#
zc98CU-BV213A-(e-ZjF$(Q!pwXFuuqRs9!Vg5lVo1%D*|4lC~N@r;V>wcQ_xGi*Ba
z3!emYiD5Psep1Y`H^T&AeiA<1l7r!tXDNN7&XCO;;yD)Ve9(6t9pDVhc20V{_p|SJ
z{@t#_5VTA$3=3kLXsoiAx_VE&17nI%6m6mCu{{eyu?|{s0Rq~h$C#k-Z`Cb$*XnT&
z6zHXO#d`2(AM`zIJE(VEr1hPk$_4*I1AYO7=UR7vgKypQ@<Oq}s$;|5eRDh3MdK<*
z)M5whrgcxTnfF@VV--Sx66SZ=4Qp+7v%PB_w&2p$r3+6A`-Mk^$AoVRwtuZ1EGSYx
zIG`8a4e+jqcYys-cmF=11#TSPir@AkUaP}RlQv%K>FW+(6_*0qn6t#Ls{-0}INj52
zi(sRssT;nWP7A7h?3B>}Iy69Y0xR|$ZoT18r!fGe)5am3ILv<B6AksjC(h(0Yd)R6
zQO`e&=h*-C4DXr8xgCbA;-v8`hn$nGGm=`6jUv0hw=Z}B28~PDd<&cBu(`sX?mgXh
z6wP=9`hw^cy>&is3;Uw?K*Q@WApIKV%KJX~wOAe^4|uu^TouG-H#R0Vt=L%X`N(fX
znO%xr6VI^Dfd}I+z;LQDFJ%_fN-nP(mT9O6iD->}Y$DiPW8WS~_>h0#^SyyV@htoK
zKzrvp4!i=*4RJB$)c}LT`}bJW;E3-$&R$^m4kpDHm^L^gzRf-!yePiG9v$l4y@sor
z4H;>Ur%k<JWMtzVc5!H5=SLuo>4$kiY{5T|@h*Hz|NBY#<Ds|e+0RD8%p93+S1j4E
zbX_$A4(CKS%Y&o;>S4jLA@<bRo9vg#=JH+RM?B@o{{P(Li6_dTQ}^sF5!VwXS=}Ij
zD2L&CDT!a^fq)BwM0rQa!mK9cWTNR7!sewFRhOtqD(knMoOagCxG@5K2PNV)$w88h
z+(V8S`l756*v4EBgen<J(KX3fA!cDVr&yLuiKUZ*rdV@^MB$79x=RJwL@@HSL#Ie2
zjpBmZ1Pa7iD<;V?1NdJK>&7BkR#cTsvJAasgbU1;Q-kdHQ={yoR1f=yRCm)REwI+r
zP)m(*jyKKHckM2L2vucN<(=LjJ2M@tOvYxmQ7e+*uqa4Q0x8q*mcJfl61Ge{f^d-$
zGG0pD0`F4twn#T)x)ma@eIySjx1P%vfWwH}{L@PharMr)L_Popp42r{p|Sxc&FN<p
zZH}lQosql+uN!(`-`OAft*=*Sjgu`ZWmg~QEY*y}u>$j!VyW^?Y;VhTMgqr{jd>|=
zl3Cf|9USkrtZ%Rnl)eEO(QQ0}^Rt!tua4{~q3R?J_n0YLM6xVHnFXa2*)VhilP;O?
z)sS=%iDU~J-zOxFj-NO5S!q^<Ei<ndRLcE(R!)4K&hwIKx=rFCQFiF3!HLMMM8Ub_
znoC51AvK$<n#Lt!AP}H(mW@flaxN{`m47yS%$Er8WDvKj1zwmm3*hCX5~k9M2?Fw=
zK!9~BQ{|VG6(1vSc9(bNml|1MwUPbJu#X*juAaSjzCXkXYbVGkxfA|XS&N%yB9UO}
z;_kL6$rKC&v(kfPoJ+!%J`A$|ITVPaQC!nt6WuhGSygrmOiYtqv7_wGVp25O-xu!^
z&2sxQ-69(+#n=<2-!4D;>|u{@!omE>cL&PvUpVPu58vY}AA0VD$i5g!VmK~ezVx=3
z1TBzdL&}2(#k0DeaH1ZL=A=0#6Gu5JgTNYFeE!}+<Po1J7*ElxxLH#;U~pCh*oV)P
z^1nR)sVGL-zhCbP9?D3Wc{x@CjS?lx$g4r$^rE~n6JV{c-c|m^i+?S$cTWXb`{iDi
zy4=COcXfC9+n3wL@`o=^c>vR^SGp@(B}xvf%hHNTjDiMk50O<SIoX=mDSBB(QdOBc
zPULJYht-H=(rm<GqB34}rYJd-QK91?;kt_w)C2hR<M~OPif2?a(d1~zSsi5`v(avz
z3b>I1ToR52h<N24*CxHdG9m)Uf*7CXibyNety%}$;utstcbp9vH`XWtO#wvQJ*dFI
zScO|O3O^b#*n#gl2W>L5pclYQ6)QTV9Q!%=fb3opS4P}uaUMdbQaw32R~6PVl9Tx2
z*a(S%Qh-V<L8{2vNAvA52RXKeY!wXP#l>J{2uL&W$<Ff3D-YH^&KI~;?hu+tXLQYy
z;4a2hHG<+->EMcr`$dkMaAyOfYqCsbdT-UdtcekygOru7$KjUt*7a-6?9(5I%J$pG
z17H-(SUG@hd<>3dL!MJiP#H#j(~>OH?L3tjuyK&5!JE#&(cluR0-_jdCaJ=Ou>khp
zI(=4M1_FHIAs~zok2!i?*77T7)oQeP5>EJ8U0>XaArC=Qf-q{5Jax^oC#`|gh|WPu
zDYymroK#RPOiSXbl$)i}0Wv+~wlWXUpk?QbgeB9?d0*iS)Ur4}LgGs!B+VXqf5>%8
zp_?sEjBI3KvR25+2B;)n$;UPs3K_$P(&<<=%}Fa7mCwdzk{Ek58ebfDbLPN1D=^pK
z&?Ptc#I3-q1Zt?AMC(@Yh`t7kJ$}q?176|+Sh`vRAH!XOC*Qne;=vck^{_DzC_!Y^
zgaZUILVp{C&I!3;fT}8Pg|xKUUYiJPo~qDtImi-sYA~^ryeF5Tt^wOVvM&N{WsIlF
zFqS;4nrEH-GU`I1u)tHTB?r+K^U|~-OXziZ3ZYM;Y58nMR^t_DkU!1+(5(d2jysrg
z52>PYL%Vp$meBDqz8R7>C&$Of#>Ter;)JyroDAvMUMS?m7u{r$3>Xc80FA@<&1`U1
zC_kA%Bo!h<+yR_!=V-^k19;Ro<B3E7lJD?HEv{}}yxB00C>SOAmBy`J%<6H^1HtO{
z-xTR_-kg^q!#YT+ut^D0sWa|4gc~!Xt2|hue6@{9X%b{chPkwuwN;-D)Jd?J8aMRi
zgRt)bO(CZpgxB8jgd;AH1{^MXAO<7}OSTIJu;BrIW{ZVjRf!A11*%a6G<zYcY)=_C
zl0(|Xz=kGF=?nxP?&WT4Z_H;@-IS{e1q4SiR-%*UE%Fer6-?>YF*qsdQA}Gg!fx_T
zy!B1oai@zk=Aq>e-fd}Omrwg4Ir-KHW9*6*X6H|LOrLW>qmG<A>%w+A+8i()U~Iuh
zmr!KPXE4G{>6(mpMfTbIU7>}&<D~zf1K>C>U&tDN(8WUMT0D?jJ@doPZ@QM^1qU*)
z%p$iJM>d;DIwxnYU|M*0aMC8cvtlC8bN0$PSYykf^WG1K*dLq>)N>zV|FtrH2*)!S
z5F1f*EpbR}_ygiVioXm;r#=T~qnVzS3>W8w=@+8Pmg`@XJPsigkN4_50xp^$)y6H6
zOM~^>B?z=UOF?Cug<PCWFHPKhn?zS#nt*))+6gz$5XV!HzbIj^tUl<vm)3U2#;w4)
z#8*!GNhuG9Jf;g#a^J&Ku~X!+qYpj&#8GnUf#WC1iQ`j8w^72fV$Bm7B1b&7u|AfF
z7qlGQmkt)RDSRh*QZlI)v_%L}yuL%s7086nqU46WRDhB+C1^bz(sV^rvH)kA1-W)>
za=3@9Ww5&@h+_z6!)|DST}y@8l{tSqXbVt5o>=3Xou3POmL}MLoa|(~&V?7N2pom+
zgROenR@R~-j{_D(Qk8RPI5145;E_aAW(z8}m^m+T-BpVxTilF&btLAiNYOGm0NV?A
zVRui4*z2igcIDkh_P3M1<_M`|dz>S7{@qR-ZjBs_4Bs)fNf18M^cYIWc|*fhIm1#6
zcXp^w1H&6I60g(XF9$Gg$jh+%oD+LHqK)o*XO)x52wr}noB&xYQp`(Gt3#{tgmr^H
zuk5JGq73)otfZ*P?FjfBsaVswu7^<E+ifU>sXm!Z5^`H`70l3Fdg1fzoouwK>d$^K
zit!_a6HAq{j+Rdv7#HDk%9fwrgYy$OU%66|$S~X$&&J0__;nYry0{Xm7nmk%7F-VS
ze!={g4tPj{-FInxZ_OnuI1Wb0Fwsuj%oz}YjoR(SkiweJVVPu;(?PUZ0*5<^!3y*Y
z+Qm!thFbAg97)SKbvIrQ0aIjU0LpCHDu~z3HJ~;z<VS{whsn~Qk{nbLq;t@W492y+
za5zE$c7nO%IcSx>+gOBMU+t^s{Ih${@7{G2MfUPjiT#c`Zkn-BeI%BQ4LfQEMUCD$
zS}iGnN<Ul)m!Dd>+jGC8*W0jxrsK~oodO-gRW@{(f~v;8Ml4}Kg+-$WBM}ri4YYXn
zt5Enk%pK0FL>whPa`@y)sAXkqg^yZg!^x7lo{t?qe&XnTPUeXSqU`&{NVw)LI0gv!
zf>}sB!hT+i?x{^WY(kYK;0j=$|A@eEE#;qn5cm6VwURAA{Ffhh;3t2oHH^p+NM7}V
z1;xVC+G#CP?);RBfy9j+=`__d=`?%hvyeE)UimB{F0w!UY)X`v|MPpNN>Ji9-oR!R
z8(x2Z8^5sjZTvAbsa@4-d8G<vtl`uMHoQpxB7R{(-*}V#-sk;6D5DD|R`b1eez6h$
p{G#8({_69-*b{zVo42h|5c%J40wsY|<`IU&`Mv)Atm&V-{vWFLxB>tG

diff --git a/examples/example_simplest/students/cs101/report1.py b/examples/example_simplest/students/cs101/report1.py
index 8e5dfca..9e9fce7 100644
--- a/examples/example_simplest/students/cs101/report1.py
+++ b/examples/example_simplest/students/cs101/report1.py
@@ -1,8 +1,8 @@
 """
 Example student code. This file is automatically generated from the files in the instructor-directory
 """
-from unitgrade2.unitgrade2 import Report
-from unitgrade2.unitgrade_helpers2 import evaluate_report_student
+from src.unitgrade2.unitgrade2 import Report
+from src.unitgrade2 import evaluate_report_student
 from cs101.homework1 import reverse_list, add
 import unittest
 
@@ -13,7 +13,6 @@ class Week1(unittest.TestCase):
 
     def test_reverse(self):
         self.assertEqual(reverse_list([1,2,3]), [3,2,1])
-        # print("Bad output\n\n")
 
 
 import cs101
diff --git a/examples/example_simplest/students/cs101/report1_grade.py b/examples/example_simplest/students/cs101/report1_grade.py
index efb1981..c244e79 100644
--- a/examples/example_simplest/students/cs101/report1_grade.py
+++ b/examples/example_simplest/students/cs101/report1_grade.py
@@ -6,14 +6,10 @@ from tabulate import tabulate
 from datetime import datetime
 import pyfiglet
 import unittest
-
 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: 
@@ -63,53 +59,6 @@ def evaluate_report_student(report, question=None, qitem=None, unmute=None, pass
                                           show_tol_err=show_tol_err)
 
 
-    # try:  # For registering stats.
-    #     import unitgrade_private
-    #     import irlc.lectures
-    #     import xlwings
-    #     from openpyxl import Workbook
-    #     import pandas as pd
-    #     from collections import defaultdict
-    #     dd = defaultdict(lambda: [])
-    #     error_computed = []
-    #     for k1, (q, _) in enumerate(report.questions):
-    #         for k2, item in enumerate(q.items):
-    #             dd['question_index'].append(k1)
-    #             dd['item_index'].append(k2)
-    #             dd['question'].append(q.name)
-    #             dd['item'].append(item.name)
-    #             dd['tol'].append(0 if not hasattr(item, 'tol') else item.tol)
-    #             error_computed.append(0 if not hasattr(item, 'error_computed') else item.error_computed)
-    #
-    #     qstats = report.wdir + "/" + report.name + ".xlsx"
-    #
-    #     if os.path.isfile(qstats):
-    #         d_read = pd.read_excel(qstats).to_dict()
-    #     else:
-    #         d_read = dict()
-    #
-    #     for k in range(1000):
-    #         key = 'run_'+str(k)
-    #         if key in d_read:
-    #             dd[key] = list(d_read['run_0'].values())
-    #         else:
-    #             dd[key] = error_computed
-    #             break
-    #
-    #     workbook = Workbook()
-    #     worksheet = workbook.active
-    #     for col, key in enumerate(dd.keys()):
-    #         worksheet.cell(row=1, column=col+1).value = key
-    #         for row, item in enumerate(dd[key]):
-    #             worksheet.cell(row=row+2, column=col+1).value = item
-    #
-    #     workbook.save(qstats)
-    #     workbook.close()
-    #
-    # except ModuleNotFoundError as e:
-    #     s = 234
-    #     pass
-
     if question is None:
         print("Provisional evaluation")
         tabulate(table_data)
@@ -161,24 +110,20 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         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)
@@ -188,104 +133,28 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
         q.possible = 0
         q.obtained = 0
         q_ = {} # Gather score in this class.
-        # unittest.Te
-        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]
         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)
-        # res = UTextTestRunner(verbosity=2, resultclass=unittest.TextTestResult).run(suite)
-        z = 234
-        # for j, item in enumerate(q.items):
-        #     if qitem is not None and question is not None and j+1 != qitem:
-        #         continue
-        #
-        #     if q_with_outstanding_init is not None: # check for None bc. this must be called to set titles.
-        #         # if not item.question.has_called_init_:
-        #         start = time.time()
-        #
-        #         cc = None
-        #         if show_progress_bar:
-        #             total_estimated_time = q.estimated_time # Use this. The time is estimated for the q itself.  # sum( [q2.estimated_time for q2 in q_with_outstanding_init] )
-        #             cc = ActiveProgress(t=total_estimated_time, title=q_title_print)
-        #         from unitgrade import Capturing # DON'T REMOVE THIS LINE
-        #         with eval('Capturing')(unmute=unmute):  # Clunky import syntax is required bc. of minify issue.
-        #             try:
-        #                 for q2 in q_with_outstanding_init:
-        #                     q2.init()
-        #                     q2.has_called_init_ = True
-        #
-        #                 # item.question.init()  # Initialize the question. Useful for sharing resources.
-        #             except Exception as e:
-        #                 if not passall:
-        #                     if not silent:
-        #                         print(" ")
-        #                         print("="*30)
-        #                         print(f"When initializing question {q.title} the initialization code threw an error")
-        #                         print(e)
-        #                         print("The remaining parts of this question will likely fail.")
-        #                         print("="*30)
-        #
-        #         if show_progress_bar:
-        #             cc.terminate()
-        #             sys.stdout.flush()
-        #             print(q_title_print, end="")
-        #
-        #         q_time =np.round(  time.time()-start, 2)
-        #
-        #         print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")
-        #         print("=" * nL)
-        #         q_with_outstanding_init = None
-        #
-        #     # item.question = q # Set the parent question instance for later reference.
-        #     item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)
-        #
-        #     if show_progress_bar:
-        #         cc = ActiveProgress(t=item.estimated_time, title=item_title_print)
-        #     else:
-        #         print(item_title_print + ( '.'*max(0, nL-4-len(ss)) ), end="")
-        #     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)
-        #     if show_progress_bar:
-        #         cc.terminate()
-        #         sys.stdout.flush()
-        #         print(item_title_print + ('.' * max(0, nL - 4 - len(ss))), end="")
-        #
-        #     if not hidden:
-        #         ss = "PASS" if current == possible else "*** FAILED"
-        #         if tsecs >= 0.1:
-        #             ss += " ("+ str(tsecs) + " seconds)"
-        #         print(ss)
-
-        # ws, possible, obtained = upack(q_)
 
         possible = res.testsRun
         obtained = len(res.successes)
 
         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"Question {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) )
@@ -300,15 +169,16 @@ 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") +")")
+    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
 
 
-
-
 from tabulate import tabulate
 from datetime import datetime
 import inspect
@@ -331,7 +201,8 @@ def gather_imports(imp):
     # dn = os.path.dirname(f)
     # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
     # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
-    if m.__class__.__name__ == 'module' and False:
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
         top_package = os.path.dirname(m.__file__)
         module_import = True
     else:
@@ -352,7 +223,7 @@ def gather_imports(imp):
             for file in files:
                 if file.endswith(".py"):
                     fpath = os.path.join(root, file)
-                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
                     zip.write(fpath, v)
 
     resources['zipfile'] = zip_buffer.getvalue()
@@ -396,14 +267,14 @@ def gather_upload_to_campusnet(report, output_dir=None):
     results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
                                           show_progress_bar=not args.noprogress,
                                           big_header=not args.autolab)
-    print(" ")
-    print("="*n)
-    print("Final evaluation")
-    print(tabulate(table_data))
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
     # also load the source code of missing files...
 
     sources = {}
-
+    print("")
     if not args.autolab:
         if len(report.individual_imports) > 0:
             print("By uploading the .token file, you verify the files:")
@@ -416,12 +287,15 @@ def gather_upload_to_campusnet(report, output_dir=None):
             print("Including files in upload...")
             for k, m in enumerate(report.pack_imports):
                 nimp, top_package = gather_imports(m)
-                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
                 nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
                 nimp['name'] = m.__name__
                 sources[k] = nimp
                 # if len([k for k in nimp if k not in sources]) > 0:
-                print(f"*** {m.__name__}")
+                print(f" * {m.__name__}")
                 # sources = {**sources, **nimp}
     results['sources'] = sources
 
@@ -440,9 +314,9 @@ def gather_upload_to_campusnet(report, output_dir=None):
 
     if not args.autolab:
         print(" ")
-        print("To get credit for your results, please upload the single file: ")
+        print("To get credit for your results, please upload the single unmodified file: ")
         print(">", token)
-        print("To campusnet without any modifications.")
+        # print("To campusnet without any modifications.")
 
         # print("Now time for some autolab fun")
 
@@ -455,7 +329,7 @@ def source_instantiate(name, report1_source, payload):
 
 
 
-report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n\n"""\n# from . import cache_read\nimport unittest\nimport numpy as np\nimport sys\nfrom io import StringIO\nimport collections\nimport re\nimport threading\nimport tqdm\nimport time\nimport pickle\nimport itertools\nimport os\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\ndef setup_dir_by_class(C,base_dir):\n    name = C.__class__.__name__\n    # base_dir = os.path.join(base_dir, name)\n    # if not os.path.isdir(base_dir):\n    #     os.makedirs(base_dir)\n    return base_dir, name\n\nclass Hidden:\n    def hide(self):\n        return True\n\nclass Logger(object):\n    def __init__(self, buffer):\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\nclass Capturing(list):\n    def __init__(self, *args, unmute=False, **kwargs):\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True): # don\'t put arguments here.\n        self._stdout = sys.stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO() # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio    # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass QItem(unittest.TestCase):\n    title = None\n    testfun = None\n    tol = 0\n    estimated_time = 0.42\n    _precomputed_payload = None\n    _computed_answer = None # Internal helper to later get results.\n    weight = 1 # the weight of the question.\n\n    def __init__(self, question=None, *args, **kwargs):\n        if self.tol > 0 and self.testfun is None:\n            self.testfun = self.assertL2Relative\n        elif self.testfun is None:\n            self.testfun = self.assertEqual\n\n        self.name = self.__class__.__name__\n        # self._correct_answer_payload = correct_answer_payload\n        self.question = question\n\n        super().__init__(*args, **kwargs)\n        if self.title is None:\n            self.title = self.name\n\n    def _safe_get_title(self):\n        if self._precomputed_title is not None:\n            return self._precomputed_title\n        return self.title\n\n    def assertNorm(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )\n        nrm = np.sqrt(np.sum( diff ** 2))\n\n        self.error_computed = nrm\n\n        if nrm > tol:\n            print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def assertL2(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        self.error_computed = np.max(diff)\n\n        if np.max(diff) > tol:\n            print(f"Not equal within tolerance {tol=}; deviation was {np.max(diff)=}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol=}, {np.max(diff)=}")\n\n    def assertL2Relative(self, computed, expected, tol=None):\n        if tol == None:\n            tol = self.tol\n        diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )\n        diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )\n        self.error_computed = np.max(np.abs(diff))\n        if np.sum(diff > tol) > 0:\n            print(f"Not equal within tolerance {tol}")\n            print(f"Element-wise differences {diff.tolist()}")\n            self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")\n\n    def precomputed_payload(self):\n        return self._precomputed_payload\n\n    def precompute_payload(self):\n        # Pre-compute resources to include in tests (useful for getting around rng).\n        pass\n\n    def compute_answer(self, unmute=False):\n        raise NotImplementedError("test code here")\n\n    def test(self, computed, expected):\n        self.testfun(computed, expected)\n\n    def get_points(self, verbose=False, show_expected=False, show_computed=False,unmute=False, passall=False, silent=False, **kwargs):\n        possible = 1\n        computed = None\n        def show_computed_(computed):\n            print(">>> Your output:")\n            print(computed)\n\n        def show_expected_(expected):\n            print(">>> Expected output (note: may have been processed; read text script):")\n            print(expected)\n\n        correct = self._correct_answer_payload\n        try:\n            if unmute: # Required to not mix together print stuff.\n                print("")\n            computed = self.compute_answer(unmute=unmute)\n        except Exception as e:\n            if not passall:\n                if not silent:\n                    print("\\n=================================================================================")\n                    print(f"When trying to run test class \'{self.name}\' your code threw an error:", e)\n                    show_expected_(correct)\n                    import traceback\n                    print(traceback.format_exc())\n                    print("=================================================================================")\n                return (0, possible)\n\n        if self._computed_answer is None:\n            self._computed_answer = computed\n\n        if show_expected or show_computed:\n            print("\\n")\n        if show_expected:\n            show_expected_(correct)\n        if show_computed:\n            show_computed_(computed)\n        try:\n            if not passall:\n                self.test(computed=computed, expected=correct)\n        except Exception as e:\n            if not silent:\n                print("\\n=================================================================================")\n                print(f"Test output from test class \'{self.name}\' does not match expected result. Test error:")\n                print(e)\n                show_computed_(computed)\n                show_expected_(correct)\n            return (0, possible)\n        return (1, possible)\n\n    def score(self):\n        try:\n            self.test()\n        except Exception as e:\n            return 0\n        return 1\n\nclass QPrintItem(QItem):\n    def compute_answer_print(self):\n        """\n        Generate output which is to be tested. By default, both text written to the terminal using print(...) as well as return values\n        are send to process_output (see compute_answer below). In other words, the text generated is:\n\n        res = compute_Answer_print()\n        txt = (any terminal output generated above)\n        numbers = (any numbers found in terminal-output txt)\n\n        self.test(process_output(res, txt, numbers), <expected result>)\n\n        :return: Optional values for comparison\n        """\n        raise Exception("Generate output here. The output is passed to self.process_output")\n\n    def process_output(self, res, txt, numbers):\n        return res\n\n    def compute_answer(self, unmute=False):\n        with Capturing(unmute=unmute) as output:\n            res = self.compute_answer_print()\n        s = "\\n".join(output)\n        s = rm_progress_bar(s) # Remove progress bar.\n        numbers = extract_numbers(s)\n        self._computed_answer = (res, s, numbers)\n        return self.process_output(res, s, numbers)\n\nclass OrderedClassMembers(type):\n    @classmethod\n    def __prepare__(self, name, bases):\n        return collections.OrderedDict()\n    def __new__(self, name, bases, classdict):\n        ks = list(classdict.keys())\n        for b in bases:\n            ks += b.__ordered__\n        classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n        return type.__new__(self, name, bases, classdict)\n\nclass QuestionGroup(metaclass=OrderedClassMembers):\n    title = "Untitled question"\n    partially_scored = False\n    t_init = 0  # Time spend on initialization (placeholder; set this externally).\n    estimated_time = 0.42\n    has_called_init_ = False\n    _name = None\n    _items = None\n\n    @property\n    def items(self):\n        if self._items == None:\n            self._items = []\n            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)]\n            for I in members:\n                self._items.append( I(question=self))\n        return self._items\n\n    @items.setter\n    def items(self, value):\n        self._items = value\n\n    @property\n    def name(self):\n        if self._name == None:\n            self._name = self.__class__.__name__\n        return self._name #\n\n    @name.setter\n    def name(self, val):\n        self._name = val\n\n    def init(self):\n        # Can be used to set resources relevant for this question instance.\n        pass\n\n    def init_all_item_questions(self):\n        for item in self.items:\n            if not item.question.has_called_init_:\n                item.question.init()\n                item.question.has_called_init_ = True\n\n\nclass Report():\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 80 # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q,_) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        root_dir = self.pack_imports[0].__path__._path[0]\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q,_) in self.questions:\n            q.nL = self.nL # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n        # else:\n        #     if os.path.isfile(self.computed_answers_file):\n        #         self.set_payload(cache_read(self.computed_answers_file), strict=strict)\n        #     else:\n        #         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."\n        #         if strict:\n        #             raise Exception(s)\n        #         else:\n        #             print(s)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        import unittest\n        loader = unittest.TestLoader()\n        for q,_ in self.questions:\n            import time\n            start = time.time() # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time()              - start\n            q.time = total\n\n    def _setup_answers(self):\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\':True}\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n            # for item in q.items:\n            #     if q.name not in payloads or item.name not in payloads[q.name]:\n            #         s = f"> Broken resource dictionary submitted to unitgrade for question {q.name} and subquestion {item.name}. Framework will not work."\n            #         if strict:\n            #             raise Exception(s)\n            #         else:\n            #             print(s)\n            #     else:\n            #         item._correct_answer_payload = payloads[q.name][item.name][\'payload\']\n            #         item.estimated_time = payloads[q.name][item.name].get("time", 1)\n            #         q.estimated_time = payloads[q.name].get("time", 1)\n            #         if "precomputed" in payloads[q.name][item.name]: # Consider removing later.\n            #             item._precomputed_payload = payloads[q.name][item.name][\'precomputed\']\n            #         try:\n            #             if "title" in payloads[q.name][item.name]: # can perhaps be removed later.\n            #                 item.title = payloads[q.name][item.name][\'title\']\n            #         except Exception as e: # Cannot set attribute error. The title is a function (and probably should not be).\n            #             pass\n            #             # print("bad", e)\n        # self.payloads = payloads\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct+1)\n            if i > 0 and l.find("|", i+1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = \'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar",show_progress_bar=True):\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.1\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n\n        # self.pbar = tqdm.tqdm(total=self.n)\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if hasattr(self, \'pbar\') and self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar=None\n\n        sys.stdout.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')  # , unit_scale=dt, unit=\'seconds\'):\n\n        for _ in range(self.n-1): # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\n\n\nfrom unittest.suite import _isnotsuite\n\nclass MySuite(unittest.suite.TestSuite): # Not sure we need this one anymore.\n    pass\n\ndef instance_call_stack(instance):\n    s = "-".join(map(lambda x: x.__name__, instance.__class__.mro()))\n    return s\n\ndef get_class_that_defined_method(meth):\n    for cls in inspect.getmro(meth.im_class):\n        if meth.__name__ in cls.__dict__:\n            return cls\n    return None\n\ndef caller_name(skip=2):\n    """Get a name of a caller in the format module.class.method\n\n       `skip` specifies how many levels of stack to skip while getting caller\n       name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.\n\n       An empty string is returned if skipped levels exceed stack height\n    """\n    stack = inspect.stack()\n    start = 0 + skip\n    if len(stack) < start + 1:\n      return \'\'\n    parentframe = stack[start][0]\n\n    name = []\n    module = inspect.getmodule(parentframe)\n    # `modname` can be None when frame is executed directly in console\n    # TODO(techtonik): consider using __main__\n    if module:\n        name.append(module.__name__)\n    # detect classname\n    if \'self\' in parentframe.f_locals:\n        # I don\'t know any way to detect call from the object method\n        # XXX: there seems to be no way to detect static method call - it will\n        #      be just a function call\n        name.append(parentframe.f_locals[\'self\'].__class__.__name__)\n    codename = parentframe.f_code.co_name\n    if codename != \'<module>\':  # top level usually\n        name.append( codename ) # function or a method\n\n    ## Avoid circular refs and frame leaks\n    #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack\n    del parentframe, stack\n\n    return ".".join(name)\n\ndef get_class_from_frame(fr):\n      import inspect\n      args, _, _, value_dict = inspect.getargvalues(fr)\n      # we check the first parameter for the frame function is\n      # named \'self\'\n      if len(args) and args[0] == \'self\':\n            # in that case, \'self\' will be referenced in value_dict\n            instance = value_dict.get(\'self\', None)\n            if instance:\n                  # return its class\n                  # isinstance(instance, Testing) # is the actual class instance.\n\n                  return getattr(instance, \'__class__\', None)\n      # return None otherwise\n      return None\n\nfrom typing import Any\nimport inspect, gc\n\ndef giveupthefunc():\n    frame = inspect.currentframe()\n    code  = frame.f_code\n    globs = frame.f_globals\n    functype = type(lambda: 0)\n    funcs = []\n    for func in gc.get_referrers(code):\n        if type(func) is functype:\n            if getattr(func, "__code__", None) is code:\n                if getattr(func, "__globals__", None) is globs:\n                    funcs.append(func)\n                    if len(funcs) > 1:\n                        return None\n    return funcs[0] if funcs else None\n\n\nfrom collections import defaultdict\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1 # HAcky way to set question number.\n    show_progress_bar = True\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        # if self.dots or self.showAll:\n        #     self.stream.writeln()\n        # if hasattr(self, \'cc\'):\n        #     self.cc.terminate()\n        # self.cc_terminate(success=False)\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n        # if self.showAll:\n        #     self.stream.writeln("FAIL")\n        # elif self.dots:\n        #     self.stream.write(\'F\')\n        #     self.stream.flush()\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        # super().addSuccess(test)\n        self.successes.append(test)\n        # super().addSuccess(test)\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        self.cc_terminate()\n\n\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            sys.stdout.flush()\n            ss = self.item_title_print\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(ss))), end="")\n            # current = 1\n            # possible = 1\n            # current == possible\n            ss = "PASS" if success else "FAILED"\n            if tsecs >= 0.1:\n                ss += " (" + str(tsecs) + " seconds)"\n            print(ss)\n\n\n    def startTest(self, test):\n        # super().startTest(test)\n        j =self.testsRun\n        self.testsRun += 1\n        # print("Starting the test...")\n        # show_progress_bar = True\n        n = UTextResult.number\n\n        item_title = self.getDescription(test)\n        item_title = item_title.split("\\n")[0]\n\n        item_title = test.shortDescription() # Better for printing (get from cache).\n        # test.countTestCases()\n        self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title)\n        estimated_time = 10\n        nL = 80\n        #\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 2\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            # q_title_print = "some printed title..."\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self): # Used when setting up the test.\n        if self._previousTestClass == None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            print(self.cc.title, end="")\n            # start = 10\n            # q_time = np.round(time.time() - start, 2)\n            nL = 80\n            print(" " * max(0, nL - len(self.cc.title)) + (\n                " (" + str(q_time) + " seconds)" if q_time >= 0.1 else ""))  # if q.name in report.payloads else "")\n            # print("=" * nL)\n\nfrom unittest.runner import _WritelnDecorator\nfrom io import StringIO\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        from io import StringIO\n        stream = StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\ndef wrapper(foo):\n    def magic(self):\n        s = "-".join(map(lambda x: x.__name__, self.__class__.mro()))\n        # print(s)\n        foo(self)\n    magic.__doc__ = foo.__doc__\n    return magic\n\nfrom functools import update_wrapper, _make_key, RLock\nfrom collections import namedtuple\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)) )\n        # key = (self.cache_id(), \'@cache\')\n        # if self._cache_contains[key]\n\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n    return wrapper\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n\n    @classmethod\n    def question_title(cls):\n        return cls.__doc__.splitlines()[0].strip() if cls.__doc__ != None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd == None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        # self._testMethodDoc.strip().splitlines()[0].strip()\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get(  (self.cache_id(), \'title\'), sd )\n        return title if title != None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    # def _callSetUp(self):\n    #     # Always run before method is called.\n    #     print("asdf")\n    #     pass\n    # @classmethod\n    # def setUpClass(cls):\n    #     # self._cache_put((self.cache_id(), \'title\'), value)\n    #     cls.reset()\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome == None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists() # Make sure cache is there.\n        if self._testMethodDoc != None:\n            # Ensure the cache is eventually updated with the right docstring.\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard() )\n        # Fix temp cache here (for using the @cache decorator)\n        self._cache2[ (self.cache_id(), \'assert\') ] = {}\n\n        res = testMethod()\n        elapsed = time.time() - t\n        # self._cache_put( (self.cache_id(), \'title\'), self.shortDescription() )\n\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put( (self.cache_id(), "time"), elapsed)\n\n    # This is my base test class. So what is new about it?\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return (c,m)\n\n    # def unique_cache_id(self):\n    #     k0 = self.cache_id()\n    #     # key = ()\n    #     i = 0\n    #     for i in itertools.count():\n    #         # key = k0 + (i,)\n    #         if i not in self._cache_get( (k0, \'assert\') ):\n    #             break\n    #     return i\n    #     return key\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n        # self.cache_indexes = defaultdict(lambda: 0)\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n    #\n    # def _cache2_contains(self, key):\n    #     print("Is this needed?")\n    #     self._ensure_cache_exists()\n    #     return key in self.__class__._cache2\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n        cache = self._cache_get(key, {})\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, first)\n        assert_fun(first, _expected, *args, **kwargs)\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__) ) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache != None: # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        # print("Loading cache from", cfile)\n        if os.path.exists(cfile):\n            with open(cfile, \'rb\') as f:\n                data = pickle.load(f)\n                self.__class__._cache = data\n        else:\n            print("Warning! data file not found", cfile)\n\ndef hide(func):\n    return func\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    # (*)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\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\n\nimport inspect\nimport os\nimport argparse\nimport sys\nimport time\nimport threading # don\'t import Thread bc. of minify issue.\nimport tqdm # don\'t do from tqdm import tqdm because of minify-issue\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    # try:  # For registering stats.\n    #     import unitgrade_private\n    #     import irlc.lectures\n    #     import xlwings\n    #     from openpyxl import Workbook\n    #     import pandas as pd\n    #     from collections import defaultdict\n    #     dd = defaultdict(lambda: [])\n    #     error_computed = []\n    #     for k1, (q, _) in enumerate(report.questions):\n    #         for k2, item in enumerate(q.items):\n    #             dd[\'question_index\'].append(k1)\n    #             dd[\'item_index\'].append(k2)\n    #             dd[\'question\'].append(q.name)\n    #             dd[\'item\'].append(item.name)\n    #             dd[\'tol\'].append(0 if not hasattr(item, \'tol\') else item.tol)\n    #             error_computed.append(0 if not hasattr(item, \'error_computed\') else item.error_computed)\n    #\n    #     qstats = report.wdir + "/" + report.name + ".xlsx"\n    #\n    #     if os.path.isfile(qstats):\n    #         d_read = pd.read_excel(qstats).to_dict()\n    #     else:\n    #         d_read = dict()\n    #\n    #     for k in range(1000):\n    #         key = \'run_\'+str(k)\n    #         if key in d_read:\n    #             dd[key] = list(d_read[\'run_0\'].values())\n    #         else:\n    #             dd[key] = error_computed\n    #             break\n    #\n    #     workbook = Workbook()\n    #     worksheet = workbook.active\n    #     for col, key in enumerate(dd.keys()):\n    #         worksheet.cell(row=1, column=col+1).value = key\n    #         for row, item in enumerate(dd[key]):\n    #             worksheet.cell(row=row+2, column=col+1).value = item\n    #\n    #     workbook.save(qstats)\n    #     workbook.close()\n    #\n    # except ModuleNotFoundError as e:\n    #     s = 234\n    #     pass\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    print(b + " v" + __version__)\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    nL = 80\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        # q = q()\n        # q_hidden = False\n        # q_hidden = issubclass(q.__class__, Hidden)\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        # unittest.Te\n        # q_with_outstanding_init = [item.question for item in q.items if not item.question.has_called_init_]\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n        # res = UTextTestRunner(verbosity=2, resultclass=unittest.TextTestResult).run(suite)\n        z = 234\n        # for j, item in enumerate(q.items):\n        #     if qitem is not None and question is not None and j+1 != qitem:\n        #         continue\n        #\n        #     if q_with_outstanding_init is not None: # check for None bc. this must be called to set titles.\n        #         # if not item.question.has_called_init_:\n        #         start = time.time()\n        #\n        #         cc = None\n        #         if show_progress_bar:\n        #             total_estimated_time = q.estimated_time # Use this. The time is estimated for the q itself.  # sum( [q2.estimated_time for q2 in q_with_outstanding_init] )\n        #             cc = ActiveProgress(t=total_estimated_time, title=q_title_print)\n        #         from unitgrade import Capturing # DON\'T REMOVE THIS LINE\n        #         with eval(\'Capturing\')(unmute=unmute):  # Clunky import syntax is required bc. of minify issue.\n        #             try:\n        #                 for q2 in q_with_outstanding_init:\n        #                     q2.init()\n        #                     q2.has_called_init_ = True\n        #\n        #                 # item.question.init()  # Initialize the question. Useful for sharing resources.\n        #             except Exception as e:\n        #                 if not passall:\n        #                     if not silent:\n        #                         print(" ")\n        #                         print("="*30)\n        #                         print(f"When initializing question {q.title} the initialization code threw an error")\n        #                         print(e)\n        #                         print("The remaining parts of this question will likely fail.")\n        #                         print("="*30)\n        #\n        #         if show_progress_bar:\n        #             cc.terminate()\n        #             sys.stdout.flush()\n        #             print(q_title_print, end="")\n        #\n        #         q_time =np.round(  time.time()-start, 2)\n        #\n        #         print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")\n        #         print("=" * nL)\n        #         q_with_outstanding_init = None\n        #\n        #     # item.question = q # Set the parent question instance for later reference.\n        #     item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)\n        #\n        #     if show_progress_bar:\n        #         cc = ActiveProgress(t=item.estimated_time, title=item_title_print)\n        #     else:\n        #         print(item_title_print + ( \'.\'*max(0, nL-4-len(ss)) ), end="")\n        #     hidden = issubclass(item.__class__, Hidden)\n        #     # if not hidden:\n        #     #     print(ss, end="")\n        #     # sys.stdout.flush()\n        #     start = time.time()\n        #\n        #     (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)\n        #     q_[j] = {\'w\': item.weight, \'possible\': possible, \'obtained\': current, \'hidden\': hidden, \'computed\': str(item._computed_answer), \'title\': item.title}\n        #     tsecs = np.round(time.time()-start, 2)\n        #     if show_progress_bar:\n        #         cc.terminate()\n        #         sys.stdout.flush()\n        #         print(item_title_print + (\'.\' * max(0, nL - 4 - len(ss))), end="")\n        #\n        #     if not hidden:\n        #         ss = "PASS" if current == possible else "*** FAILED"\n        #         if tsecs >= 0.1:\n        #             ss += " ("+ str(tsecs) + " seconds)"\n        #         print(ss)\n\n        # ws, possible, obtained = upack(q_)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        # possible = int(ws @ possible)\n        # obtained = int(ws @ obtained)\n        # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"*** Question q{n+1}"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n    if m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    print(" ")\n    print("="*n)\n    print("Final evaluation")\n    print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f"*** {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single file: ")\n        print(">", token)\n        print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nfrom cs101.homework1 import reverse_list, add\nimport unittest\n\nclass Week1(unittest.TestCase):\n    def test_add(self):\n        self.assertEqual(add(2,2), 4)\n        self.assertEqual(add(-100, 5), -95)\n\n    def test_reverse(self):\n        self.assertEqual(reverse_list([1,2,3]), [3,2,1])\n        # print("Bad output\\n\\n")\n\n\nimport cs101\nclass Report1(Report):\n    title = "CS 101 Report 1"\n    questions = [(Week1, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs101]'
+report1_source = 'import os\n\n# DONT\'t import stuff here since install script requires __version__\n\ndef cache_write(object, file_name, verbose=True):\n    import compress_pickle\n    dn = os.path.dirname(file_name)\n    if not os.path.exists(dn):\n        os.mkdir(dn)\n    if verbose: print("Writing cache...", file_name)\n    with open(file_name, \'wb\', ) as f:\n        compress_pickle.dump(object, f, compression="lzma")\n    if verbose: print("Done!")\n\n\ndef cache_exists(file_name):\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    return os.path.exists(file_name)\n\n\ndef cache_read(file_name):\n    import compress_pickle # Import here because if you import in top the __version__ tag will fail.\n    # file_name = cn_(file_name) if cache_prefix else file_name\n    if os.path.exists(file_name):\n        try:\n            with open(file_name, \'rb\') as f:\n                return compress_pickle.load(f, compression="lzma")\n        except Exception as e:\n            print("Tried to load a bad pickle file at", file_name)\n            print("If the file appears to be automatically generated, you can try to delete it, otherwise download a new version")\n            print(e)\n            # return pickle.load(f)\n    else:\n        return None\n\n\n\n"""\ngit add . && git commit -m "Options" && git push &&  pip install git+ssh://git@gitlab.compute.dtu.dk/tuhe/unitgrade.git --upgrade\n"""\nimport numpy as np\nimport sys\nimport re\nimport threading\nimport tqdm\nimport pickle\nimport os\nfrom io import StringIO\nimport io\nfrom unittest.runner import _WritelnDecorator\nfrom typing import Any\nimport inspect\nimport textwrap\nimport colorama\nfrom colorama import Fore\nfrom functools import _make_key, RLock\nfrom collections import namedtuple\nimport unittest\nimport time\n\n_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])\n\ncolorama.init(autoreset=True)  # auto resets your settings after every output\n\ndef gprint(s):\n    print(f"{Fore.GREEN}{s}")\n\nmyround = lambda x: np.round(x)  # required.\nmsum = lambda x: sum(x)\nmfloor = lambda x: np.floor(x)\n\n\ndef setup_dir_by_class(C, base_dir):\n    name = C.__class__.__name__\n    return base_dir, name\n\n\nclass Logger(object):\n    def __init__(self, buffer):\n        assert False\n        self.terminal = sys.stdout\n        self.log = buffer\n\n    def write(self, message):\n        self.terminal.write(message)\n        self.log.write(message)\n\n    def flush(self):\n        # this flush method is needed for python 3 compatibility.\n        pass\n\n\nclass Capturing(list):\n    def __init__(self, *args, stdout=None, unmute=False, **kwargs):\n        self._stdout = stdout\n        self.unmute = unmute\n        super().__init__(*args, **kwargs)\n\n    def __enter__(self, capture_errors=True):  # don\'t put arguments here.\n        self._stdout = sys.stdout if self._stdout == None else self._stdout\n        self._stringio = StringIO()\n        if self.unmute:\n            sys.stdout = Logger(self._stringio)\n        else:\n            sys.stdout = self._stringio\n\n        if capture_errors:\n            self._sterr = sys.stderr\n            sys.sterr = StringIO()  # memory hole it\n        self.capture_errors = capture_errors\n        return self\n\n    def __exit__(self, *args):\n        self.extend(self._stringio.getvalue().splitlines())\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n\nclass Capturing2(Capturing):\n    def __exit__(self, *args):\n        lines = self._stringio.getvalue().splitlines()\n        txt = "\\n".join(lines)\n        numbers = extract_numbers(txt)\n        self.extend(lines)\n        del self._stringio  # free up some memory\n        sys.stdout = self._stdout\n        if self.capture_errors:\n            sys.sterr = self._sterr\n\n        self.output = txt\n        self.numbers = numbers\n\n\n# @classmethod\n# class OrderedClassMembers(type):\n#     def __prepare__(self, name, bases):\n#         assert False\n#         return collections.OrderedDict()\n#\n#     def __new__(self, name, bases, classdict):\n#         ks = list(classdict.keys())\n#         for b in bases:\n#             ks += b.__ordered__\n#         classdict[\'__ordered__\'] = [key for key in ks if key not in (\'__module__\', \'__qualname__\')]\n#         return type.__new__(self, name, bases, classdict)\n\n\nclass Report:\n    title = "report title"\n    version = None\n    questions = []\n    pack_imports = []\n    individual_imports = []\n    nL = 120  # Maximum line width\n\n    @classmethod\n    def reset(cls):\n        for (q, _) in cls.questions:\n            if hasattr(q, \'reset\'):\n                q.reset()\n\n    @classmethod\n    def mfile(clc):\n        return inspect.getfile(clc)\n\n    def _file(self):\n        return inspect.getfile(type(self))\n\n    def _import_base_relative(self):\n        if hasattr(self.pack_imports[0], \'__path__\'):\n            root_dir = self.pack_imports[0].__path__._path[0]\n        else:\n            root_dir = self.pack_imports[0].__file__\n\n        root_dir = os.path.dirname(root_dir)\n        relative_path = os.path.relpath(self._file(), root_dir)\n        modules = os.path.normpath(relative_path[:-3]).split(os.sep)\n        return root_dir, relative_path, modules\n\n    def __init__(self, strict=False, payload=None):\n        working_directory = os.path.abspath(os.path.dirname(self._file()))\n        self.wdir, self.name = setup_dir_by_class(self, working_directory)\n        # self.computed_answers_file = os.path.join(self.wdir, self.name + "_resources_do_not_hand_in.dat")\n        for (q, _) in self.questions:\n            q.nL = self.nL  # Set maximum line length.\n\n        if payload is not None:\n            self.set_payload(payload, strict=strict)\n\n    def main(self, verbosity=1):\n        # Run all tests using standard unittest (nothing fancy).\n        loader = unittest.TestLoader()\n        for q, _ in self.questions:\n            start = time.time()  # A good proxy for setup time is to\n            suite = loader.loadTestsFromTestCase(q)\n            unittest.TextTestRunner(verbosity=verbosity).run(suite)\n            total = time.time() - start\n            q.time = total\n\n    def _setup_answers(self, with_coverage=False):\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = True\n                q._report = self\n\n        self.main()  # Run all tests in class just to get that out of the way...\n        report_cache = {}\n        for q, _ in self.questions:\n            if hasattr(q, \'_save_cache\'):\n                q()._save_cache()\n                q._cache[\'time\'] = q.time\n                report_cache[q.__qualname__] = q._cache\n            else:\n                report_cache[q.__qualname__] = {\'no cache see _setup_answers in unitgrade2.py\': True}\n        if with_coverage:\n            for q, _ in self.questions:\n                q._with_coverage = False\n        return report_cache\n\n    def set_payload(self, payloads, strict=False):\n        for q, _ in self.questions:\n            q._cache = payloads[q.__qualname__]\n\n\ndef rm_progress_bar(txt):\n    # More robust version. Apparently length of bar can depend on various factors, so check for order of symbols.\n    nlines = []\n    for l in txt.splitlines():\n        pct = l.find("%")\n        ql = False\n        if pct > 0:\n            i = l.find("|", pct + 1)\n            if i > 0 and l.find("|", i + 1) > 0:\n                ql = True\n        if not ql:\n            nlines.append(l)\n    return "\\n".join(nlines)\n\n\ndef extract_numbers(txt):\n    # txt = rm_progress_bar(txt)\n    numeric_const_pattern = r\'[-+]? (?: (?: \\d* \\. \\d+ ) | (?: \\d+ \\.? ) )(?: [Ee] [+-]? \\d+ ) ?\'\n    rx = re.compile(numeric_const_pattern, re.VERBOSE)\n    all = rx.findall(txt)\n    all = [float(a) if (\'.\' in a or "e" in a) else int(a) for a in all]\n    if len(all) > 500:\n        print(txt)\n        raise Exception("unitgrade.unitgrade.py: Warning, too many numbers!", len(all))\n    return all\n\n\nclass ActiveProgress():\n    def __init__(self, t, start=True, title="my progress bar", show_progress_bar=True, file=None):\n        if file == None:\n            file = sys.stdout\n        self.file = file\n        self.t = t\n        self._running = False\n        self.title = title\n        self.dt = 0.01\n        self.n = int(np.round(self.t / self.dt))\n        self.show_progress_bar = show_progress_bar\n        self.pbar = None\n\n        if start:\n            self.start()\n\n    def start(self):\n        self._running = True\n        if self.show_progress_bar:\n            self.thread = threading.Thread(target=self.run)\n            self.thread.start()\n        self.time_started = time.time()\n\n    def terminate(self):\n        if not self._running:\n            raise Exception("Stopping a stopped progress bar. ")\n        self._running = False\n        if self.show_progress_bar:\n            self.thread.join()\n        if self.pbar is not None:\n            self.pbar.update(1)\n            self.pbar.close()\n            self.pbar = None\n\n        self.file.flush()\n        return time.time() - self.time_started\n\n    def run(self):\n        self.pbar = tqdm.tqdm(total=self.n, file=self.file, position=0, leave=False, desc=self.title, ncols=100,\n                              bar_format=\'{l_bar}{bar}| [{elapsed}<{remaining}]\')\n\n        for _ in range(self.n - 1):  # Don\'t terminate completely; leave bar at 99% done until terminate.\n            if not self._running:\n                self.pbar.close()\n                self.pbar = None\n                break\n\n            time.sleep(self.dt)\n            self.pbar.update(1)\n\ndef dprint(first, last, nL, extra = "", file=None, dotsym=\'.\', color=\'white\'):\n    if file == None:\n        file = sys.stdout\n\n    # ss = self.item_title_print\n    # state = "PASS" if success else "FAILED"\n    dot_parts = (dotsym * max(0, nL - len(last) - len(first)))\n    # if self.show_progress_bar or True:\n    print(first + dot_parts, end="", file=file)\n    # else:\n    # print(dot_parts, end="", file=self.cc.file)\n    last += extra\n    # if tsecs >= 0.5:\n    #     state += " (" + str(tsecs) + " seconds)"\n    print(last, file=file)\n\n\nclass UTextResult(unittest.TextTestResult):\n    nL = 80\n    number = -1  # HAcky way to set question number.\n    show_progress_bar = True\n    cc = None\n\n    def __init__(self, stream, descriptions, verbosity):\n        super().__init__(stream, descriptions, verbosity)\n        self.successes = []\n\n    def printErrors(self) -> None:\n        self.printErrorList(\'ERROR\', self.errors)\n        self.printErrorList(\'FAIL\', self.failures)\n\n    def addError(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addFailure(self, test, err):\n        super(unittest.TextTestResult, self).addFailure(test, err)\n        self.cc_terminate(success=False)\n\n    def addSuccess(self, test: unittest.case.TestCase) -> None:\n        self.successes.append(test)\n        self.cc_terminate()\n\n    def cc_terminate(self, success=True):\n        if self.show_progress_bar or True:\n            tsecs = np.round(self.cc.terminate(), 2)\n            self.cc.file.flush()\n            ss = self.item_title_print\n\n            state = "PASS" if success else "FAILED"\n\n            dot_parts = (\'.\' * max(0, self.nL - len(state) - len(ss)))\n            if self.show_progress_bar or True:\n                print(self.item_title_print + dot_parts, end="", file=self.cc.file)\n            else:\n                print(dot_parts, end="", file=self.cc.file)\n\n            if tsecs >= 0.5:\n                state += " (" + str(tsecs) + " seconds)"\n            print(state, file=self.cc.file)\n\n    def startTest(self, test):\n        # j =self.testsRun\n        self.testsRun += 1\n        # item_title = self.getDescription(test)\n        item_title = test.shortDescription()  # Better for printing (get from cache).\n        if item_title == None:\n            # For unittest framework where getDescription may return None.\n            item_title = self.getDescription(test)\n        self.item_title_print = " * q%i.%i) %s" % (UTextResult.number + 1, self.testsRun, item_title)\n        estimated_time = 10\n        if self.show_progress_bar or True:\n            self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print, show_progress_bar=self.show_progress_bar, file=sys.stdout)\n        else:\n            print(self.item_title_print + (\'.\' * max(0, self.nL - 4 - len(self.item_title_print))), end="")\n\n        self._test = test\n        self._stdout = sys.stdout\n        sys.stdout = io.StringIO()\n\n    def stopTest(self, test):\n        sys.stdout = self._stdout\n        super().stopTest(test)\n\n    def _setupStdout(self):\n        if self._previousTestClass == None:\n            total_estimated_time = 1\n            if hasattr(self.__class__, \'q_title_print\'):\n                q_title_print = self.__class__.q_title_print\n            else:\n                q_title_print = "<unnamed test. See unitgrade.py>"\n\n            cc = ActiveProgress(t=total_estimated_time, title=q_title_print, show_progress_bar=self.show_progress_bar)\n            self.cc = cc\n\n    def _restoreStdout(self):  # Used when setting up the test.\n        if self._previousTestClass is None:\n            q_time = self.cc.terminate()\n            q_time = np.round(q_time, 2)\n            sys.stdout.flush()\n            if self.show_progress_bar:\n                print(self.cc.title, end="")\n            print(" " * max(0, self.nL - len(self.cc.title)) + (" (" + str(q_time) + " seconds)" if q_time >= 0.5 else ""))\n\n\nclass UTextTestRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        stream = io.StringIO()\n        super().__init__(*args, stream=stream, **kwargs)\n\n    def _makeResult(self):\n        # stream = self.stream # not you!\n        stream = sys.stdout\n        stream = _WritelnDecorator(stream)\n        return self.resultclass(stream, self.descriptions, self.verbosity)\n\n\ndef cache(foo, typed=False):\n    """ Magic cache wrapper\n    https://github.com/python/cpython/blob/main/Lib/functools.py\n    """\n    maxsize = None\n    def wrapper(self, *args, **kwargs):\n        key = (self.cache_id(), ("@cache", foo.__name__, _make_key(args, kwargs, typed)))\n        if not self._cache_contains(key):\n            value = foo(self, *args, **kwargs)\n            self._cache_put(key, value)\n        else:\n            value = self._cache_get(key)\n        return value\n\n    return wrapper\n\n\ndef get_hints(ss):\n    if ss == None:\n        return None\n    try:\n        ss = textwrap.dedent(ss)\n        ss = ss.replace(\'\'\'"""\'\'\', "").strip()\n        hints = ["hints:", ]\n        j = np.argmax([ss.lower().find(h) for h in hints])\n        h = hints[j]\n        ss = ss[ss.find(h) + len(h) + 1:]\n        ss = "\\n".join([l for l in ss.split("\\n") if not l.strip().startswith(":")])\n        ss = textwrap.dedent(ss)\n        ss = ss.strip()\n        return ss\n    except Exception as e:\n        print("bad hints", ss, e)\n\n\nclass UTestCase(unittest.TestCase):\n    _outcome = None  # A dictionary which stores the user-computed outcomes of all the tests. This differs from the cache.\n    _cache = None  # Read-only cache. Ensures method always produce same result.\n    _cache2 = None  # User-written cache.\n    _with_coverage = False\n    _report = None  # The report used. This is very, very hacky and should always be None. Don\'t rely on it!\n\n    def capture(self):\n        if hasattr(self, \'_stdout\') and self._stdout is not None:\n            file = self._stdout\n        else:\n            file = sys.stdout\n        return Capturing2(stdout=file)\n\n    @classmethod\n    def question_title(cls):\n        """ Return the question title """\n        return cls.__doc__.strip().splitlines()[0].strip() if cls.__doc__ is not None else cls.__qualname__\n\n    @classmethod\n    def reset(cls):\n        print("Warning, I am not sure UTestCase.reset() is needed anymore and it seems very hacky.")\n        cls._outcome = None\n        cls._cache = None\n        cls._cache2 = None\n\n    def _callSetUp(self):\n        if self._with_coverage:\n            if not hasattr(self._report, \'covcache\'):\n                self._report.covcache = {}\n            import coverage\n            self.cov = coverage.Coverage()\n            self.cov.start()\n        self.setUp()\n\n    def _callTearDown(self):\n        self.tearDown()\n        if self._with_coverage:\n            from pathlib import Path\n            from snipper import snipper\n            self.cov.stop()\n            data = self.cov.get_data()\n            base, _, _ = self._report._import_base_relative()\n            for file in data.measured_files():\n                file = os.path.normpath(file)\n                root = Path(base)\n                child = Path(file)\n                if root in child.parents:\n                    with open(child, \'r\') as f:\n                        s = f.read()\n                    lines = s.splitlines()\n                    garb = \'GARBAGE\'\n\n                    lines2 = snipper.censor_code(lines, keep=True)\n                    assert len(lines) == len(lines2)\n\n                    for l in data.contexts_by_lineno(file):\n                        if lines2[l].strip() == garb:\n                            if self.cache_id() not in self._report.covcache:\n                                self._report.covcache[self.cache_id()] = {}\n\n                            rel = os.path.relpath(child, root)\n                            cc = self._report.covcache[self.cache_id()]\n                            j = 0\n                            for j in range(l, -1, -1):\n                                if "def" in lines2[j] or "class" in lines2[j]:\n                                    break\n                            from snipper.snipper import gcoms\n                            fun = lines2[j]\n                            comments, _ = gcoms("\\n".join(lines2[j:l]))\n                            if rel not in cc:\n                                cc[rel] = {}\n                            cc[rel][fun] = (l, "\\n".join(comments))\n                            self._cache_put((self.cache_id(), \'coverage\'), self._report.covcache)\n\n    def shortDescriptionStandard(self):\n        sd = super().shortDescription()\n        if sd is None:\n            sd = self._testMethodName\n        return sd\n\n    def shortDescription(self):\n        sd = self.shortDescriptionStandard()\n        title = self._cache_get((self.cache_id(), \'title\'), sd)\n        return title if title is not None else sd\n\n    @property\n    def title(self):\n        return self.shortDescription()\n\n    @title.setter\n    def title(self, value):\n        self._cache_put((self.cache_id(), \'title\'), value)\n\n    def _get_outcome(self):\n        if not (self.__class__, \'_outcome\') or self.__class__._outcome is None:\n            self.__class__._outcome = {}\n        return self.__class__._outcome\n\n    def _callTestMethod(self, testMethod):\n        t = time.time()\n        self._ensure_cache_exists()  # Make sure cache is there.\n        if self._testMethodDoc is not None:\n            self._cache_put((self.cache_id(), \'title\'), self.shortDescriptionStandard())\n\n        self._cache2[(self.cache_id(), \'assert\')] = {}\n        res = testMethod()\n        elapsed = time.time() - t\n        self._get_outcome()[self.cache_id()] = res\n        self._cache_put((self.cache_id(), "time"), elapsed)\n\n    def cache_id(self):\n        c = self.__class__.__qualname__\n        m = self._testMethodName\n        return c, m\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._load_cache()\n        self._assert_cache_index = 0\n\n    def _ensure_cache_exists(self):\n        if not hasattr(self.__class__, \'_cache\') or self.__class__._cache == None:\n            self.__class__._cache = dict()\n        if not hasattr(self.__class__, \'_cache2\') or self.__class__._cache2 == None:\n            self.__class__._cache2 = dict()\n\n    def _cache_get(self, key, default=None):\n        self._ensure_cache_exists()\n        return self.__class__._cache.get(key, default)\n\n    def _cache_put(self, key, value):\n        self._ensure_cache_exists()\n        self.__class__._cache2[key] = value\n\n    def _cache_contains(self, key):\n        self._ensure_cache_exists()\n        return key in self.__class__._cache\n\n    def wrap_assert(self, assert_fun, first, *args, **kwargs):\n        # sys.stdout = self._stdout\n        key = (self.cache_id(), \'assert\')\n        if not self._cache_contains(key):\n            print("Warning, framework missing", key)\n            self.__class__._cache[\n                key] = {}  # A new dict. We manually insert it because we have to use that the dict is mutable.\n        cache = self._cache_get(key)\n        id = self._assert_cache_index\n        if not id in cache:\n            print("Warning, framework missing cache index", key, "id =", id)\n        _expected = cache.get(id, f"Key {id} not found in cache; framework files missing. Please run deploy()")\n\n        # The order of these calls is important. If the method assert fails, we should still store the correct result in cache.\n        cache[id] = first\n        self._cache_put(key, cache)\n        self._assert_cache_index += 1\n        assert_fun(first, _expected, *args, **kwargs)\n\n    def assertEqualC(self, first: Any, msg: Any = ...) -> None:\n        self.wrap_assert(self.assertEqual, first, msg)\n\n    def _cache_file(self):\n        return os.path.dirname(inspect.getfile(self.__class__)) + "/unitgrade/" + self.__class__.__name__ + ".pkl"\n\n    def _save_cache(self):\n        # get the class name (i.e. what to save to).\n        cfile = self._cache_file()\n        if not os.path.isdir(os.path.dirname(cfile)):\n            os.makedirs(os.path.dirname(cfile))\n\n        if hasattr(self.__class__, \'_cache2\'):\n            with open(cfile, \'wb\') as f:\n                pickle.dump(self.__class__._cache2, f)\n\n    # But you can also set cache explicitly.\n    def _load_cache(self):\n        if self._cache is not None:  # Cache already loaded. We will not load it twice.\n            return\n            # raise Exception("Loaded cache which was already set. What is going on?!")\n        cfile = self._cache_file()\n        if os.path.exists(cfile):\n            try:\n                with open(cfile, \'rb\') as f:\n                    data = pickle.load(f)\n                self.__class__._cache = data\n            except Exception as e:\n                print("Bad cache", cfile)\n                print(e)\n        else:\n            print("Warning! data file not found", cfile)\n\n    def _feedErrorsToResult(self, result, errors):\n        """ Use this to show hints on test failure. """\n        if not isinstance(result, UTextResult):\n            er = [e for e, v in errors if v != None]\n\n            if len(er) > 0:\n                hints = []\n                key = (self.cache_id(), \'coverage\')\n                if self._cache_contains(key):\n                    CC = self._cache_get(key)\n                    for id in CC:\n                        if id == self.cache_id():\n                            cl, m = id\n                            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:")\n                            for file in CC[id]:\n                                rec = CC[id][file]\n                                gprint(f">   * {file}")\n                                for l in rec:\n                                    _, comments = CC[id][file][l]\n                                    hint = get_hints(comments)\n\n                                    if hint != None:\n                                        hints.append(hint)\n                                    gprint(f">      - {l}")\n\n                er = er[0]\n                doc = er._testMethodDoc\n                if doc is not None:\n                    hint = get_hints(er._testMethodDoc)\n                    if hint is not None:\n                        hints = [hint] + hints\n                if len(hints) > 0:\n                    gprint("> Hints:")\n                    gprint(textwrap.indent("\\n".join(hints), ">   "))\n\n        super()._feedErrorsToResult(result, errors)\n\n    def startTestRun(self):\n        # print("asdfsdaf 11", file=sys.stderr)\n        super().startTestRun()\n        # print("asdfsdaf")\n\n    def _callTestMethod(self, method):\n        # print("asdfsdaf")\n        super()._callTestMethod(method)\n\n\ndef hide(func):\n    return func\n\n\ndef makeRegisteringDecorator(foreignDecorator):\n    """\n        Returns a copy of foreignDecorator, which is identical in every\n        way(*), except also appends a .decorator property to the callable it\n        spits out.\n    """\n\n    def newDecorator(func):\n        # Call to newDecorator(method)\n        # Exactly like old decorator, but output keeps track of what decorated it\n        R = foreignDecorator(func)  # apply foreignDecorator, like call to foreignDecorator(method) would have done\n        R.decorator = newDecorator  # keep track of decorator\n        # R.original = func         # might as well keep track of everything!\n        return R\n\n    newDecorator.__name__ = foreignDecorator.__name__\n    newDecorator.__doc__ = foreignDecorator.__doc__\n    return newDecorator\n\nhide = makeRegisteringDecorator(hide)\n\ndef methodsWithDecorator(cls, decorator):\n    """\n        Returns all methods in CLS with DECORATOR as the\n        outermost decorator.\n\n        DECORATOR must be a "registering decorator"; one\n        can make any decorator "registering" via the\n        makeRegisteringDecorator function.\n\n        import inspect\n        ls = list(methodsWithDecorator(GeneratorQuestion, deco))\n        for f in ls:\n            print(inspect.getsourcelines(f) ) # How to get all hidden questions.\n    """\n    for maybeDecorated in cls.__dict__.values():\n        if hasattr(maybeDecorated, \'decorator\'):\n            if maybeDecorated.decorator == decorator:\n                print(maybeDecorated)\n                yield maybeDecorated\n# 817\n\n\nimport numpy as np\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport pyfiglet\nimport unittest\nimport inspect\nimport os\nimport argparse\nimport time\n\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Example: \nTo run all tests in a report: \n\n> python assignment1_dp.py\n\nTo run only question 2 or question 2.1\n\n> python assignment1_dp.py -q 2\n> python assignment1_dp.py -q 2.1\n\nNote this scripts does not grade your report. To grade your report, use:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'-q\', nargs=\'?\', type=str, default=None, help=\'Only evaluate this question (e.g.: -q 2)\')\nparser.add_argument(\'--showexpected\',  action="store_true",  help=\'Show the expected/desired result\')\nparser.add_argument(\'--showcomputed\',  action="store_true",  help=\'Show the answer your code computes\')\nparser.add_argument(\'--unmute\',  action="store_true",  help=\'Show result of print(...) commands in code\')\nparser.add_argument(\'--passall\',  action="store_true",  help=\'Automatically pass all tests. Useful when debugging.\')\n\ndef evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False):\n    args = parser.parse_args()\n    if question is None and args.q is not None:\n        question = args.q\n        if "." in question:\n            question, qitem = [int(v) for v in question.split(".")]\n        else:\n            question = int(question)\n\n    if hasattr(report, "computed_answer_file") and not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:\n        raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")\n\n    if unmute is None:\n        unmute = args.unmute\n    if passall is None:\n        passall = args.passall\n\n    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,\n                                          show_tol_err=show_tol_err)\n\n\n    if question is None:\n        print("Provisional evaluation")\n        tabulate(table_data)\n        table = table_data\n        print(tabulate(table))\n        print(" ")\n\n    fr = inspect.getouterframes(inspect.currentframe())[1].filename\n    gfile = os.path.basename(fr)[:-3] + "_grade.py"\n    if os.path.exists(gfile):\n        print("Note your results have not yet been registered. \\nTo register your results, please run the file:")\n        print(">>>", gfile)\n        print("In the same manner as you ran this file.")\n\n\n    return results\n\n\ndef upack(q):\n    # h = zip([(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()])\n    h =[(i[\'w\'], i[\'possible\'], i[\'obtained\']) for i in q.values()]\n    h = np.asarray(h)\n    return h[:,0], h[:,1], h[:,2],\n\nclass UnitgradeTextRunner(unittest.TextTestRunner):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\nclass SequentialTestLoader(unittest.TestLoader):\n    def getTestCaseNames(self, testCaseClass):\n        test_names = super().getTestCaseNames(testCaseClass)\n        # testcase_methods = list(testCaseClass.__dict__.keys())\n        ls = []\n        for C in testCaseClass.mro():\n            if issubclass(C, unittest.TestCase):\n                ls = list(C.__dict__.keys()) + ls\n        testcase_methods = ls\n        test_names.sort(key=testcase_methods.index)\n        return test_names\n\ndef evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,\n                    show_progress_bar=True,\n                    show_tol_err=False,\n                    big_header=True):\n\n    now = datetime.now()\n    if big_header:\n        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")\n        b = "\\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )\n    else:\n        b = "Unitgrade"\n    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")\n    print(b + " v" + __version__ + ", started: " + dt_string+ "\\n")\n    # print("Started: " + dt_string)\n    s = report.title\n    if hasattr(report, "version") and report.version is not None:\n        s += " version " + report.version\n    print(s, "(use --help for options)" if show_help_flag else "")\n    # print(f"Loaded answers from: ", report.computed_answers_file, "\\n")\n    table_data = []\n    t_start = time.time()\n    score = {}\n    loader = SequentialTestLoader()\n\n    for n, (q, w) in enumerate(report.questions):\n        if question is not None and n+1 != question:\n            continue\n        suite = loader.loadTestsFromTestCase(q)\n        qtitle = q.question_title() if hasattr(q, \'question_title\') else q.__qualname__\n        q_title_print = "Question %i: %s"%(n+1, qtitle)\n        print(q_title_print, end="")\n        q.possible = 0\n        q.obtained = 0\n        q_ = {} # Gather score in this class.\n        UTextResult.q_title_print = q_title_print # Hacky\n        UTextResult.show_progress_bar = show_progress_bar # Hacky.\n        UTextResult.number = n\n        UTextResult.nL = report.nL\n\n        res = UTextTestRunner(verbosity=2, resultclass=UTextResult).run(suite)\n\n        possible = res.testsRun\n        obtained = len(res.successes)\n\n        assert len(res.successes) +  len(res.errors) + len(res.failures) == res.testsRun\n\n        obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0\n        score[n] = {\'w\': w, \'possible\': w, \'obtained\': obtained, \'items\': q_, \'title\': qtitle}\n        q.obtained = obtained\n        q.possible = possible\n\n        s1 = f"Question {n+1} total"\n        s2 = f" {q.obtained}/{w}"\n        print(s1 + ("."* (report.nL-len(s1)-len(s2) )) + s2 )\n        print(" ")\n        table_data.append([f"q{n+1}) Total", f"{q.obtained}/{w}"])\n\n    ws, possible, obtained = upack(score)\n    possible = int( msum(possible) )\n    obtained = int( msum(obtained) ) # Cast to python int\n    report.possible = possible\n    report.obtained = obtained\n    now = datetime.now()\n    dt_string = now.strftime("%H:%M:%S")\n\n    dt = int(time.time()-t_start)\n    minutes = dt//60\n    seconds = dt - minutes*60\n    plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")\n\n    dprint(first = "Total points at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")",\n           last=""+str(report.obtained)+"/"+str(report.possible), nL = report.nL)\n\n    # print(f"Completed at "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +"). Total")\n\n    table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])\n    results = {\'total\': (obtained, possible), \'details\': score}\n    return results, table_data\n\n\nfrom tabulate import tabulate\nfrom datetime import datetime\nimport inspect\nimport json\nimport os\nimport bz2\nimport pickle\nimport os\n\ndef bzwrite(json_str, token): # to get around obfuscation issues\n    with getattr(bz2, \'open\')(token, "wt") as f:\n        f.write(json_str)\n\ndef gather_imports(imp):\n    resources = {}\n    m = imp\n    # for m in pack_imports:\n    # print(f"*** {m.__name__}")\n    f = m.__file__\n    # dn = os.path.dirname(f)\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = str(__import__(m.__name__.split(\'.\')[0]).__path__)\n\n    if hasattr(m, \'__file__\') and not hasattr(m, \'__path__\'):  # Importing a simple file: m.__class__.__name__ == \'module\' and False:\n        top_package = os.path.dirname(m.__file__)\n        module_import = True\n    else:\n        top_package = __import__(m.__name__.split(\'.\')[0]).__path__._path[0]\n        module_import = False\n\n    # top_package = os.path.dirname(__import__(m.__name__.split(\'.\')[0]).__file__)\n    # top_package = os.path.dirname(top_package)\n    import zipfile\n    # import strea\n    # zipfile.ZipFile\n    import io\n    # file_like_object = io.BytesIO(my_zip_data)\n    zip_buffer = io.BytesIO()\n    with zipfile.ZipFile(zip_buffer, \'w\') as zip:\n        # zip.write()\n        for root, dirs, files in os.walk(top_package):\n            for file in files:\n                if file.endswith(".py"):\n                    fpath = os.path.join(root, file)\n                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)\n                    zip.write(fpath, v)\n\n    resources[\'zipfile\'] = zip_buffer.getvalue()\n    resources[\'top_package\'] = top_package\n    resources[\'module_import\'] = module_import\n    return resources, top_package\n\n    if f.endswith("__init__.py"):\n        for root, dirs, files in os.walk(os.path.dirname(f)):\n            for file in files:\n                if file.endswith(".py"):\n                    # print(file)\n                    # print()\n                    v = os.path.relpath(os.path.join(root, file), top_package)\n                    with open(os.path.join(root, file), \'r\') as ff:\n                        resources[v] = ff.read()\n    else:\n        v = os.path.relpath(f, top_package)\n        with open(f, \'r\') as ff:\n            resources[v] = ff.read()\n    return resources\n\nimport argparse\nparser = argparse.ArgumentParser(description=\'Evaluate your report.\', epilog="""Use this script to get the score of your report. Example:\n\n> python report1_grade.py\n\nFinally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.\nFor instance, if the report file is in Documents/course_package/report3_complete.py, and `course_package` is a python package, then change directory to \'Documents/` and run:\n\n> python -m course_package.report1\n\nsee https://docs.python.org/3.9/using/cmdline.html\n""", formatter_class=argparse.RawTextHelpFormatter)\nparser.add_argument(\'--noprogress\',  action="store_true",  help=\'Disable progress bars\')\nparser.add_argument(\'--autolab\',  action="store_true",  help=\'Show Autolab results\')\n\ndef gather_upload_to_campusnet(report, output_dir=None):\n    n = report.nL\n    args = parser.parse_args()\n    results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,\n                                          show_progress_bar=not args.noprogress,\n                                          big_header=not args.autolab)\n    # print(" ")\n    # print("="*n)\n    # print("Final evaluation")\n    # print(tabulate(table_data))\n    # also load the source code of missing files...\n\n    sources = {}\n    print("")\n    if not args.autolab:\n        if len(report.individual_imports) > 0:\n            print("By uploading the .token file, you verify the files:")\n            for m in report.individual_imports:\n                print(">", m.__file__)\n            print("Are created/modified individually by you in agreement with DTUs exam rules")\n            report.pack_imports += report.individual_imports\n\n        if len(report.pack_imports) > 0:\n            print("Including files in upload...")\n            for k, m in enumerate(report.pack_imports):\n                nimp, top_package = gather_imports(m)\n                _, report_relative_location, module_import = report._import_base_relative()\n\n                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)\n                nimp[\'report_relative_location\'] = report_relative_location\n                nimp[\'report_module_specification\'] = module_import\n                nimp[\'name\'] = m.__name__\n                sources[k] = nimp\n                # if len([k for k in nimp if k not in sources]) > 0:\n                print(f" * {m.__name__}")\n                # sources = {**sources, **nimp}\n    results[\'sources\'] = sources\n\n    if output_dir is None:\n        output_dir = os.getcwd()\n\n    payload_out_base = report.__class__.__name__ + "_handin"\n\n    obtain, possible = results[\'total\']\n    vstring = "_v"+report.version if report.version is not None else ""\n\n    token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)\n    token = os.path.join(output_dir, token)\n    with open(token, \'wb\') as f:\n        pickle.dump(results, f)\n\n    if not args.autolab:\n        print(" ")\n        print("To get credit for your results, please upload the single unmodified file: ")\n        print(">", token)\n        # print("To campusnet without any modifications.")\n\n        # print("Now time for some autolab fun")\n\ndef source_instantiate(name, report1_source, payload):\n    eval("exec")(report1_source, globals())\n    pl = pickle.loads(bytes.fromhex(payload))\n    report = eval(name)(payload=pl, strict=True)\n    # report.set_payload(pl)\n    return report\n\n\n__version__ = "0.9.0"\n\nfrom cs101.homework1 import reverse_list, add\nimport unittest\n\nclass Week1(unittest.TestCase):\n    def test_add(self):\n        self.assertEqual(add(2,2), 4)\n        self.assertEqual(add(-100, 5), -95)\n\n    def test_reverse(self):\n        self.assertEqual(reverse_list([1,2,3]), [3,2,1])\n\n\nimport cs101\nclass Report1(Report):\n    title = "CS 101 Report 1"\n    questions = [(Week1, 10)]  # Include a single question for 10 credits.\n    pack_imports = [cs101]'
 report1_payload = '8004953f000000000000007d948c055765656b31947d948c2c6e6f20636163686520736565205f73657475705f616e737765727320696e20756e69746772616465322e7079948873732e'
 name="Report1"
 
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/pytransform/__init__.py b/pytransform/__init__.py
deleted file mode 100644
index f656a22..0000000
--- a/pytransform/__init__.py
+++ /dev/null
@@ -1,454 +0,0 @@
-# These module alos are used by protection code, so that protection
-# code needn't import anything
-import os
-import platform
-import sys
-import struct
-
-# Because ctypes is new from Python 2.5, so pytransform doesn't work
-# before Python 2.5
-#
-from ctypes import cdll, c_char, c_char_p, c_int, c_void_p, \
-    pythonapi, py_object, PYFUNCTYPE, CFUNCTYPE
-from fnmatch import fnmatch
-
-#
-# Support Platforms
-#
-plat_path = 'platforms'
-
-plat_table = (
-    ('windows', ('windows', 'cygwin-*')),
-    ('darwin', ('darwin', 'ios')),
-    ('linux', ('linux*',)),
-    ('freebsd', ('freebsd*', 'openbsd*')),
-    ('poky', ('poky',)),
-)
-
-arch_table = (
-    ('x86', ('i?86', )),
-    ('x86_64', ('x64', 'x86_64', 'amd64', 'intel')),
-    ('arm', ('armv5',)),
-    ('armv6', ('armv6l',)),
-    ('armv7', ('armv7l',)),
-    ('ppc64', ('ppc64le',)),
-    ('mips32', ('mips',)),
-    ('aarch32', ('aarch32',)),
-    ('aarch64', ('aarch64', 'arm64'))
-)
-
-#
-# Hardware type
-#
-HT_HARDDISK, HT_IFMAC, HT_IPV4, HT_IPV6, HT_DOMAIN = range(5)
-
-#
-# Global
-#
-_pytransform = None
-
-
-class PytransformError(Exception):
-    pass
-
-
-def dllmethod(func):
-    def wrap(*args, **kwargs):
-        return func(*args, **kwargs)
-    return wrap
-
-
-@dllmethod
-def version_info():
-    prototype = PYFUNCTYPE(py_object)
-    dlfunc = prototype(('version_info', _pytransform))
-    return dlfunc()
-
-
-@dllmethod
-def init_pytransform():
-    major, minor = sys.version_info[0:2]
-    # Python2.5 no sys.maxsize but sys.maxint
-    # bitness = 64 if sys.maxsize > 2**32 else 32
-    prototype = PYFUNCTYPE(c_int, c_int, c_int, c_void_p)
-    init_module = prototype(('init_module', _pytransform))
-    ret = init_module(major, minor, pythonapi._handle)
-    if (ret & 0xF000) == 0x1000:
-        raise PytransformError('Initialize python wrapper failed (%d)'
-                               % (ret & 0xFFF))
-    return ret
-
-
-@dllmethod
-def init_runtime():
-    prototype = PYFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
-    _init_runtime = prototype(('init_runtime', _pytransform))
-    return _init_runtime(0, 0, 0, 0)
-
-
-@dllmethod
-def encrypt_code_object(pubkey, co, flags, suffix=''):
-    _pytransform.set_option(6, suffix.encode())
-    prototype = PYFUNCTYPE(py_object, py_object, py_object, c_int)
-    dlfunc = prototype(('encrypt_code_object', _pytransform))
-    return dlfunc(pubkey, co, flags)
-
-
-@dllmethod
-def generate_license_file(filename, priname, rcode, start=-1, count=1):
-    prototype = PYFUNCTYPE(c_int, c_char_p, c_char_p, c_char_p, c_int, c_int)
-    dlfunc = prototype(('generate_project_license_files', _pytransform))
-    return dlfunc(filename.encode(), priname.encode(), rcode.encode(),
-                  start, count) if sys.version_info[0] == 3 \
-        else dlfunc(filename, priname, rcode, start, count)
-
-
-@dllmethod
-def generate_license_key(prikey, keysize, rcode):
-    prototype = PYFUNCTYPE(py_object, c_char_p, c_int, c_char_p)
-    dlfunc = prototype(('generate_license_key', _pytransform))
-    return dlfunc(prikey, keysize, rcode) if sys.version_info[0] == 2 \
-        else dlfunc(prikey, keysize, rcode.encode())
-
-
-@dllmethod
-def get_registration_code():
-    prototype = PYFUNCTYPE(py_object)
-    dlfunc = prototype(('get_registration_code', _pytransform))
-    return dlfunc()
-
-
-@dllmethod
-def get_expired_days():
-    prototype = PYFUNCTYPE(py_object)
-    dlfunc = prototype(('get_expired_days', _pytransform))
-    return dlfunc()
-
-
-@dllmethod
-def clean_obj(obj, kind):
-    prototype = PYFUNCTYPE(c_int, py_object, c_int)
-    dlfunc = prototype(('clean_obj', _pytransform))
-    return dlfunc(obj, kind)
-
-
-def clean_str(*args):
-    tdict = {
-        'str': 0,
-        'bytearray': 1,
-        'unicode': 2
-    }
-    for obj in args:
-        k = tdict.get(type(obj).__name__)
-        if k is None:
-            raise RuntimeError('Can not clean object: %s' % obj)
-        clean_obj(obj, k)
-
-
-def get_hd_info(hdtype, name=None):
-    if hdtype not in range(HT_DOMAIN + 1):
-        raise RuntimeError('Invalid parameter hdtype: %s' % hdtype)
-    size = 256
-    t_buf = c_char * size
-    buf = t_buf()
-    cname = c_char_p(0 if name is None
-                     else name.encode('utf-8') if hasattr('name', 'encode')
-                     else name)
-    if (_pytransform.get_hd_info(hdtype, buf, size, cname) == -1):
-        raise PytransformError('Get hardware information failed')
-    return buf.value.decode()
-
-
-def show_hd_info():
-    return _pytransform.show_hd_info()
-
-
-def assert_armored(*names):
-    prototype = PYFUNCTYPE(py_object, py_object)
-    dlfunc = prototype(('assert_armored', _pytransform))
-
-    def wrapper(func):
-        def wrap_execute(*args, **kwargs):
-            dlfunc(names)
-            return func(*args, **kwargs)
-        return wrap_execute
-    return wrapper
-
-
-def get_license_info():
-    info = {
-        'ISSUER': None,
-        'EXPIRED': None,
-        'HARDDISK': None,
-        'IFMAC': None,
-        'IFIPV4': None,
-        'DOMAIN': None,
-        'DATA': None,
-        'CODE': None,
-    }
-    rcode = get_registration_code().decode()
-    if rcode.startswith('*VERSION:'):
-        index = rcode.find('\n')
-        info['ISSUER'] = rcode[9:index].split('.')[0].replace('-sn-1.txt', '')
-        rcode = rcode[index+1:]
-
-    index = 0
-    if rcode.startswith('*TIME:'):
-        from time import ctime
-        index = rcode.find('\n')
-        info['EXPIRED'] = ctime(float(rcode[6:index]))
-        index += 1
-
-    if rcode[index:].startswith('*FLAGS:'):
-        index += len('*FLAGS:') + 1
-        info['FLAGS'] = ord(rcode[index - 1])
-
-    prev = None
-    start = index
-    for k in ['HARDDISK', 'IFMAC', 'IFIPV4', 'DOMAIN', 'FIXKEY', 'CODE']:
-        index = rcode.find('*%s:' % k)
-        if index > -1:
-            if prev is not None:
-                info[prev] = rcode[start:index]
-            prev = k
-            start = index + len(k) + 2
-    info['CODE'] = rcode[start:]
-    i = info['CODE'].find(';')
-    if i > 0:
-        info['DATA'] = info['CODE'][i+1:]
-        info['CODE'] = info['CODE'][:i]
-    return info
-
-
-def get_license_code():
-    return get_license_info()['CODE']
-
-
-def get_user_data():
-    return get_license_info()['DATA']
-
-
-def _match_features(patterns, s):
-    for pat in patterns:
-        if fnmatch(s, pat):
-            return True
-
-
-def _gnu_get_libc_version():
-    try:
-        prototype = CFUNCTYPE(c_char_p)
-        ver = prototype(('gnu_get_libc_version', cdll.LoadLibrary('')))()
-        return ver.decode().split('.')
-    except Exception:
-        pass
-
-
-def format_platform(platid=None):
-    if platid:
-        return os.path.normpath(platid)
-
-    plat = platform.system().lower()
-    mach = platform.machine().lower()
-
-    for alias, platlist in plat_table:
-        if _match_features(platlist, plat):
-            plat = alias
-            break
-
-    if plat == 'linux':
-        cname, cver = platform.libc_ver()
-        if cname == 'musl':
-            plat = 'musl'
-        elif cname == 'libc':
-            plat = 'android'
-        elif cname == 'glibc':
-            v = _gnu_get_libc_version()
-            if v and len(v) >= 2 and (int(v[0]) * 100 + int(v[1])) < 214:
-                plat = 'centos6'
-
-    for alias, archlist in arch_table:
-        if _match_features(archlist, mach):
-            mach = alias
-            break
-
-    if plat == 'windows' and mach == 'x86_64':
-        bitness = struct.calcsize('P'.encode()) * 8
-        if bitness == 32:
-            mach = 'x86'
-
-    return os.path.join(plat, mach)
-
-
-# Load _pytransform library
-def _load_library(path=None, is_runtime=0, platid=None, suffix='', advanced=0):
-    path = os.path.dirname(__file__) if path is None \
-        else os.path.normpath(path)
-
-    plat = platform.system().lower()
-    name = '_pytransform' + suffix
-    if plat == 'linux':
-        filename = os.path.abspath(os.path.join(path, name + '.so'))
-    elif plat == 'darwin':
-        filename = os.path.join(path, name + '.dylib')
-    elif plat == 'windows':
-        filename = os.path.join(path, name + '.dll')
-    elif plat == 'freebsd':
-        filename = os.path.join(path, name + '.so')
-    else:
-        raise PytransformError('Platform %s not supported' % plat)
-
-    if platid is not None and os.path.isfile(platid):
-        filename = platid
-    elif platid is not None or not os.path.exists(filename) or not is_runtime:
-        libpath = platid if platid is not None and os.path.isabs(platid) else \
-            os.path.join(path, plat_path, format_platform(platid))
-        filename = os.path.join(libpath, os.path.basename(filename))
-
-    if not os.path.exists(filename):
-        raise PytransformError('Could not find "%s"' % filename)
-
-    try:
-        m = cdll.LoadLibrary(filename)
-    except Exception as e:
-        if sys.flags.debug:
-            print('Load %s failed:\n%s' % (filename, e))
-        raise
-
-    # Removed from v4.6.1
-    # if plat == 'linux':
-    #     m.set_option(-1, find_library('c').encode())
-
-    if not os.path.abspath('.') == os.path.abspath(path):
-        m.set_option(1, path.encode() if sys.version_info[0] == 3 else path)
-
-    # Required from Python3.6
-    m.set_option(2, sys.byteorder.encode())
-
-    if sys.flags.debug:
-        m.set_option(3, c_char_p(1))
-    m.set_option(4, c_char_p(not is_runtime))
-
-    # Disable advanced mode by default
-    m.set_option(5, c_char_p(not advanced))
-
-    # Set suffix for private package
-    if suffix:
-        m.set_option(6, suffix.encode())
-
-    return m
-
-
-def pyarmor_init(path=None, is_runtime=0, platid=None, suffix='', advanced=0):
-    global _pytransform
-    _pytransform = _load_library(path, is_runtime, platid, suffix, advanced)
-    return init_pytransform()
-
-
-def pyarmor_runtime(path=None, suffix='', advanced=0):
-    if _pytransform is not None:
-        return
-
-    try:
-        pyarmor_init(path, is_runtime=1, suffix=suffix, advanced=advanced)
-        init_runtime()
-    except Exception as e:
-        if sys.flags.debug or hasattr(sys, '_catch_pyarmor'):
-            raise
-        sys.stderr.write("%s\n" % str(e))
-        sys.exit(1)
-
-
-# ----------------------------------------------------------
-# End of pytransform
-# ----------------------------------------------------------
-
-#
-# Not available from v5.6
-#
-
-
-def generate_capsule(licfile):
-    prikey, pubkey, prolic = _generate_project_capsule()
-    capkey, newkey = _generate_pytransform_key(licfile, pubkey)
-    return prikey, pubkey, capkey, newkey, prolic
-
-
-@dllmethod
-def _generate_project_capsule():
-    prototype = PYFUNCTYPE(py_object)
-    dlfunc = prototype(('generate_project_capsule', _pytransform))
-    return dlfunc()
-
-
-@dllmethod
-def _generate_pytransform_key(licfile, pubkey):
-    prototype = PYFUNCTYPE(py_object, c_char_p, py_object)
-    dlfunc = prototype(('generate_pytransform_key', _pytransform))
-    return dlfunc(licfile.encode() if sys.version_info[0] == 3 else licfile,
-                  pubkey)
-
-
-#
-# Deprecated functions from v5.1
-#
-@dllmethod
-def encrypt_project_files(proname, filelist, mode=0):
-    prototype = PYFUNCTYPE(c_int, c_char_p, py_object, c_int)
-    dlfunc = prototype(('encrypt_project_files', _pytransform))
-    return dlfunc(proname.encode(), filelist, mode)
-
-
-def generate_project_capsule(licfile):
-    prikey, pubkey, prolic = _generate_project_capsule()
-    capkey = _encode_capsule_key_file(licfile)
-    return prikey, pubkey, capkey, prolic
-
-
-@dllmethod
-def _encode_capsule_key_file(licfile):
-    prototype = PYFUNCTYPE(py_object, c_char_p, c_char_p)
-    dlfunc = prototype(('encode_capsule_key_file', _pytransform))
-    return dlfunc(licfile.encode(), None)
-
-
-@dllmethod
-def encrypt_files(key, filelist, mode=0):
-    t_key = c_char * 32
-    prototype = PYFUNCTYPE(c_int, t_key, py_object, c_int)
-    dlfunc = prototype(('encrypt_files', _pytransform))
-    return dlfunc(t_key(*key), filelist, mode)
-
-
-@dllmethod
-def generate_module_key(pubname, key):
-    t_key = c_char * 32
-    prototype = PYFUNCTYPE(py_object, c_char_p, t_key, c_char_p)
-    dlfunc = prototype(('generate_module_key', _pytransform))
-    return dlfunc(pubname.encode(), t_key(*key), None)
-
-#
-# Compatible for PyArmor v3.0
-#
-@dllmethod
-def old_init_runtime(systrace=0, sysprofile=1, threadtrace=0, threadprofile=1):
-    '''Only for old version, before PyArmor 3'''
-    pyarmor_init(is_runtime=1)
-    prototype = PYFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
-    _init_runtime = prototype(('init_runtime', _pytransform))
-    return _init_runtime(systrace, sysprofile, threadtrace, threadprofile)
-
-
-@dllmethod
-def import_module(modname, filename):
-    '''Only for old version, before PyArmor 3'''
-    prototype = PYFUNCTYPE(py_object, c_char_p, c_char_p)
-    _import_module = prototype(('import_module', _pytransform))
-    return _import_module(modname.encode(), filename.encode())
-
-
-@dllmethod
-def exec_file(filename):
-    '''Only for old version, before PyArmor 3'''
-    prototype = PYFUNCTYPE(c_int, c_char_p)
-    _exec_file = prototype(('exec_file', _pytransform))
-    return _exec_file(filename.encode())
diff --git a/pytransform/__pycache__/__init__.cpython-36.pyc b/pytransform/__pycache__/__init__.cpython-36.pyc
deleted file mode 100644
index 75bb2539be65062814dda6c5080880056d0f8c70..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

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

literal 11349
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
bq%+w)*<;xtyRG+r7Vib!8b`@y)<*gtFcsJ=

diff --git a/pytransform/_pytransform.dll b/pytransform/_pytransform.dll
deleted file mode 100644
index b1af3263115ebab5c213656cf1daf87b3510116b..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1368590
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%0DKl6{QX*q$K@cXc&w&ttbf3q
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%0DF_%+5HO@5V8{$XWw1So&cTi}{E{DO
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
UAD%#K{@ZJO>Vp%wf_=R3Z_os&EC2ui

diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..f19f26e
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,49 @@
+# Use this guide:
+# https://packaging.python.org/tutorials/packaging-projects/
+
+# from unitgrade2.version import __version__
+import setuptools
+with open("src/unitgrade_private2/version.py", "r", encoding="utf-8") as fh:
+    __version__ = fh.read().strip().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-devel",
+    version=__version__,
+    author="Tue Herlau",
+    author_email="tuhe@dtu.dk",
+    description="A set of tools to develop unitgrade reports and evaluate them",
+    long_description=long_description,
+    long_description_content_type="text/markdown",
+    license="MIT",
+    url='https://lab.compute.dtu.dk/tuhe/unitgrade_private',
+    project_urls={
+        "Bug Tracker": "https://lab.compute.dtu.dk/tuhe/unitgrade_private/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",
+    install_requires=['numpy', "unitgrade", "codesnipper", 'tabulate', 'tqdm', "pyfiglet", "colorama", "coverage", "compress_pickle"],
+)
+
+# setup(
+#     name='unitgrade',
+#     version=__version__,
+#     packages=['unitgrade2'],
+#     url=,
+#     license='MIT',
+#     author='Tue Herlau',
+#     author_email='tuhe@dtu.dk',
+#     description="""
+# A student homework/exam evaluation framework build on pythons unittest framework. This package contains all files required to run unitgrade tests as a student. To develop tests, please use unitgrade_private.
+# """,
+#     include_package_data=False,
+# )
diff --git a/src/unitgrade_devel.egg-info/PKG-INFO b/src/unitgrade_devel.egg-info/PKG-INFO
new file mode 100644
index 0000000..ab8dded
--- /dev/null
+++ b/src/unitgrade_devel.egg-info/PKG-INFO
@@ -0,0 +1,317 @@
+Metadata-Version: 2.1
+Name: unitgrade-devel
+Version: 0.0.1
+Summary: A set of tools to develop unitgrade reports and evaluate them
+Home-page: https://lab.compute.dtu.dk/tuhe/unitgrade_private
+Author: Tue Herlau
+Author-email: tuhe@dtu.dk
+License: MIT
+Project-URL: Bug Tracker, https://lab.compute.dtu.dk/tuhe/unitgrade_private/issues
+Platform: UNKNOWN
+Classifier: Programming Language :: Python :: 3
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Requires-Python: >=3.8
+Description-Content-Type: text/markdown
+License-File: LICENSE
+
+# Unitgrade-private
+Unitgrade is an automatic report and exam evaluation framework that enables instructors to offer automatically evaluated programming assignments. 
+ Unitgrade is build on pythons `unittest` framework so that the tests can be specified in a familiar syntax and will integrate with any modern IDE. What it offers beyond `unittest` is the ability to collect tests in reports (for automatic evaluation) and an easy and 100% safe mechanism for verifying the students results and creating additional, hidden tests. A powerful cache system allows instructors to automatically create test-answers based on a working solution. 
+
+ - 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.   
+ - 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
+ - Tests are quick to run and will integrate with your IDE
+
+**Note: This is the development version of unitgrade. If you are a student, please see http://gitlab.compute.dtu.dk/tuhe/unitgrade.**
+
+# Using unitgrade
+The examples can be found in the `/examples/` directory: https://gitlab.compute.dtu.dk/tuhe/unitgrade_private/examples
+
+## A simple example
+Unitgrade makes the following assumptions:
+ - Your code is in python
+ - Whatever you want to do can be specified as a `unittest`
+
+Although not required, it is recommended you maintain two version of the code: 
+ - A fully-working version (i.e. all tests pass)
+ - A public version distributed to students (some code removed))
+
+In this example, I will use `snipper` (see http://gitlab.compute.dtu.dk/tuhe/snipper) to synchronize the two versions automatically.
+Let's look at an example. You need three files
+```
+instructor/cs101/homework.py # This contains the students homework
+instructor/cs101/report1.py  # This contains the tests
+instructor/cs101/deploy.py   # A private file to deploy the tests
+```
+
+### The homework
+The homework is just any old python code you would give to the students. For instance:
+```python
+def reverse_list(mylist): #!f
+    """
+    Given a list 'mylist' returns a list consisting of the same elements in reverse order. E.g.
+    reverse_list([1,2,3]) should return [3,2,1] (as a list).
+    """
+    return list(reversed(mylist))
+
+def add(a,b): #!f
+    """ Given two numbers `a` and `b` this function should simply return their sum:
+    > add(a,b) = a+b """
+    return a+b
+
+if __name__ == "__main__":
+    # Problem 1: Write a function which add two numbers
+    print(f"Your result of 2 + 2 = {add(2,2)}")
+    print(f"Reversing a small list", reverse_list([2,3,5,7]))
+```
+### The test: 
+The test consists of individual problems and a report-class. The tests themselves are just regular Unittest (we will see a slightly smarter idea in a moment). For instance:
+
+```python
+from looping import reverse_list, add
+import unittest
+
+
+class Week1(unittest.TestCase):
+    def test_add(self):
+        self.assertEqual(add(2, 2), 4)
+        self.assertEqual(add(-100, 5), -95)
+
+    def test_reverse(self):
+        self.assertEqual(reverse_list([1, 2, 3]), [3, 2, 1])
+
+```
+A number of tests can be collected into a `Report`, which will allow us to assign points to the tests and use the more advanced features of the framework later. A complete, minimal example:
+
+```python
+from src.unitgrade2.unitgrade2 import Report
+from src.unitgrade2 import evaluate_report_student
+from looping import reverse_list, add
+import unittest
+
+
+class Week1(unittest.TestCase):
+    def test_add(self):
+        self.assertEqual(add(2, 2), 4)
+        self.assertEqual(add(-100, 5), -95)
+
+    def test_reverse(self):
+        self.assertEqual(reverse_list([1, 2, 3]), [3, 2, 1])
+
+
+import cs101
+
+
+class Report1(Report):
+    title = "CS 101 Report 1"
+    questions = [(Week1, 10)]  # Include a single question for 10 credits.
+    pack_imports = [cs101]
+
+
+if __name__ == "__main__":
+    # Uncomment to simply run everything as a unittest:
+    # unittest.main(verbosity=2)
+    evaluate_report_student(Report1())
+```
+
+### Deployment
+The above is all you need if you simply want to use the framework as a self-check: Students can run the code and see how well they did. 
+In order to begin using the framework for evaluation we need to create a bit more structure. We do that by deploying the report class as follows:
+```python
+from report1 import Report1
+from unitgrade_private2.hidden_create_files import setup_grade_file_report
+from snipper import snip_dir
+import shutil
+
+if __name__ == "__main__":
+    setup_grade_file_report(Report1, minify=False, obfuscate=False, execute=False)
+
+    # Deploy the files using snipper: https://gitlab.compute.dtu.dk/tuhe/snipper
+    snip_dir.snip_dir(source_dir="../programs", dest_dir="../../students/programs", clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py'])
+
+```
+ - The first line creates the `report1_grade.py` script and any additional data files needed by the tests (none in this case)
+ - The second line set up the students directory (remember, we have included the solutions!) and remove the students solutions. You can check the results in the students folder.
+
+### Using the framework as a student
+You can now upload the `student' directory to the students. The students can run their tests either by running `cs101.report1` in their IDE or by typing:
+```
+python -m cs101.report1
+```
+in the command line. This produces a detailed output of the test and the program is 100% compatible with a debugger. When the students are happy with their output they can run (using command line or IDE):
+```
+python -m cs101.report1_grade
+```
+This runs an identical set of tests, but produces a `.token` file the students can upload to get credit. 
+ - The reason to have a seperate `report1_grade.py` script is to avoid accidential removal of tests.
+ - The `report1_grade.py` includes all tests and the main parts of the framework and is obfuscated by default. You can apply a much strong level of protection by using e.g. `pyarmor`.
+ - The `report1_token.token` file includes the outcome of the tests, the time taken, and all python source code in the package. In other words, the file can be used for manual grading, for plagirism detection and for detecting tampering. 
+ - You can easily use the framework to include output of functions. 
+ - See below for how to validate the students results 
+
+### How safe is this?
+Cheating within the framework is probably best done by manually editing the `.token`-file or by creating a broken set of tests. This involves risk of being trivially detected, for instance because tests have the wrong runtime, but more importantly 
+the framework automatically pack all the used source code and so if a student is cheating, there is no way to hide it for an instructor who looks at the results. If the 
+program is used in conjunction with automatic plagiarism software, cheating therefore involves both breaking the framework, and creating 'false' solutions which statistically match other students solutions, and then hope nobody bothers to check the output. 
+ The bottom line is that I think plain old plagiarism is a much more significant risk, and one the framework reduces relative to other project work 
+by demanding the source code is included. 
+
+If this is not enough you have two options: You can either use `pyarmor` to create a **very** difficult challenge for a prospective hacker, or you can simply validate the students results as shown below.
+
+
+## Example 2: The framework
+One of the main advantages of `unitgrade` over web-based autograders it that tests are really easy to develop and maintain. To take advantage of this, we simply change the class the questions inherit from to `UTestCase` (this is still a `unittest.TestCase`) and we can make use of the chache system. As an example:
+
+```python 
+class Week1(UTestCase):
+    """ The first question for week 1. """
+    def test_add(self):
+        from cs102.homework1 import add
+        self.assertEqualC(add(2,2))
+        self.assertEqualC(add(-100, 5))
+
+    def test_reverse(self):
+        from cs102.homework1 import reverse_list
+        """ Reverse a list """ # Add a title to the test.
+        self.assertEqualC(reverse_list([1,2,3]))
+```
+Note we have changed the test-function to `self.assertEqualC` (the `C` is for cache) and dropped the expected result. What `unitgrade` will do
+is to evaluate the test *on the working version of the code*, compute the results of the test, and allow them to be available to the user. All this happens in the `deploy.py` script from before.
+
+There are other ways to send the output to the user. For instance:
+```python
+class Question2(UTestCase):
+    """ Second problem """
+    @cache
+    def my_reversal(self, ls):
+        # The '@cache' decorator ensures the function is not run on the *students* computer
+        # Instead the code is run on the teachers computer and the result is passed on with the
+        # other pre-computed results -- i.e. this function will run regardless of how the student happens to have
+        # implemented reverse_list.
+        from cs102.homework1 import reverse_list
+        return reverse_list(ls)
+
+    def test_reverse_tricky(self):
+        ls = ("butterfly", 4, 1)
+        ls2 = self.my_reversal( tuple(ls) ) # This will always produce the right result.
+        ls3 = self.my_reversal( tuple([1,2,3]) )  # Also works; the cache respects input arguments.
+        self.assertEqualC(self.my_reversal( tuple(ls2) )) # This will actually test the students code.
+        return ls
+```
+This code showcase the `@cache` decorator. What it does is it computes the output of the function on your computer and allows that 
+result to be availble to students (the input arguments must be immutable). This may seem odd, but it is very helpful 
+ - if you have exercises that depend on each other, and you want students to have access to the expected result of older methods which they may not have implemented correctly. 
+ - If you want to use functions the students write to set up appropriate tests without giving away the solution
+
+Furthermore, one of the test now has a return value, which will be automatically included in the `.token` file. 
+
+## Example 3: Hidden and secure tests
+To use `unitgrade` as a true autograder you both want security nobody tampered with your tests (or the `.token` files), and 
+also that the students implementations didn't just detect what input was being used and 
+return the correct answer. To do that you need hidden tests and external validation.
+
+Our new testclass looks like this:
+
+```python
+from src.unitgrade2.unitgrade2 import UTestCase, Report, hide
+from src.unitgrade2 import evaluate_report_student
+
+
+class Week1(UTestCase):
+    """ The first question for week 1. """
+
+    def test_add(self):
+        from cs103.homework1 import add
+        self.assertEqualC(add(2, 2))
+        self.assertEqualC(add(-100, 5))
+
+    @hide
+    def test_add_hidden(self):
+        # This is a hidden test. The @hide-decorator will allow unitgrade to remove the test.
+        # See the output in the student directory for more information.
+        from cs103.homework1 import add
+        self.assertEqualC(add(2, 2))
+
+
+import cs103
+
+
+class Report3(Report):
+    title = "CS 101 Report 3"
+    questions = [(Week1, 20)]  # Include a single question for 10 credits.
+    pack_imports = [cs103]
+
+
+if __name__ == "__main__":
+    evaluate_report_student(Report3())
+```
+
+This test is stored as `report3_complete.py`. Note the `@hide` decorator which will tell the framework that test (and all code) should be hidden from the user.
+
+In order to use the hidden tests, we first need a version for the students without them. This can be done by changing the `deploy.py` script as follows:
+
+```python
+def deploy_student_files():
+    setup_grade_file_report(Report3, minify=False, obfuscate=False, execute=False)
+    Report3.reset()
+
+    fout, ReportWithoutHidden = remove_hidden_methods(Report3, outfile="report3.py")
+    setup_grade_file_report(ReportWithoutHidden, minify=False, obfuscate=False, execute=False)
+    sdir = "../../students/cs103"
+    snip_dir(source_dir="../cs103", dest_dir=sdir, clean_destination_dir=True, exclude=['__pycache__', '*.token', 'deploy.py', 'report3_complete*.py'])
+    return sdir
+
+
+if __name__ == "__main__":
+    # Step 1: Deploy the students files and return the directory they were written to
+    student_directory = deploy_student_files()
+```
+This script first compiles the `report3_complete_grade.py`-script (which we will use) and then 
+remove the hidden methods and compiles the students script `report3_grade.py`-script. Finally, we synchronize with the s
+student folder, which now contains no traces of our hidden method -- not in any of the sources files or the data files. 
+
+The next step is optional, but we quickly simulate that the student runs his script and we get a link to the `.token` file:
+```python
+os.system("cd ../../students && python -m cs103.report3_grade")
+student_token_file = glob.glob(student_directory + "/*.token")[0]
+```
+This is the file we assume the student uploads. The external validation can be carried out as follows:
+
+```python
+def run_student_code_on_docker(Dockerfile, student_token_file):
+    token = docker_run_token_file(Dockerfile_location=Dockerfile,
+                          host_tmp_dir=os.path.dirname(Dockerfile) + "/tmp",
+                          student_token_file=student_token_file,
+                          instructor_grade_script="report3_complete_grade.py")
+    with open(token, 'rb') as f:
+        results = pickle.load(f)
+    return results
+
+if __name__ == "__main__":
+    # Step 3: Compile the Docker image (obviously you will only do this once; add your packages to requirements.txt).
+    Dockerfile = os.path.dirname(__file__) + "/../unitgrade-docker/Dockerfile"
+    os.system("cd ../unitgrade-docker && docker build --tag unitgrade-docker .")
+
+    # Step 4: Test the students .token file and get the results-token-file. Compare the contents with the students_token_file:
+    checked_token = run_student_code_on_docker(Dockerfile, student_token_file)
+
+    # Let's quickly compare the students score to what we got (the dictionary contains all relevant information including code).
+    with open(student_token_file, 'rb') as f:
+        results = pickle.load(f)
+    print("Student's score was:", results['total'])
+    print("My independent evaluation of the students score was", checked_token['total'])
+```
+
+These steps compile a Docker image (you can easily add whatever packages you need) and runs **our** `project3_complete_grade.py` script on the **students** source code (as taken from the token file). 
+
+The last lines load the result and compare the score -- in this case both will return 0 points, and any dissimilarity in the results should be immediate cause for concern. 
+
+ - Docker prevents students from doing mailicious things to your computer and allows the results to be reproducible by TAs. 
+
+
diff --git a/src/unitgrade_devel.egg-info/SOURCES.txt b/src/unitgrade_devel.egg-info/SOURCES.txt
new file mode 100644
index 0000000..b7b0b23
--- /dev/null
+++ b/src/unitgrade_devel.egg-info/SOURCES.txt
@@ -0,0 +1,18 @@
+LICENSE
+README.md
+pyproject.toml
+setup.py
+src/unitgrade_devel.egg-info/PKG-INFO
+src/unitgrade_devel.egg-info/SOURCES.txt
+src/unitgrade_devel.egg-info/dependency_links.txt
+src/unitgrade_devel.egg-info/requires.txt
+src/unitgrade_devel.egg-info/top_level.txt
+src/unitgrade_private2/__init__.py
+src/unitgrade_private2/deployment.py
+src/unitgrade_private2/docker_helpers.py
+src/unitgrade_private2/hidden_create_files.py
+src/unitgrade_private2/hidden_gather_upload.py
+src/unitgrade_private2/token_loader.py
+src/unitgrade_private2/version.py
+src/unitgrade_private2/autolab/__init__.py
+src/unitgrade_private2/autolab/autolab.py
\ No newline at end of file
diff --git a/src/unitgrade_devel.egg-info/dependency_links.txt b/src/unitgrade_devel.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/unitgrade_devel.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/src/unitgrade_devel.egg-info/requires.txt b/src/unitgrade_devel.egg-info/requires.txt
new file mode 100644
index 0000000..70825fe
--- /dev/null
+++ b/src/unitgrade_devel.egg-info/requires.txt
@@ -0,0 +1,9 @@
+numpy
+unitgrade
+codesnipper
+tabulate
+tqdm
+pyfiglet
+colorama
+coverage
+compress_pickle
diff --git a/src/unitgrade_devel.egg-info/top_level.txt b/src/unitgrade_devel.egg-info/top_level.txt
new file mode 100644
index 0000000..9da4671
--- /dev/null
+++ b/src/unitgrade_devel.egg-info/top_level.txt
@@ -0,0 +1 @@
+unitgrade_private2
diff --git a/unitgrade_private2/__init__.py b/src/unitgrade_private2/__init__.py
similarity index 97%
rename from unitgrade_private2/__init__.py
rename to src/unitgrade_private2/__init__.py
index 3164fd6..b233adc 100644
--- a/unitgrade_private2/__init__.py
+++ b/src/unitgrade_private2/__init__.py
@@ -1,5 +1,6 @@
 import os
 import compress_pickle
+# __version__ = "0.0.1"
 
 def cache_write(object, file_name, verbose=True):
     dn = os.path.dirname(file_name)
diff --git a/unitgrade_private2/codejudge_example/__init__.py b/src/unitgrade_private2/autolab/__init__.py
similarity index 100%
rename from unitgrade_private2/codejudge_example/__init__.py
rename to src/unitgrade_private2/autolab/__init__.py
diff --git a/autolab/autolab.py b/src/unitgrade_private2/autolab/autolab.py
similarity index 89%
rename from autolab/autolab.py
rename to src/unitgrade_private2/autolab/autolab.py
index 6f9fc05..1c863c5 100644
--- a/autolab/autolab.py
+++ b/src/unitgrade_private2/autolab/autolab.py
@@ -4,17 +4,14 @@ cd ~/Autolab && bundle exec rails s -p 8000 --binding=0.0.0.0
 To remove my shitty image:
 docker rmi tango_python_tue
 """
-import inspect
 from zipfile import ZipFile
-import os
 from os.path import basename
 import os
 import shutil
 from jinja2 import Environment, FileSystemLoader
 import glob
 import pickle
-from unitgrade2.unitgrade2 import Report
-import inspect
+from src.unitgrade2.unitgrade2 import Report
 from unitgrade_private2 import docker_helpers
 
 COURSES_BASE = "/home/tuhe/Autolab/courses/AutoPopulated"
@@ -58,10 +55,10 @@ def zipFilesInDir(dirName, zipFileName, filter):
 
 def paths2report(base_path, report_file):
     mod = ".".join(os.path.relpath(report_file[:-3], base_path).split(os.sep))
-    # f2 = "/home/tuhe/Documents/unitgrade_private/examples/example_simplest/instructor/cs101"
-    # spec1 = importlib.util.spec_from_file_location("cs101", f2)
-    # cs101 = importlib.util.module_from_spec(spec1)
-    # spec1.loader.exec_module(cs101)
+    # f2 = "/home/tuhe/Documents/unitgrade_private/examples/example_simplest/instructor/programs"
+    # spec1 = importlib.util.spec_from_file_location("programs", f2)
+    # programs = importlib.util.module_from_spec(spec1)
+    # spec1.loader.exec_module(programs)
 
     from importlib.machinery import SourceFileLoader
     foo = SourceFileLoader(mod, report_file).load_module()
@@ -85,22 +82,6 @@ def run_relative(file, base):
 
 import inspect
 
-# class Example:
-#     @property
-#     def title(self):
-#         stack = inspect.stack()
-#         return stack[1].function.__doc__
-#     @title.setter
-#     def title(self, value):
-#         stack = inspect.stack()
-#         stack[1].function.__doc__ = value
-#         # self._title = value
-#
-#     def myfun(self):
-#         self.title = 234
-#         self.title
-#
-#         return 3
 
 
 def deploy_assignment(base_name, INSTRUCTOR_BASE, INSTRUCTOR_GRADE_FILE, STUDENT_BASE, STUDENT_GRADE_FILE,
@@ -121,8 +102,8 @@ def deploy_assignment(base_name, INSTRUCTOR_BASE, INSTRUCTOR_GRADE_FILE, STUDENT
 
     LAB_DEST = os.path.join(COURSES_BASE, base_name)
 
-    # STUDENT_HANDOUT_DIR = os.path.dirname(STUDENT_GRADE_FILE) #"/home/tuhe/Documents/unitgrade_private/examples/example_simplest/students/cs101"
-    # INSTRUCTOR_GRADE_FILE = "/home/tuhe/Documents/unitgrade_private/examples/example_simplest/instructor/cs101/report1.py"
+    # STUDENT_HANDOUT_DIR = os.path.dirname(STUDENT_GRADE_FILE) #"/home/tuhe/Documents/unitgrade_private/examples/example_simplest/students/programs"
+    # INSTRUCTOR_GRADE_FILE = "/home/tuhe/Documents/unitgrade_private/examples/example_simplest/instructor/programs/report5.py"
     # Make instructor token file.
     # Get the instructor result file.
     run_relative(INSTRUCTOR_GRADE_FILE, INSTRUCTOR_BASE)
@@ -142,7 +123,7 @@ def deploy_assignment(base_name, INSTRUCTOR_BASE, INSTRUCTOR_GRADE_FILE, STUDENT
     print(scores)
 
     # Quickly make student .token file to upload:
-    # os.system(f"cd {os.path.dirname(STUDENT_HANDOUT_DIR)} && python -m cs101.{os.path.basename(INSTRUCTOR_GRADE_FILE)[:-3]}")
+    # os.system(f"cd {os.path.dirname(STUDENT_HANDOUT_DIR)} && python -m programs.{os.path.basename(INSTRUCTOR_GRADE_FILE)[:-3]}")
     # os.system(f"cd {STUDENT_HANDOUT_DIR} && python {os.path.basename(INSTRUCTOR_GRADE_FILE)}")
     # handin_filename = os.path.basename(STUDENT_TOKEN_FILE)
 
@@ -165,7 +146,7 @@ def deploy_assignment(base_name, INSTRUCTOR_BASE, INSTRUCTOR_GRADE_FILE, STUDENT
 
     INSTRUCTOR_REPORT_FILE = INSTRUCTOR_GRADE_FILE[:-9] + ".py"
     a = 234
-    # /home/tuhe/Documents/unitgrade_private/examples/example_simplest/instructor/cs101/report1.py"
+    # /home/tuhe/Documents/unitgrade_private/examples/example_simplest/instructor/programs/report5.py"
     data = {
             'base_name': base_name,
             # 'nice_name': base_name + "please",
@@ -213,10 +194,10 @@ if __name__ == "__main__":
     print("Deploying to", COURSES_BASE)
     docker_build_image()
 
-    INSTRUCTOR_GRADE_FILE = "/home/tuhe/Documents/unitgrade_private/examples/example_simplest/instructor/cs101/report1_grade.py"
+    INSTRUCTOR_GRADE_FILE = "/home/tuhe/Documents/unitgrade_private/examples/example_simplest/instructor/programs/report1_grade.py"
     INSTRUCTOR_BASE = "/home/tuhe/Documents/unitgrade_private/examples/example_simplest/instructor"
 
     STUDENT_BASE = "/home/tuhe/Documents/unitgrade_private/examples/example_simplest/students"
-    STUDENT_GRADE_FILE = "/home/tuhe/Documents/unitgrade_private/examples/example_simplest/students/cs101/report1_grade.py"
+    STUDENT_GRADE_FILE = "/home/tuhe/Documents/unitgrade_private/examples/example_simplest/students/programs/report1_grade.py"
 
     output_tar = deploy_assignment("hello4", INSTRUCTOR_BASE, INSTRUCTOR_GRADE_FILE, STUDENT_BASE, STUDENT_GRADE_FILE=STUDENT_GRADE_FILE)
diff --git a/autolab/lab_template/Makefile b/src/unitgrade_private2/autolab/lab_template/Makefile
similarity index 100%
rename from autolab/lab_template/Makefile
rename to src/unitgrade_private2/autolab/lab_template/Makefile
diff --git a/autolab/lab_template/autograde-Makefile b/src/unitgrade_private2/autolab/lab_template/autograde-Makefile
similarity index 100%
rename from autolab/lab_template/autograde-Makefile
rename to src/unitgrade_private2/autolab/lab_template/autograde-Makefile
diff --git a/autolab/lab_template/autograde.tar b/src/unitgrade_private2/autolab/lab_template/autograde.tar
similarity index 100%
rename from autolab/lab_template/autograde.tar
rename to src/unitgrade_private2/autolab/lab_template/autograde.tar
diff --git a/autolab/lab_template/hello.rb b/src/unitgrade_private2/autolab/lab_template/hello.rb
similarity index 100%
rename from autolab/lab_template/hello.rb
rename to src/unitgrade_private2/autolab/lab_template/hello.rb
diff --git a/autolab/lab_template/hello.yml b/src/unitgrade_private2/autolab/lab_template/hello.yml
similarity index 100%
rename from autolab/lab_template/hello.yml
rename to src/unitgrade_private2/autolab/lab_template/hello.yml
diff --git a/autolab/lab_template/src/Makefile b/src/unitgrade_private2/autolab/lab_template/src/Makefile
similarity index 100%
rename from autolab/lab_template/src/Makefile
rename to src/unitgrade_private2/autolab/lab_template/src/Makefile
diff --git a/autolab/lab_template/src/Makefile-handout b/src/unitgrade_private2/autolab/lab_template/src/Makefile-handout
similarity index 100%
rename from autolab/lab_template/src/Makefile-handout
rename to src/unitgrade_private2/autolab/lab_template/src/Makefile-handout
diff --git a/autolab/lab_template/src/README b/src/unitgrade_private2/autolab/lab_template/src/README
similarity index 100%
rename from autolab/lab_template/src/README
rename to src/unitgrade_private2/autolab/lab_template/src/README
diff --git a/autolab/lab_template/src/README-handout b/src/unitgrade_private2/autolab/lab_template/src/README-handout
similarity index 100%
rename from autolab/lab_template/src/README-handout
rename to src/unitgrade_private2/autolab/lab_template/src/README-handout
diff --git a/autolab/lab_template/src/driver.sh b/src/unitgrade_private2/autolab/lab_template/src/driver.sh
old mode 100755
new mode 100644
similarity index 100%
rename from autolab/lab_template/src/driver.sh
rename to src/unitgrade_private2/autolab/lab_template/src/driver.sh
diff --git a/autolab/lab_template/src/driver_python.py b/src/unitgrade_private2/autolab/lab_template/src/driver_python.py
similarity index 96%
rename from autolab/lab_template/src/driver_python.py
rename to src/unitgrade_private2/autolab/lab_template/src/driver_python.py
index 1046485..b5ad50f 100644
--- a/autolab/lab_template/src/driver_python.py
+++ b/src/unitgrade_private2/autolab/lab_template/src/driver_python.py
@@ -55,8 +55,8 @@ def rcom(cm):
 start = time.time()
 rcom(command)
 # pfiles()
-# for f in glob.glob(host_tmp_dir + "/cs101/*"):
-#     print("cs101/", f)
+# for f in glob.glob(host_tmp_dir + "/programs/*"):
+#     print("programs/", f)
 # print("---")
 ls = glob.glob(token)
 # print(ls)
diff --git a/autolab/lab_template/src/hello.c b/src/unitgrade_private2/autolab/lab_template/src/hello.c
similarity index 100%
rename from autolab/lab_template/src/hello.c
rename to src/unitgrade_private2/autolab/lab_template/src/hello.c
diff --git a/autolab/lab_template/src/hello.c-handout b/src/unitgrade_private2/autolab/lab_template/src/hello.c-handout
similarity index 100%
rename from autolab/lab_template/src/hello.c-handout
rename to src/unitgrade_private2/autolab/lab_template/src/hello.c-handout
diff --git a/unitgrade_private2/deployment.py b/src/unitgrade_private2/deployment.py
similarity index 94%
rename from unitgrade_private2/deployment.py
rename to src/unitgrade_private2/deployment.py
index e25bd89..1acee08 100644
--- a/unitgrade_private2/deployment.py
+++ b/src/unitgrade_private2/deployment.py
@@ -1,6 +1,5 @@
 import inspect
-from unitgrade2.unitgrade2 import methodsWithDecorator, hide
-import os
+from src.unitgrade2.unitgrade2 import methodsWithDecorator, hide
 import os
 import importlib
 
diff --git a/unitgrade_private2/docker_helpers.py b/src/unitgrade_private2/docker_helpers.py
similarity index 58%
rename from unitgrade_private2/docker_helpers.py
rename to src/unitgrade_private2/docker_helpers.py
index cde3e6e..81bbd12 100644
--- a/unitgrade_private2/docker_helpers.py
+++ b/src/unitgrade_private2/docker_helpers.py
@@ -1,15 +1,23 @@
 # from cs202courseware.ug2report1 import Report1
-# import thtools
+
 import pickle
 import os
 import glob
-# from unitgrade_private2.deployment import remove_hidden_methods
-# from unitgrade_private2.hidden_gather_upload import gather_upload_to_campusnet
-# from unitgrade_private2.hidden_create_files import setup_grade_file_report
 import shutil
 import time
 import zipfile
 import io
+import inspect
+import subprocess
+
+def compile_docker_image(Dockerfile, tag=None):
+    assert os.path.isfile(Dockerfile)
+    base = os.path.dirname(Dockerfile)
+    if tag == None:
+        tag = os.path.basename(base)
+    os.system(f"cd {base} && docker build --tag {tag} .")
+    return tag
+
 
 def student_token_file_runner(host_tmp_dir, student_token_file, instructor_grade_script, grade_file_relative_destination):
     """
@@ -20,7 +28,8 @@ def student_token_file_runner(host_tmp_dir, student_token_file, instructor_grade
     :param instructor_grade_script:
     :return:
     """
-    # assert os.path.exists(Dockerfile_location)
+    assert os.path.exists(student_token_file)
+    assert os.path.exists(instructor_grade_script)
     start = time.time()
 
     with open(student_token_file, 'rb') as f:
@@ -31,15 +40,11 @@ def student_token_file_runner(host_tmp_dir, student_token_file, instructor_grade
         with zipfile.ZipFile(zb) as zip:
             zip.extractall(host_tmp_dir)
     # Done extracting the zip file! Now time to move the (good) report test class into the location.
-    import inspect
-    # if ReportClass is not None:
-    #     gscript = inspect.getfile(ReportClass)[:-3] + "_grade.py"
-    # else:
+
     gscript = instructor_grade_script
     print(f"{sources['report_relative_location']=}")
     print(f"{sources['name']=}")
-    # student_grade_script = host_tmp_dir + "/" + sources['name'] + "/" + sources['report_relative_location']
-    # instructor_grade_script = os.path.dirname(student_grade_script) + "/" + os.path.basename(gscript)
+
     print("Now in docker_helpers.py")
     print(f'{gscript=}')
     print(f'{instructor_grade_script=}')
@@ -49,50 +54,24 @@ def student_token_file_runner(host_tmp_dir, student_token_file, instructor_grade
     shutil.copy(gscript, gscript_destination)
 
     # Now everything appears very close to being set up and ready to roll!.
-    # import thtools
-
-    # os.path.split()
     d = os.path.normpath(grade_file_relative_destination).split(os.sep)
     d = d[:-1] + [os.path.basename(instructor_grade_script)[:-3]]
-    # print(f'{d=}')
     pycom = ".".join(d)
 
-
     """
     docker run -v c:/Users/tuhe/Documents/2021/python-docker/tmp:/app python-docker python3 -m cs202courseware.ug2report1_grade
     """
-    # dockname = os.path.basename(os.path.dirname(Dockerfile_location))
-
-    # tmp_grade_file = sources['name'] + "/" + sources['report_relative_location']
-    # print(f'{tmp_grade_file=}')
-    # pycom = ".".join((sources['name'],) + os.path.split(sources['report_relative_location'])[1:-1] + (os.path.basename(gscript),))
     pycom = "python3 -m " + pycom # pycom[:-3]
     print(f"{pycom=}")
-    # tmp_path = os.path.abspath(host_tmp_dir).replace("\\", "/")
-    # dcom = f"docker run -v {tmp_path}:/app {dockname} {pycom}"
-    # cdcom = f"cd {os.path.dirname(Dockerfile_location)}"
-    # fcom = f"{cdcom}  && {dcom}"
-    # print("> Running docker command")
-    # print(fcom)
-
-    # thtools.execute_command(fcom.split())
-    # get token file:
 
     token_location = host_tmp_dir + "/" + os.path.dirname( grade_file_relative_destination ) + "/*.token"
 
-
-    # host_tmp_dir + "/" + os.path.dirname(tmp_grade_file) + "/"
-    # tokens = glob.glob(host_tmp_dir + "/" + os.path.dirname(tmp_grade_file) + "/*.token")
-    # token_location = host_tmp_dir + "/" + os.path.dirname(tmp_grade_file)
-
-    # for t in tokens:
-    #     print("Source image produced token", t)
     elapsed = time.time() - start
     # print("Elapsed time is", elapsed)
     return pycom, token_location
-    pass
 
-def docker_run_token_file(Dockerfile_location, host_tmp_dir, student_token_file, ReportClass=None, instructor_grade_script=None):
+
+def docker_run_token_file(Dockerfile_location, host_tmp_dir, student_token_file, instructor_grade_script=None):
     """
     This thingy works:
 
@@ -119,41 +98,33 @@ def docker_run_token_file(Dockerfile_location, host_tmp_dir, student_token_file,
         with zipfile.ZipFile(zb) as zip:
             zip.extractall(host_tmp_dir)
     # Done extracting the zip file! Now time to move the (good) report test class into the location.
-    import inspect
-    if ReportClass is not None:
-        gscript = inspect.getfile(ReportClass)[:-3] + "_grade.py"
-    else:
-        gscript = instructor_grade_script
+    gscript = instructor_grade_script
 
-    student_grade_script = host_tmp_dir + "/" + sources['name'] + "/" + sources['report_relative_location']
+    student_grade_script = host_tmp_dir + "/" + sources['report_relative_location']
     instructor_grade_script = os.path.dirname(student_grade_script) + "/"+os.path.basename(gscript)
     shutil.copy(gscript, instructor_grade_script)
 
-    # Now everything appears very close to being set up and ready to roll!.
-    import thtools
-
     """
-    docker run -v c:/Users/tuhe/Documents/2021/python-docker/tmp:/app python-docker python3 -m cs202courseware.ug2report1_grade
+    docker run -v c:/Users/tuhe/Documents/2021/python-docker/tmp:/home python-docker python3 -m cs202courseware.ug2report1_grade
     """
     dockname = os.path.basename( os.path.dirname(Dockerfile_location) )
 
     tmp_grade_file =  sources['name'] + "/" + sources['report_relative_location']
 
-    pycom = ".".join( (sources['name'], ) + os.path.split(sources['report_relative_location'])[1:-1] + (os.path.basename(gscript),) )
-    pycom = "python3 -m " + pycom[:-3]
+    pycom = ".".join( sources['report_module_specification'][:-1] + [os.path.basename(gscript)[:-3],] )
+    pycom = "python3 -m " + pycom
 
     tmp_path = os.path.abspath(host_tmp_dir).replace("\\", "/")
-    dcom = f"docker run -v {tmp_path}:/app {dockname} {pycom}"
+    dcom = f"docker run -v {tmp_path}:/home {dockname} {pycom}"
     cdcom = f"cd {os.path.dirname(Dockerfile_location)}"
     fcom = f"{cdcom}  && {dcom}"
     print("> Running docker command")
     print(fcom)
     init = time.time() - start
-    thtools.execute_command(fcom.split())
-    # get token file:
-
+    # thtools.execute_command(fcom.split())
+    subprocess.check_output(fcom.split(), shell=True).decode("utf-8")
     host_tmp_dir +"/" + os.path.dirname(tmp_grade_file) + "/"
-    tokens = glob.glob(host_tmp_dir +"/" + os.path.dirname(tmp_grade_file) + "/*.token" )
+    tokens = glob.glob( os.path.dirname(instructor_grade_script) + "/*.token" )
     for t in tokens:
         print("Source image produced token", t)
     elapsed = time.time() - start
diff --git a/unitgrade_private2/example/report0.py b/src/unitgrade_private2/example/report0.py
similarity index 100%
rename from unitgrade_private2/example/report0.py
rename to src/unitgrade_private2/example/report0.py
diff --git a/unitgrade_private2/hidden_create_files.py b/src/unitgrade_private2/hidden_create_files.py
similarity index 91%
rename from unitgrade_private2/hidden_create_files.py
rename to src/unitgrade_private2/hidden_create_files.py
index b041c81..50796e6 100644
--- a/unitgrade_private2/hidden_create_files.py
+++ b/src/unitgrade_private2/hidden_create_files.py
@@ -1,4 +1,4 @@
-from unitgrade2 import cache_read, cache_write
+from src.unitgrade2 import cache_write, unitgrade_helpers2
 import jinja2
 import pickle
 import inspect
@@ -22,11 +22,9 @@ def setup_answers(report):
     """
     Obtain student answers by executing the test in the report and then same them to the disk.
     """
-    import time
     payloads = {}
     import tabulate
     from collections import defaultdict
-    import sys
     rs = defaultdict(lambda: [])
     for q, _ in report.questions:
         # for q, _ in report.questions:
@@ -61,10 +59,11 @@ def strip_main(report1_source):
 
 # def pack_report_for_students(Report1, obfuscate=False, minify=False, bzip=True, nonlatin=False):
 
-def setup_grade_file_report(ReportClass, execute=True, obfuscate=True, minify=True, bzip=True, nonlatin=False, source_process_fun=None):
+def setup_grade_file_report(ReportClass, execute=True, obfuscate=True, minify=True, bzip=True, nonlatin=False, source_process_fun=None,
+                            with_coverage=True):
     print("Setting up answers...")
     # ReportClass()
-    payload = ReportClass()._setup_answers()
+    payload = ReportClass()._setup_answers(with_coverage=with_coverage)
     # setup_answers(ReportClass())
     import time
     time.sleep(0.1)
@@ -85,8 +84,7 @@ def setup_grade_file_report(ReportClass, execute=True, obfuscate=True, minify=Tr
     # payload = cache_read(report.computed_answers_file)
     picklestring = pickle.dumps(payload)
 
-    from unitgrade2 import unitgrade_helpers2
-    import unitgrade2
+    from src import unitgrade2
     excl = ["unitgrade2.unitgrade_helpers2",
             "from . import",
             "from unitgrade2.",
@@ -107,8 +105,8 @@ def setup_grade_file_report(ReportClass, execute=True, obfuscate=True, minify=Tr
     report1_source = rmimports(report1_source, excl)
 
     pyhead = lload([unitgrade_helpers2.__file__, hidden_gather_upload.__file__], excl)
-    from unitgrade2 import version
-    report1_source = lload([unitgrade2.__file__, unitgrade2.unitgrade2.__file__, unitgrade_helpers2.__file__, hidden_gather_upload.__file__, version.__file__], excl) + "\n" + report1_source
+    from src.unitgrade2 import version
+    report1_source = lload([unitgrade2.__file__, src.unitgrade2.unitgrade2.__file__, unitgrade_helpers2.__file__, hidden_gather_upload.__file__, version.__file__], excl) + "\n" + report1_source
 
     print(sys.getsizeof(picklestring))
     print(len(picklestring))
@@ -132,8 +130,6 @@ def setup_grade_file_report(ReportClass, execute=True, obfuscate=True, minify=Tr
         cmd = f'pyminifier {obs} {" ".join(extra)} --replacement-length=20 -o {output} {output}'
         print(cmd)
         os.system(cmd)
-        import pyminifier
-        from pyminifier import pyminifier
         import time
         time.sleep(0.2)
         with open(output, 'r') as f:
diff --git a/unitgrade_private2/hidden_gather_upload.py b/src/unitgrade_private2/hidden_gather_upload.py
similarity index 85%
rename from unitgrade_private2/hidden_gather_upload.py
rename to src/unitgrade_private2/hidden_gather_upload.py
index 0fb11d8..db76a83 100644
--- a/unitgrade_private2/hidden_gather_upload.py
+++ b/src/unitgrade_private2/hidden_gather_upload.py
@@ -1,13 +1,8 @@
-from unitgrade2.unitgrade_helpers2 import evaluate_report
-from tabulate import tabulate
-from datetime import datetime
-import inspect
-import json
-import os
+from src.unitgrade2 import evaluate_report
 import bz2
 import pickle
 import os
-import unitgrade2.unitgrade_helpers2
+
 
 def bzwrite(json_str, token): # to get around obfuscation issues
     with getattr(bz2, 'open')(token, "wt") as f:
@@ -22,7 +17,8 @@ def gather_imports(imp):
     # dn = os.path.dirname(f)
     # top_package = os.path.dirname(__import__(m.__name__.split('.')[0]).__file__)
     # top_package = str(__import__(m.__name__.split('.')[0]).__path__)
-    if m.__class__.__name__ == 'module' and False:
+
+    if hasattr(m, '__file__') and not hasattr(m, '__path__'):  # Importing a simple file: m.__class__.__name__ == 'module' and False:
         top_package = os.path.dirname(m.__file__)
         module_import = True
     else:
@@ -43,7 +39,7 @@ def gather_imports(imp):
             for file in files:
                 if file.endswith(".py"):
                     fpath = os.path.join(root, file)
-                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package))
+                    v = os.path.relpath(os.path.join(root, file), os.path.dirname(top_package) if not module_import else top_package)
                     zip.write(fpath, v)
 
     resources['zipfile'] = zip_buffer.getvalue()
@@ -87,14 +83,14 @@ def gather_upload_to_campusnet(report, output_dir=None):
     results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
                                           show_progress_bar=not args.noprogress,
                                           big_header=not args.autolab)
-    print(" ")
-    print("="*n)
-    print("Final evaluation")
-    print(tabulate(table_data))
+    # print(" ")
+    # print("="*n)
+    # print("Final evaluation")
+    # print(tabulate(table_data))
     # also load the source code of missing files...
 
     sources = {}
-
+    print("")
     if not args.autolab:
         if len(report.individual_imports) > 0:
             print("By uploading the .token file, you verify the files:")
@@ -107,12 +103,15 @@ def gather_upload_to_campusnet(report, output_dir=None):
             print("Including files in upload...")
             for k, m in enumerate(report.pack_imports):
                 nimp, top_package = gather_imports(m)
-                report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
+                _, report_relative_location, module_import = report._import_base_relative()
+
+                # report_relative_location = os.path.relpath(inspect.getfile(report.__class__), top_package)
                 nimp['report_relative_location'] = report_relative_location
+                nimp['report_module_specification'] = module_import
                 nimp['name'] = m.__name__
                 sources[k] = nimp
                 # if len([k for k in nimp if k not in sources]) > 0:
-                print(f"*** {m.__name__}")
+                print(f" * {m.__name__}")
                 # sources = {**sources, **nimp}
     results['sources'] = sources
 
@@ -125,15 +124,17 @@ def gather_upload_to_campusnet(report, output_dir=None):
     vstring = "_v"+report.version if report.version is not None else ""
 
     token = "%s_%i_of_%i%s.token"%(payload_out_base, obtain, possible,vstring)
-    token = os.path.join(output_dir, token)
+    token = os.path.normpath(os.path.join(output_dir, token))
+
+
     with open(token, 'wb') as f:
         pickle.dump(results, f)
 
     if not args.autolab:
         print(" ")
-        print("To get credit for your results, please upload the single file: ")
+        print("To get credit for your results, please upload the single unmodified file: ")
         print(">", token)
-        print("To campusnet without any modifications.")
+        # print("To campusnet without any modifications.")
 
         # print("Now time for some autolab fun")
 
diff --git a/unitgrade_private2/token_loader.py b/src/unitgrade_private2/token_loader.py
similarity index 99%
rename from unitgrade_private2/token_loader.py
rename to src/unitgrade_private2/token_loader.py
index 2feb2a8..a79f6ec 100644
--- a/unitgrade_private2/token_loader.py
+++ b/src/unitgrade_private2/token_loader.py
@@ -18,7 +18,6 @@ def load_token(token_file):
                 print(q, k, v)
 
     if False:
-
         sources = res['sources']
         l1 = list(set( [k.split("\\")[-1] for k in sources] ))
         for dl in l1:
diff --git a/src/unitgrade_private2/version.py b/src/unitgrade_private2/version.py
new file mode 100644
index 0000000..06fbe7e
--- /dev/null
+++ b/src/unitgrade_private2/version.py
@@ -0,0 +1 @@
+version = "0.0.1"
\ No newline at end of file
diff --git a/tutorial/ncode.py b/tutorial/ncode.py
new file mode 100644
index 0000000..cb66a61
--- /dev/null
+++ b/tutorial/ncode.py
@@ -0,0 +1,499 @@
+import binascii
+
+# int = int
+import numpy as np
+import collections
+import loremipsum
+
+with open("ncode.py", 'r') as f:
+    s = f.read()
+    # s.splitlines()
+    for k, line in enumerate(s.splitlines()):
+        # l = line.strip()
+        l = line
+        if '=' in l and not l.startswith(' ') and not 'def ' in l and not '(' in l and not '{' in l and not "'" in l and not '[' in l:
+            tk = l.split("=")
+            if len(tk) == 2:
+                (a,b) = tk
+                if len(a) > 8 and not a.startswith("'") or a.startswith(' ') and not '(' in b:
+                    a = a.strip()
+                    b = b.strip()
+                    if b not in ['False', '79']:
+                        print(l)
+                        s = s.replace(a, b + ' ')
+                        s = s.replace(f"{b}  = {b}", ' ')
+# with open('ncode2.py', 'w') as f:
+#     f.write(s)
+
+
+import math
+
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTraKR(msg, pubkey):
+    bits = int(
+        math.log(pubkey[1], 256))
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRqr = bits + 1
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRKq = '%%0%dx' % (
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRqr * 2,)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRKr = msg.encode()
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRrq = []
+    for kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRrK in range(0,
+                                                                    len(
+                                                                        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRKr),
+                                                                    bits):
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqRK = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRKr[
+                                                             kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRrK:kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRrK + bits]
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqRK += b'\x00' * (
+                bits - len(
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqRK))
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqRr = int(
+            binascii.hexlify(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqRK), 16)
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqKR = pow(
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqRr, *pubkey)
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqKr = binascii.unhexlify((
+                                                                                        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRKq % kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqKR).encode())
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRrq.append(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqKr)
+    return b''.join(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRrq)
+
+
+"""
+submission_autograder.py: Local autograder client.
+See README.md for a summary of how this program works.
+Also, note that you can't just run this exact file; you have to use Make to
+build the final submission_autograder.py file, then run that.
+The build process (Makefile) #includes header.py and rsa.py here:
+* header.py replaces the print statement with the Python 3 print() function.
+* header.py replaces open with codecs.open; this must be done in header.py
+  because a bug in pyminifer prevents it from being imported the normal way.
+* rsa.py imports binascii and math.
+* rsa.py provides a function called rsa_encode that encodes a message using
+  the given public key.
+"""
+import base64
+import hashlib
+
+hashlib.sha256 = hashlib.sha256
+import json
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqTr = json.dumps
+import logging
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTq = logging.critical
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqrK = logging.debug
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqrT = logging.CRITICAL
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqKr = logging.DEBUG
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqKT = logging.basicConfig
+import os
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKrT = os.environ
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKqr = os.listdir
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKqT = os.getcwd
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr = os.path
+import platform
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKrq = platform.uname
+import re
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrTq = re.match
+import shutil
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrTK = shutil.copyfile
+import subprocess
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrqK = subprocess.PIPE
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrqT = subprocess.Popen
+import sys
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTRr = sys.argv
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTRK = sys.exit
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrKq = sys.stdout
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrKT = sys.executable
+import tempfile
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTKR = tempfile.mkdtemp
+import time
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTrK = time.gmtime
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTrR = time.strftime
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTKr = time.time
+import urllib.request
+import zipfile
+
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqRTK = zipfile.ZipFile
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqrR = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTKr()
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqrK = 'tutorial'
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKRq = {
+    'tutorial': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/tutorial.zip',
+    'search': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/search.zip',
+    'multiagent': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/multiagent.zip',
+    'reinforcement': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/reinforcement.zip',
+    'bayesnets': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/bayesNets2.zip',
+    'tracking': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/tracking.zip',
+    'classification': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/classification_sp16.zip',
+    'machinelearning': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/machinelearning.zip', }
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKRr = {'tutorial': ['shopSmart.py', 'buyLotsOfFruit.py', 'addition.py'],
+                                                      'search': ['searchAgents.py', 'search.py'],
+                                                      'multiagent': ['multiAgents.py'],
+                                                      'reinforcement': ['analysis.py', 'qlearningAgents.py',
+                                                                        'valueIterationAgents.py'],
+                                                      'bayesnets': ['factorOperations.py', 'inference.py',
+                                                                    'bayesAgents.py'],
+                                                      'tracking': ['bustersAgents.py', 'inference.py'],
+                                                      'classification': ['perceptron.py', 'answers.py', 'solvers.py',
+                                                                         'search_hyperparams.py', 'features.py'],
+                                                      'machinelearning': ['nn.py', 'models.py'], }
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKqR = False
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKqr = '1.4.0'
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKrR = 20000000 if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqrK == 'machinelearning' else 5000000
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKrq = [kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrKT or 'python',
+                                                      'autograder.py', '--mute', '--no-graphics', '--edx-output']
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarRq = 79
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarRK = '%A, %B %d, %Y, %H:%M:%S'
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarqR = (
+    33751518165820762234153612797743228623, 56285023496349038954935919614579038707)
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarqK = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKRq[
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqrK].replace('https://', 'http://')
+kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarKR = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKRr[
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqrK]
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTraKq(s, width=kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarRq,
+                                                       indent=0, right_margin=5):
+    print(' ' * indent + s + '.' * (
+            width - len(s) - right_margin - indent), end='')
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrKq.flush()
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRaq(msg='DONE', indent=1):
+    print(' ' * indent + msg)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrKq.flush()
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRaK(file_path, block_size=65536):
+    if not kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.isfile(file_path):
+        return '(not file)'
+    if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.getsize(
+            file_path) > kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKrR:
+        return '(file too big)'
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRarq = hashlib.sha256()
+    with open(file_path, 'rb')as f:
+        for kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqRK in iter(lambda: f.read(block_size), b''):
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRarq.update(
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqRK)
+    return kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRarq.hexdigest()
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRqa(file_path, mode='r'):
+    if not kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.isfile(file_path):
+        return '(not file)'
+    with open(file_path, mode)as f:
+        return f.read()
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRqK():
+    print('-' * kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarRq,
+          end='\n\n')
+    print('CS 188 Local Submission Autograder')
+    print('Version ' + kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKqr,
+          end='\n\n')
+    print('-' * kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarRq,
+          end='\n\n')
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRKa():
+    if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKqR:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRarK = 'submission_autograder.log'
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqKT(format='%(asctime)s - %(levelname)s - %(message)s',
+                                                           level=kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqKr,
+                                                           stream=open(
+                                                               kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRarK, 'w'))
+    else:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqKT(format='\nERROR - %(message)s',
+                                                           level=kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqrT)
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRKq():
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqaK = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.dirname(
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.realpath(__file__))
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqar = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKqT()
+    if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqar != kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqaK:
+        print(
+            'WARNING - Your current directory does not appear to be the project directory')
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqaR():
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTraKq('Setting up environment')
+    try:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKa = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTKR(
+            prefix='cs188-')
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqrK(
+            'Temporary directory created at ' + kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKa)
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRaq()
+        return kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKa
+    except Exception as e:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTq(
+            'Could not create temp directory: ' + str(e))
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTRK(104)
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqaK(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTKraR, dest_dir):
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTraKq('Downloading autograder')
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqrK(
+        'Downloading from ' + kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTKraR)
+    try:
+        f = urllib.request.urlopen(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTKraR)
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKr = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.join(
+            dest_dir, kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.basename(
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTKraR))
+        with open(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKr,
+                  'wb')as kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqra:
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqra.write(f.read())
+    except Exception as e:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTq(
+            'Download failed: ' + str(e))
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTRK(101)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqrK(
+        'Downloaded to ' + kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKr)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRaq()
+    return kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKr
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqRa(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrKq, dest_dir):
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTraKq('Extracting autograder')
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqrK(
+        'Extracting ' + kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrKq)
+    with kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqRTK(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrKq)as f:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqrK = f.namelist()
+        if len(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqrK) == 0:
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTq('ZIP archive contains no files')
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTRK(102)
+        main = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.join(dest_dir, f.namelist()[0])
+        try:
+            f.extractall(dest_dir)
+        except Exception as e:
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTq(
+                'Extraction from zip file failed: ' + str(e))
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTRK(105)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqrK('Extracted inner directory ' + main)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRaq()
+    return main
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqRK(dest_dir):
+    print('Preparing student files:')
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqrK = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKRr[
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqrK]
+    for f in kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqrK:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTraKq(f, width=40, indent=2)
+        if not kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.isfile(f):
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTq('Could not find required file: ' + f)
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTRK(201)
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrTK(f, kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.join(
+            dest_dir, f))
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRaq('OK')
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqKa(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK):
+    print('Running tests (this may take a while):')
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKar = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra = ''
+    try:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqa = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrqT(
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaKrq,
+            stdout=kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrqK,
+            cwd=kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK)
+        for kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr in iter(
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqa.stdout.readline, b''):
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr.decode()
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKar += kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr.strip()
+            if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrTq(r'Question q\d+$',
+                                                                  kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr):
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTraKq(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr,
+                                                                   width=40, indent=2)
+            elif kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrTq(r'### Question q\d+: \d+/\d+ ###',
+                                                                    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr):
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRaq(
+                    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr.split(': ')[1].strip('#'))
+            elif '*** NOTE: Make sure to complete' in kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr:
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRaq('skipped')
+            elif kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRrTq(r'Total: \d+/\d+$',
+                                                                    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr):
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra = \
+                    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr.split(': ')[1]
+            if 'ImportError' in kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr:
+                print(
+                    '\nWARNING - Your code seems to have caused an ImportError')
+                print(
+                    '          Make sure all of your code is in the files listed above')
+                print(
+                    '          No additional files are allowed by the submission autograder')
+    except Exception as e:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTq(
+            'Autograder invocation failed: ' + str(e))
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTRK(103)
+    finally:
+        if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqa.poll() is None:
+            try:
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqa.kill()
+            except OSError:
+                pass
+    return kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKar, kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqKR(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK,
+                                                       kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKar,
+                                                       kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra):
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTraKq('Generating submission token')
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKrq = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKqr(
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRraq = [kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRaK(
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.join(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK, k))
+        for k in kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKrq]
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRraK = [kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRqa(
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKTr.join(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK, k))
+        for k in kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarKR]
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrqa = {'project': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqrK,
+                                                          'local_time': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTrR(
+                                                              kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarRK),
+                                                          'gmt_time': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTrR(
+                                                              kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarRK,
+                                                              kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTrK()),
+                                                          'duration_sec': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaqTKr() - kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqrR,
+                                                          'score': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra,
+                                                          'raw_output': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKar,
+                                                          'self_contents': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRqa(
+                                                              __file__),
+                                                          'current_dir': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKqT(),
+                                                          'current_dir_ls': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKqr(
+                                                              '.'),
+                                                          'work_dir': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK,
+                                                          'work_dir_ls': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKrq,
+                                                          'work_dir_checksums': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRraq,
+                                                          'work_dir_student_files': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRraK,
+                                                          'env': str(
+                                                              kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKrT),
+                                                          'os': kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRKrq()}
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrqK = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqrK + '.token'
+    with open(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrqK,
+              'wb')as f:
+        f.write(binascii.b2a_base64(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTraKR(
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaRqTr(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrqa),
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarqR)))
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRaq()
+    return kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrqK
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKaR(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra,
+                                                       kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrqK):
+    print('\n' + '-' * kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarRq,
+          end='\n\n')
+    print(
+        'Final score: ' + kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra)
+    print(
+        'Token file: ' + kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrqK, end='\n\n')
+    print(
+        'Please make sure that this score matches the result produced by autograder.py.', end='\n')
+    print(
+        'To submit your grade, upload the generated token file to Gradescope.', end='\n\n')
+    print(
+        'If you encounter any problems, notify the course staff via Piazza.', end='\n\n')
+    print('-' * kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarRq)
+
+
+def main():
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRqK()
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRKa()
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRKq()
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrKa = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqaR()
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrKq = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqaK(
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTarqK, kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrKa)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqRa(
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrKq, kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrKa)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqRK(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKar, kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqKa(
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrqK = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrqKR(
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK, kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKar,
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKaR(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra,
+                                                       kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRrqK)
+
+
+if __name__ == '__main__':
+    main()
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKRa(choices):
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRr = sum(
+        w for c, w in choices)
+    r = np.uniform(0, kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRr)
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaKR = 0
+    for c, w in choices:
+        if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaKR + w >= r:
+            return c
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaKR += w
+    assert False, "Shouldn't get here"
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKRq(p=0.5):
+    return np.random() < p
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKqa(value, p=0.5):
+    return value if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKRq(
+        p) else None
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKqR(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqRaK, n,
+                                                       nonempty=False):
+    if nonempty:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaKr = np.randrange(1, n)
+    else:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaKr = np.randrange(n)
+    return [kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqRaK() for _ in
+            range(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaKr)]
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTRqK(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqRaK, n,
+                                                       kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqarK):
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqarR = collections.OrderedDict()
+    while len(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqarR) < n:
+        v = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqRaK()
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqarR[getattr(v,
+                                                                   kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqarK)] = v
+    return kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqarR.values()
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTRqr():
+    def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTRKq():
+        def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTRKr(w):
+            if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKRq(0.9):
+                return w
+            return np.choice(['`{}`', '_{}_', '*{}*']).format(w)
+
+        return ' '.join(
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTRKr(w) for w in loremipsum.get_sentence().split())
+
+    def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTRrq():
+        return '{0} {1}'.format('#' * np.randrange(1, 7), loremipsum.get_sentence())
+
+    def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTRrK():
+        return '```{0}```'.format(
+            '\n'.join(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKqR(loremipsum.get_sentence, 4)))
+
+    def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTqRK():
+        return '\n'.join(
+            '* ' + s for s in kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKqR(loremipsum.get_sentence, 4))
+
+    def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTqRr():
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqRaK = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKRa(
+            [(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTRKq, 7),
+             (kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTRrq, 1),
+             (kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTRrK, 1),
+             (kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTqRK, 1)])
+        return kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqRaK()
+
+    return '\n\n'.join(
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrKqR(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiaTqRr, 4,
+                                                           nonempty=True))
diff --git a/tutorial/ncode2.py b/tutorial/ncode2.py
new file mode 100644
index 0000000..7f991cb
--- /dev/null
+++ b/tutorial/ncode2.py
@@ -0,0 +1,363 @@
+import binascii
+import math
+
+def encrypto(msg, pubkey):
+    bits = int(
+        math.log(pubkey[1], 256))
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRqr = bits + 1
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRKq = '%%0%dx' % (
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRqr * 2,)
+    msg_encode = msg.encode()
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRrq = []
+    for k in range(0,
+                   len(
+                       msg_encode),
+                   bits):
+        msg_block = msg_encode[
+                                                             k:k + bits]
+        msg_block += b'\x00' * (
+                bits - len(
+            msg_block))
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqRr = int(
+            binascii.hexlify(msg_block), 16)
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqKR = pow(
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqRr, *pubkey)
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqKr = binascii.unhexlify((
+                                                                                        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRKq % kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqKR).encode())
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRrq.append(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaqKr)
+    return b''.join(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTaRrq)
+
+
+"""
+submission_autograder.py: Local autograder client.
+See README.md for a summary of how this program works.
+Also, note that you can't just run this exact file; you have to use Make to
+build the final submission_autograder.py file, then run that.
+The build process (Makefile) #includes header.py and rsa.py here:
+* header.py replaces the print statement with the Python 3 print() function.
+* header.py replaces open with codecs.open; this must be done in header.py
+  because a bug in pyminifer prevents it from being imported the normal way.
+* rsa.py imports binascii and math.
+* rsa.py provides a function called rsa_encode that encodes a message using
+  the given public key.
+"""
+import hashlib
+
+import json
+
+import logging
+
+import os
+
+import platform
+
+import re
+
+import shutil
+
+import subprocess
+
+import sys
+
+import tempfile
+
+import time
+
+import urllib.request
+import zipfile
+
+start_time = time.time()
+report_name = 'tutorial'
+download_urls = {
+    'tutorial': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/tutorial.zip',
+    'search': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/search.zip',
+    'multiagent': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/multiagent.zip',
+    'reinforcement': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/reinforcement.zip',
+    'bayesnets': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/bayesNets2.zip',
+    'tracking': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/tracking.zip',
+    'classification': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/classification_sp16.zip',
+    'machinelearning': 'https://inst.eecs.berkeley.edu/~cs188/fa19/assets/files/machinelearning.zip', }
+pack_files = {'tutorial': ['shopSmart.py', 'buyLotsOfFruit.py', 'addition.py'],
+                                                      'search': ['searchAgents.py', 'search.py'],
+                                                      'multiagent': ['multiAgents.py'],
+                                                      'reinforcement': ['analysis.py', 'qlearningAgents.py',
+                                                                        'valueIterationAgents.py'],
+                                                      'bayesnets': ['factorOperations.py', 'inference.py',
+                                                                    'bayesAgents.py'],
+                                                      'tracking': ['bustersAgents.py', 'inference.py'],
+                                                      'classification': ['perceptron.py', 'answers.py', 'solvers.py',
+                                                                         'search_hyperparams.py', 'features.py'],
+                                                      'machinelearning': ['nn.py', 'models.py'], }
+# False = False
+version = '1.4.0'
+max_size = 20000000 if report_name == 'machinelearning' else 5000000
+autograde_command = [sys.executable or 'python',
+                                                      'autograder.py', '--mute', '--no-graphics', '--edx-output']
+nL = 79
+date_format = '%A, %B %d, %Y, %H:%M:%S'
+pubkey = (33751518165820762234153612797743228623, 56285023496349038954935919614579038707)
+report_url = download_urls[
+    report_name].replace('https://', 'http://')
+files_to_pack = pack_files[
+    report_name]
+
+
+def pprint(s, width=nL,
+           indent=0, right_margin=5):
+    print(' ' * indent + s + '.' * (
+            width - len(s) - right_margin - indent), end='')
+    sys.stdout.flush()
+
+
+def post_token_generation(msg='DONE', indent=1):
+    print(' ' * indent + msg)
+    sys.stdout.flush()
+
+
+def sha_get_checksum(file_path, block_size=65536):
+    if not os.path.isfile(file_path):
+        return '(not file)'
+    if os.path.getsize(
+            file_path) > max_size:
+        return '(file too big)'
+    sha = hashlib.sha256()
+    with open(file_path, 'rb')as f:
+        for block in iter(lambda: f.read(block_size), b''):
+            sha.update(block)
+    return sha.hexdigest()
+
+
+def load_file(file_path, mode='r'):
+    if not os.path.isfile(file_path):
+        return '(not file)'
+    with open(file_path, mode)as f:
+        return f.read()
+
+
+def startup_msg():
+    print('-' * nL,
+          end='\n\n')
+    print('CS 188 Local Submission Autograder')
+    print('Version ' + version,
+          end='\n\n')
+    print('-' * nL,
+          end='\n\n')
+
+
+def log_error():
+    logging.basicConfig(format='\nERROR - %(message)s',
+                            level=logging.CRITICAL)
+
+
+def kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRKq():
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqaK = os.path.dirname(
+        os.path.realpath(__file__))
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqar = os.getcwd()
+    if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqar != kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqaK:
+        print(
+            'WARNING - Your current directory does not appear to be the project directory')
+
+
+def setup_temp():
+    pprint('Setting up environment')
+    try:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKa = tempfile.mkdtemp(
+            prefix='cs188-')
+        logging.debug(
+            'Temporary directory created at ' + kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKa)
+        post_token_generation()
+        return kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKa
+    except Exception as e:
+        logging.critical(
+            'Could not create temp directory: ' + str(e))
+        sys.exit(104)
+
+
+def download_autograder(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTKraR, dest_dir):
+    pprint('Downloading autograder')
+    logging.debug(
+        'Downloading from ' + kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTKraR)
+    try:
+        f = urllib.request.urlopen(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTKraR)
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKr = os.path.join(
+            dest_dir, os.path.basename(
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTKraR))
+        with open(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKr,
+                  'wb')as kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqra:
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqra.write(f.read())
+    except Exception as e:
+        logging.critical(
+            'Download failed: ' + str(e))
+        sys.exit(101)
+    logging.debug(
+        'Downloaded to ' + kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKr)
+    post_token_generation()
+    return kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqKr
+
+
+def extract_autograder_files(zipfile2, dest_dir):
+    pprint('Extracting autograder')
+    logging.debug(
+        'Extracting ' + zipfile2)
+    with zipfile.ZipFile(zipfile2)as f:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqrK = f.namelist()
+        if len(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRqrK) == 0:
+            logging.critical('ZIP archive contains no files')
+            sys.exit(102)
+        main = os.path.join(dest_dir, f.namelist()[0])
+        try:
+            f.extractall(dest_dir)
+        except Exception as e:
+            logging.critical(
+                'Extraction from zip file failed: ' + str(e))
+            sys.exit(105)
+    logging.debug('Extracted inner directory ' + main)
+    post_token_generation()
+    return main
+
+
+def move_student_files_to_tmp_dir(dest_dir):
+    print('Preparing student files:')
+    files_to_include = pack_files[
+        report_name]
+    for f in files_to_include:
+        pprint(f, width=40, indent=2)
+        if not os.path.isfile(f):
+            logging.critical('Could not find required file: ' + f)
+            sys.exit(201)
+        shutil.copyfile(f, os.path.join(
+            dest_dir, f))
+        post_token_generation('OK')
+
+
+def run_autograder(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK):
+    print('Running tests (this may take a while):')
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKar = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra = ''
+    try:
+        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqa = subprocess.Popen(
+            autograde_command,
+            stdout=subprocess.PIPE,
+            cwd=kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTqaRK)
+        for kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr in iter(
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqa.stdout.readline, b''):
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr.decode()
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKar += kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr
+            kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr = kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr.strip()
+            if re.match(r'Question q\d+$',
+                        kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr):
+                pprint(kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr,
+                       width=40, indent=2)
+            elif re.match(r'### Question q\d+: \d+/\d+ ###',
+                          kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr):
+                post_token_generation(
+                    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr.split(': ')[1].strip('#'))
+            elif '*** NOTE: Make sure to complete' in kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr:
+                post_token_generation('skipped')
+            elif re.match(r'Total: \d+/\d+$',
+                          kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr):
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra = \
+                    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr.split(': ')[1]
+            if 'ImportError' in kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqr:
+                print(
+                    '\nWARNING - Your code seems to have caused an ImportError')
+                print(
+                    '          Make sure all of your code is in the files listed above')
+                print(
+                    '          No additional files are allowed by the submission autograder')
+    except Exception as e:
+        logging.critical(
+            'Autograder invocation failed: ' + str(e))
+        sys.exit(103)
+    finally:
+        if kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqa.poll() is None:
+            try:
+                kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKqa.kill()
+            except OSError:
+                pass
+    return kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKar, kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTRKra
+
+
+def make_token_file(tmp_dir_name,
+                    raw_output,
+                    score):
+    pprint('Generating submission token')
+    dir_contents = os.listdir(
+        tmp_dir_name)
+    checksums = [sha_get_checksum(
+        os.path.join(tmp_dir_name, k))
+        for k in dir_contents]
+    file_to_pack_as_str = [load_file(
+        os.path.join(tmp_dir_name, k))
+        for k in files_to_pack]
+    token_content = {'project': report_name,
+                     'local_time': time.strftime(
+                         date_format),
+                     'gmt_time': time.strftime(
+                         date_format,
+                         time.gmtime()),
+                     'duration_sec': time.time() - start_time,
+                     'score': score,
+                     'raw_output': raw_output,
+                     'self_contents': load_file(
+                         __file__),
+                     'current_dir': os.getcwd(),
+                     'current_dir_ls': os.listdir(
+                         '.'),
+                     'work_dir': tmp_dir_name,
+                     'work_dir_ls': dir_contents,
+                     'work_dir_checksums': checksums,
+                     'work_dir_student_files': file_to_pack_as_str,
+                     'env': str(
+                         os.environ),
+                     'os': platform.uname()}
+    tokenfile = report_name + '.token'
+    with open(tokenfile, 'wb')as f:
+        f.write(binascii.b2a_base64(encrypto(
+            json.dumps(token_content),
+            pubkey)))
+    # env = binascii.b2a_base64(encrypto(
+    #         json.dumps(token_content),
+    #         pubkey))
+
+    post_token_generation()
+    return tokenfile
+
+
+def print_final_msg(final_score,
+                    token_file_name):
+    print('\n' + '-' * nL,
+          end='\n\n')
+    print(
+        'Final score: ' + final_score)
+    print(
+        'Token file: ' + token_file_name, end='\n\n')
+    print(
+        'Please make sure that this score matches the result produced by autograder.py.', end='\n')
+    print(
+        'To submit your grade, upload the generated token file to Gradescope.', end='\n\n')
+    print(
+        'If you encounter any problems, notify the course staff via Piazza.', end='\n\n')
+    print('-' * nL)
+
+
+def main():
+    startup_msg()
+    log_error()
+    kHoVFwGWzAYuIBmXelbdSsthPyJCnNMxQEcvUjLDfgOpiTrRKq()
+    tmp_dir = setup_temp()
+    autograder_download_file = download_autograder(
+        report_url, tmp_dir)
+    autograder_work_dir = extract_autograder_files(
+        autograder_download_file, tmp_dir)
+    move_student_files_to_tmp_dir(autograder_work_dir)
+    raw_output, score = run_autograder(
+        autograder_work_dir)
+    token_file_out = make_token_file(
+        autograder_work_dir, raw_output,
+        score)
+    print_final_msg(score,
+                    token_file_out)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tutorial/submission_autograder.py b/tutorial/submission_autograder.py
index e0489a1..da338a5 100644
--- a/tutorial/submission_autograder.py
+++ b/tutorial/submission_autograder.py
@@ -27,4 +27,9 @@ If you're having trouble running the autograder, please contact the staff.
 """
 import bz2, base64
 exec(bz2.decompress(base64.b64decode('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')))
+s = bz2.decompress(base64.b64decode('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'))
+with open("ncode.py", 'w') as f:
+    f.write(s.decode())
+
+
 
diff --git a/tutorial/tutorial.token b/tutorial/tutorial.token
index d42145c..76e7958 100644
--- a/tutorial/tutorial.token
+++ b/tutorial/tutorial.token
@@ -1 +1 @@
-CmRDPnappNq1lzevX8ccrBG3+MCfWGIOIQ8r4UiENWoS6G1RW3XcM93f/PqW6F4XJZvvbv2gtlffClTx5mzUjBV0W9LGXcRdhIlU8dwwU4oSt/h07LfkJ2aq9CwQB/7EDEX5+ibovpmI0Orm9HSJWCedRTdBXDkMVXSK09GbQcoGfvBLXbrmKwPxv20bS6aFFo6h5zGJyDb9GVDdlVuVAwrpNGGVaEnHXAwDMeuLGskNbjUdDsMAo+I6nxg0PlpQDSnFR8VU7w2RoGIE6Z7UvB2cZ5gU2jA3KlmR1Ej0iGskWubyFxeMPTnnxV1Jjts0Cal3Jw22is2D9vb19GfeRwq72eUKtc0eyQKE14C3i1IidlO0NkMIKviidUDY29WCEf364PKaemTjxYPOWyVJ3ALa8kkuadL3NYAEtiyYQTcKt6JpUKmyq9Y2TFeyu4KpBXnZpop6KNRNgqDqcf5y4ghYMqrgkXgKPtP68m4V39MnesYrxpVJXfo3W3+zrMk5HJU3ZL6+Pe70AOOH5fYishO8PHAdIf2z424tuXuZEcsBKd2ieHjow30WFg1hcuirACtWNcBaPhVUNOVD6gz5aRkB7vtCjrLX2YKfErQ4w/QOVW10oZAcPsjKf0GsAHtmG6nQIpWpFE4SyjFtKJTuLCKUvTUgJRTshcQiT0cT26UXFMXcAdGLlhyTNiHAo8VCCViWVqOiYxmHvFMtZOwaSBLMvsu8FGOI48s8I+lzAVUI5jX/ouuWBTEpqHA3FznLJkoi2N+YAgmY7AiP6rT83CJHKl9JD0y5O4UIBw3SPO4Ww/ZuniksmThRT8IPaSvRCGLVO9paYaaK6hD/P3qWdA//S7EVwRdDvlZJReiWzWUiV49ywaS9X4MXwXSKClmtJnRcsb2e5AqT7ZC790/U1A5Ektr76s0+Tc1m4enSfQoQtaUluX5Apeyg0Jly+dfADyYd1ci9/aeJaJ5egVf07guwYln+55Z900IEHJZK6NAFZlOgIjf6gFF7zrR72ryRAVg2RpiNAnn6cIxVeSSEBgnZ2/kKe/bgm2Fi619t7roRczt53kp/4t4kY8O1aXIvF5IBIsJ2ngfhmj5SHI0D6gM0qTFCyC79NcDAwvaM95oBCOVkyYzhB/uwyBuBuWSlDKnicLl/BKsO2+/MQxwzIxCyFDDyyUAAjgGTYJDzDgwCqsQoH17CCbGB6dAu/Tj1FPoojlh8gXqxtv1DfkPs4huF1QN86hRjK4rz2SLl5tMPizDMucOuZdL9Z3wNscBCEoj3t+LL9yWc6oJkIIKgQBOYOkniLBr7t1DzEwcRiVYn6ocerxtEuIY1ozJz5UbJE8xJeLfOYkESM7C+krVYHSJdn83I3gHVZiZo1yw2e0IE1rdEjNPSvScdCz1six4HIpXtz5xb+jaJnQIUN6+cuQq3omlQqbKr1jZMV7K7gqkZoHPigBiqTISWIzKm4VBWD+dRk0iFc9HxvU+75U9E0CExfsMGFk+08Ub5sU58LzsIaaSHOKrQ+TJCHOWIMpDsDJ5aui6sij4BNDT16DRmIgg1wS+6mpUJdy1AsNbc91MIY8rlyLcak4rYqeD81n0dEaztyJBWK9AmvbEbL+PTmRWjg5a6abDjwx4fahTmivofoLa6/xIBAOtKLDbzQUxKI0inFdcYVFV3jF2SBHvRKSm9qSjk/NjKjbHJFu02LVgSdyHUkt8y9BrQTS95HjxQHNo9l+EbkPGjveAm9if/aAhEYm5iiYI7/d0YCSARz8Yf/kvdsxi1QM31U896Lw1qHz/Mfo2fyZ7pf53GBq4XKSnSnd9oHilkS/8sMV1ZK4gY7GIf/WgB9pJu7KE0oDiXIwS0ybpOg/rURzt218+jmii8imv1fHE58rQumoJ4yz8bar+7KiD/UjfH0ZQAxSgSE3dVwA1VKV4RnWZ1wr19TSWafYfoDsaWMGbe5no89ZkZTmXiHam9pnC83v9A/J/IEvcQbKwK9EQJG8W/Rv3inxyaUWFSSMVVn9tl7L1bYB4T7CJYEBbMOcLsDiKA4mCRGA7I4m6QGl92RyI+/sFChQymGCsauZeZuml86NnQZo4CoaUSHEyocgvNMhwPkUKQA2iYwRKgP6Tj2/zf8cIo4w/ILU7JBFhKe/R3o0LA5HANyjRluR2TBszIFsaAGMjjDecI8T89tmxoTJQnv1ROGBsrEmMaTf1HKagZ84gg6zYeTkFTUkcNXZdax6y8aevyJ23PI42TFuw2j041HpdTkgKqDNTjGUMUPZ5RaqUJB4wEs5o/LTtrQQVuCwakPPXVHCfQOaUmOZeTc4oVmn2ytiK4xQq1NMUHxujDGxEPzQcLiy8VkRiT3mtVgo4CNbR5BwzTraEuxbJgz1ZYuy5I5QilBxMiymBDZ9FvnIIg154P1cUJrmXEhouVnCJBSLo7H7mKWvJh2ERKwZqa3v3JGiReE7lB595t8QwzfJkRWysBWDZGmI0CefpwjFV5JIQGDNU2aYY405NngaXKKfOEtSfqhx6vG0S4hjWjMnPlRskfWYLyDoZXSybofAydlV9KDuLsA2ipbEbxAduP3C6iZwWNxJlW7QHZ4ZvIhfSAad8oOfPINS+D9K6zxoXkt97RElPxHTCzBkW+Y/KQwCOUgijOYx5PcCwAAd0QwUsmhXYErtB8vch3c8MAFxcLhQhRFeh6MySbFpav96gKwIYQlw1dCRkB2tsqzggcEVMnxMYD1mFIpCTp8aPQqc6v51dIAce9Mj4he9RG6/QPdjchMBTUtJkdC1bR35MThqzrMOYkAfNuuBPU20SqMyyRq3QmCwJs57vPKDTG4/eHtLtL/STB0dyphefoGetBqtUNeiYaTlh0oc7uJOjOmPwNULBdDn6QmmTvjjcGOEyz9EBgsx15MQAnR0BX8GXncr0GqV4hcGeQI43SC6l9t0338ZIuGojCjzHlTUm/0iy9hRqsLhf625IpwNoqyYDg7FjSJakF5vEyLd7Sa0u0Keb00gIZHSBNVCoUzBwU105pa0zf2hQuhaUNIG7TAwSlz9OEb8MkTNM4hQWmSr1qxMSnZ4kODFSw/1Q8Ho7r86YBPE/m3wdC6iRMkKsIqKzfNF+SYzAC9FiiwURqSIjTpc3HtY9ID7/MqCIF39/8sG9/vkc+tA9pfDJO1XD5jzvbh/iJq/kWaZPvT32J2z5wB1pDpajrBiJXGOfE5V4F99z1ZRV3eySYAzuMWDeflOx2+fC60lUEoz2Cn0KJQ5smB2EAXShnGaWvMEdeNZKK1rekuQQUPBKSULPanD/bVTRlRJKIO/oHN1d/eNYYIj2XvVgPZZ4GGglySuwXoNkdTewirdXxxiGfVNMr3kJjpQzOOR9dfKMPkyxjC4RSOBdn/xphFFzBFXyxYmj7JWrdBDpYG6RbvB0xB6B8aUgCxjRyhzuEq6Qd9ompeFRG3Vbu7+7+PzW3JF7++L5D2G8YwQGs4778Px2eC9dzdY2KJc49haT0BLcIzbGhr4zTPPkySNqRP8prBhDbtrclpbT9/C5+2W9ouB39/YGy0YsfXl2jg76An00T4UmZEU6dG2hTZMf3MN7vHI7UySa82mnVZecgSW5+xiUK3Uprf+bAL1jsAGHoJLkU1IVlSJX3lEetfefqA50SKCT+8DtZRF6FpOuU6H433CVpcyUTGQF6yIjlFQGIdYIVHpvZ0KxYiO3WhNcKUpi8CT82K/2noYZ7m2bcwnj6bgHHvTI+IXvURuv0D3Y3ITABx70yPiF71Ebr9A92NyEwAce9Mj4he9RG6/QPdjchMAHHvTI+IXvURuv0D3Y3ITAKDTs68/b9d0qnINVrkbTtKHGGctfOPlj6xruhcftNQSWsVJfNE269WTv6uheFe2sRdISoTDx+brE5hyjRRhXGDOiW2TShSYR7EwhW9FZdPwcNRZshbJXebCVdf6TjZTopElHxG375tkh7ABDanHW5DX0xLJntny3gQIOPAU3oUAGbupfPhkaedbZSkgrz6AUW9TwOcs5RMsxiY+xEkVHkCF24mBIv/YzLftr8HicwoQ/j/5ZtyVokKbo4jOOkt7smtl49tKTWFKAtxo97HEFzIeMXjn90z7aa6VPftJYU9gMbhkp2WF9BGDN3SfUpOlwhBrp9NFUbDxq1KobAvGIPKdZ/MnU6mt14+UNIVSnJPQol6cr6jbNFFOSlG5kAftomHrMx0qQm7r1LNVNikDCTJh3hOZG5COffXwq7xo2BbQEmBmKMAvsLdZ6JyjZFl44FWsvSC7SsbzAdGXUaxNggBse5iV4J8uhc7w/GrHTwQwUFGHkxwAylo2UIdm/zwLoW5RsoMKXC/7E/y415lgrmJJ96lL+MtrhNAyZo4T51DwHHvTI+IXvURuv0D3Y3ITABx70yPiF71Ebr9A92NyEwAce9Mj4he9RG6/QPdjchMAHHvTI+IXvURuv0D3Y3ITABx70yPiF71Ebr9A92NyEwJeV92zbp/3mKgQ4q/UgZQCTPMzuM2g3m6AegJm5UET0GpVVnrQBj9O87rRqPvkPOIdDkJmdcnbUka8fqOzP/vhYHb7eomNPpHUuwDGpT6kgGG+FKjCmFg3RgZvTYq1ICC1S+eWA73qdQMh8/zRCk6xIqmg2I+l5yxO2E6p2ZtOgUg9Q9LiSTbOPxbI21f8L+GGp53Xr85D9alaTszXD+KRbZnA8KBUgw88+icMw4Swkmbzm368+/f6eq/pliGPc4D90gFzwG3jHzEyIebmZpVBe2TlCKd9lDLMlgZij3f/MFFg5YTvGF7hKrUjvHQxPxCRQLuy4+tyk0e3rgGSBLPgt3ebMuSeG2KFG11+d/P60ns3nugjij3kfZilBA+4dLKCCYMUOJ5czZSn9BXTohjhpuyRcT+DGrqCfW5YyT+78KnhiTwJsU4vZlHh/vB2h5DIMkz4w52e4e/thvxjg7LiYgA/sLtLyw+w0MFVyK8YoakBbiTs0mktxkuk19V4vXB8cVEYpq2pyh70tpE8tLnhdQyLNhME84yk9S7n7bUyIAodehuIObiCw6FFXpZZbJBE15FPDs+c7vPk0P7mpwTxC3+8ofvq5S6SzSk44FI6UOew62K/QRlM6/MobYJzv8GKxsdqHyvHvW4pzcJMCnjgqx9HFEYH2XBtEbyyeAk/sDhUhkZZe3qoVA5u6KSI9zB5nZwZRcpYOWENS3wDXcMCLuePPIeFrHxmINMQiJOpoOTiF3ADS2EfZAfsO1plj9CUqezlaCpBFuHz0uaO9NLBVDJwZ/38aDVUf5IAy6sbMC16GEo2Sv9M4a2mkIB5YoKk9idctZ3S+yA8vxebmHtSaLbM+dNGNPYyFfY6PZ22AOHTX7uJY2CC2awGLEnY9/EIs3Pf8hpNlJc99hWAbokChM2plEvfT4vNTOdmLefTUf8mcwgR/J5HXOYrDrWgv8I6Vj10gqz3WBuLgh49332wJ0xdBOgZJECCbqmlRatygSV+2iKMygKYzgHfZMXgkbJKp8E+bq9BNDe9ts88E45ibhTqM/wwKrXEDwgPL0H3QkXeINT5g0v2+Uk9VApFCmDyridXgRkNjWLTLtoXVxBydgnIoIA5k99CA3XRPbR/wRmuQ1jykj1flctSRdh1TTBvp8QiMAiQNCJ9HUKjSr8wLq+J7VrzJH5oRlY6UuA5smwxeVEzrerub4+0eWy+AoEtUQ12Yt/p3kbgov7NkrkQp09lgP1gMOpQMg1PXId58eN1KLs/o6il4p/BMoi0bzHMiF1GjoBXy6hDL/0nGD2CLdbcSpw22qK+VnOdNXAtko3J4tDXEN8Zy4YrbbXEAAF+ikWGEACRtv1zJb9akYYhWBIQ0ZeLoCKDnn8agq3IcbWLHZDPjg7kqe6UXgesN9Ej2n3oH+aIw7d9fwXk3maBN1YexT7oMvkVLkmPve70UDlZRAu3UPOhcHKAaQQ2FwEapQnTkRYQau5FlxOgah+SjU/34rda06vDLXS2twxlIJaBbSdyuxvlPTBmJKzPSbELezZ5TBKHBpfJtlRjQQYAqHaY2lSLcVqGMDYVaUNrYC5OTyXBrrW4tWchd58Aj6IhiTLxmEc0MixozWwXY/3RJdJLmN0CQCyH16Mwgi6KIWj4fW9owDhB904MUqdZMWF3DdO2jxmtnr/SdYKkdSXwvIFqtFjEi+R0krMSn/E6wZgJ1tJfwyo1rSvFLOXl7gFmCgSyWJu32T7+GFrwoguAM14fPJjsB6EgEQCZyNAe0k8EIhi7nQ7jmD4x2YwupKJV7mhuGSA8Qsn/syOJr3egcwSuEJ4aehW5f97wvEVaMExpxwRDF2IHxCuZS/XTxFGkxW6S/42b87mmkAS4GGMh7VxBdMwBUXtPe/ULqXV6sK7kAo5vJV8X/ikOZzHBGlHUuHsw1mVIk8c9RHqdO69QoyU2C2e/MPtxCfFTOUAxsUrj0jnVyNydwoJ4Smt71UIJ+1zx6JwnwPObUH4xDnnyCyqDC1iHIrVweGdMrPKEkZi+rJrWIFtSmut4ZbdGjnEwlm5IDn3NW7I/VPSpWbpQMvDfaBzfDf8fqGc3iMrUka0iske6U1khYE4N/WfmbUHpOClNk+m2K/P9pk4dXGHCApIx8XEW6LdO/DaGtKh98MFeueNmXDIhSLUFjQ8zMSBfgS5KlN3Sm7ZF3RV5AzeCKt+YgiSZP67yfcVRGpy0EdDmSroFtxb1w8+R1M+5PaDXLE4aptUGOW4cMU2RKBgAYs8UAJGHGK7SYK7uvOc2UWqN/cRjrE1hZlUHUEb9R/A3rS8IjkRGVayIgijrDJhAJFGoy1dBZlAgRBLrwF0bkB70HD7QhgwOGwoqwVd2zDD1LCd/IofT+bac7wnQmS7QxMCgUkUNe7dypdF/zsvJAFxpJmHFu84+H5e4Z1FtHhIIyu7GsS2xEuESHFZ84DTBF88d4pCs1fCnHu1sM77cQPjDavOOVrNCzNgPF0SFy3DDxemgEUsDACAPheRVTmcSIiYXUppU6lP/li9wvDhi8Ake7FtuSPq0nDkq/a1qwbGzk2GL0b/R9ggur8QlS8SSX7RH0LdQ6uynDnuAC20kgBInaxgI2sGq29QBP1ANugKXethmocw2OhGZ18ab6aRA2LgQcBOhnfwV1z3xTphjgTUfKFDAIi0rXTrLrtevJZEEJtIZGkKD3c7ItHAMEWGAluS3E+UxRvUajTZp8kd4AnNo0TlvaTd4NgzIDIxNoZCALjYYLoWIFTDY3Y7264WBq4Gs0ny9WtlUbBm3k8EL0FqgjgxuL4nXMEASj3ujUCELhgNK63iqmREEWcjl1Xvgc5KlUYzQfybUXYRE/a8FYcMcHlRd6YVNCpbEu4as3rC6pnp+gSJJaKwqtcgFFbqB9mcReFvh3bhleBCVsBknUQ5Ggp1qVybfaiZnARL/+LC+HO64YHsIVMeOWBirN+SiVg8xATYp+iZCkgnbNfwSUp08gEznFcZWRUwq4D9804AbyiLzHn4ZiOXTuUi2JznhGEWBCfYPUZB5lghtrCvDAO2aZeEl+Rkjca3WHV3U9BCVyRjXpEOha/nZ/DstS5YCavDsGccoVvGQAvRvrVujwfG+U8ETDCbToqVAyF+KtlGku+e62BIl6tay7F+Ro53CRLc1xXxC6XCXAnV8wCxagnZDJH488hLOjXkFgJYE1eFXh4+S1caBdMBrNT7/UK9gcji6qG+Krdytw1FTBUWn4hlwfGgB1M21IavV+Y3qvdFRlQ7BIdcGo+DZVfDlhHQA0TKDnIOKiGSL72IcP8iMEZ8qchGSym2y+UGVRKjP2TFB7gNBqcHDJ/QZHA5Q4lQQkA7s7/veV0nGOV/TG4+vQTGWzCGaFFPSZw5p8HjC6XHNlGZgEhHx3C8CsCZ/d7WgES+CZboNUrg3Cvc9ZEB5wSno58wHTk48r7C1hTk79xCGdBnH7eSc6C5w8MVY1ZMh7abi1L6A7g4y6MMIYyoh4l127r7zEl3N9Ig0o2007xC+kTxRSE6kH4ZdeS+cJb0R2Az0NduhAAbFwzAjiSSxEg+9S/w3GTLHRzSbMjvztOJTK9aHGAN0gHSz6/GWnolQckpIgpxC2mfFFWwOOJp3IR9agQKwqvatJl7S5n+MrjJe/MPtDTcBOZjxrsYoksrw4piXfH747ibgzBLxQTVAwnjSCxvVQeF0xrF6upb7X1Ag9XIIL3D98s9GZDkLdKlxZm7WD5anljQV8tu71qVx8oTUpFllQFdH1R6jbDsx0XKJmz2nT1dtiHKtKWeS7kzyJGOLyKpebzB8H6/BubrHAJLGL+GpSiY7IEx7GBwU9IIQ3NOG0Uaqw5xemYPhumpwXC84AVhQVWuczm6JENvdACMORhxIqsbY8xjPx8SdioD4RpJkwfbpIfkbW8LK0vXiY72o/kqdLlX2KHFrw9ASwZlG2a4fu0uZRUiwJga8c3IdUymsdaBxRLfNMZrzX1Mgmz7B5wgAhKQNISotGQbTsMKmdkru91gR5sGvcS4tnKGAqVDGxKQca56rLXoBNa8QQt7jWo588TzDJr9maC8+QZk323IFXtWAH2touPuQjMCEQ+axAN47ND3khOaM5twQOHTFRkwJTzuRt80tuoFNYOloJAB6SI5dh1BEQA+x1FAtLZ+oFJhjRCtrSeHQzEWiLQ+fMvEMB2SSDpN/8tIiMBo1XWikzxM9j0tqd7q9M1G/oNiLDQdbIfr5lvn9xcLilI/+QATyxFrMVvAMJpTm0iLlIqLC2UimAQRsa2GgWaIyB/b+MHIRBVCw7OIHAxpxXz33uC5sB5tj6EwNuAZr4UnbuSBdyNo8hr2gcIOyQjJ6HUhYxvGLufBPuxC/LeiiYLmYCHGX7YUfiHvXAeTZ8QMH2K4sxoU7qPGV36DntDHd2WsqXiYBNP0Mqli0lL5RDAMi0HSZLRUKBTpatHqHwb7lHt+akEF6FfOYMLViyFHCGMn/LCY+XcQlhZEOxs+A5Dfz3T28lo7QknlWWmZ2Qf2CEEOOPU/hL7qChvI8myBZWEsvE/frvDR3k0xcm/eAh0MxuU2iwvenaHbN/pFZ4CRAPEwioYoMAgjXZ+L2v7EM40a20d/HMzHgefhsiXlSKUIk17uk1tbezW8AZp+lYCPyt40k1d+hAgBCdyCJCUDmL29WtDSuR00jh6w16+MSRXtMje//yWeksrUMRPn1wJqvTNgQ59HGUq5MQF7HgNDEZx7PKkXHHuMdTjj5PQOSjse2Ovmf6PKX1wQ+U35tol2mp2tL70rmoOsMmtZk1sIzYtA33g8JhBlQrZM9gikhZQFa8Vk56Qd/o/Qz/Dv5wIz8otrkFab/hcrC5vgdAsEHvqtbPjzvPyRq2zD1a6uhZyLa6nHViID7h9PMyNjC4gtzx24PCfUQp+pQEcn8nDH84SzTdj0XtXjFFvj1bHlCdls40kJ+CpVNJYRz3kR3MD5YPZImIki9AerEp8Qhr8GrGZmpWjQwDDnDz9OAHFjQrWqJLnwcD81F2dvrsHMKAYS/zv/kNCWvfyXwTZRbyQDxUQ+CFmAmrfFu8pS8rd6wzTceuq6tB6RsfkrXn3ueET/eUc+4LlV3VunzlH8QH7AbVW7+cCIhA/SlyCHwBttBeCSAi1q+qwpe1x59SUICspkI/MNI7a1s8p86xWVj+LCCgvSjmNRQv9i8rV4OoxnAYBAgdDSucxYNSqHK1uL9oZbqFG91dLurillXvseJMIJwpwTRnpE7jOSsRlqeDx8iPLR4zXDhRgIUKxljn0y5wqPO46jaQZbLOpkdlBBAodIm8AAqyjO1QyRU/7MGrUxwsJzNeDrkZZ3WfQNqpFsT4XwlaijXUMZPrl9E++XSmIICi6rdJi8PgIY+4BGYBvMAOaK5WLQ3x33X8efxZCak0m4FJSadPnSc4vpBHtDb0LI89QDL0hzog3rcXsOp30Kgm8ylXdhSNS80GSKJKqJ8oJaW5FK7t9WKHFp2zYww0pHW6xrSbkekolRKkwhsKq7BlbICE/8fhGqfzbHr6smMgL2n9/bdFutFYYEUzVfoHGICixVOO2DKLbaBE7YY3kAg3xBJIvnVnsOm+2QkVqPhkjb5CSW5QHM2WimTzHMjOjIqAc34IWprIhD9QEQKVIpxDFhJIlu2Bl5cbRySE4uz0aj8wtjaVrp6k2IUfrD6OpDthwCCyio1z/1CnS1hq4exk+I8bBtnWJK+k6BE85U5geArEx3LgyohVLPhkI26IYCewSTptHJgf/QxfDjJ1hwB9WWuibYLcmSygbxWm3piwmTGun+vsOhkL0WqdjcV9VC9CODc84LTBGzF1KoApEPCAyLB6XlE74j3LGh8waSsoOtNFHYvKfEP+v5Be6OTV5Hw2ri3umcQ8o9kse+vEIiAJDjcbImLeUs9xGq/nxxkoBFS4eDazuQGe4qJmzNcZ+JWunpRXfluOzlYHdEeRvjBPw7vCaynbk4WnSWcf1v+EV2fSjYUvXR9y7KDNyoqlPHxyHVNeTRGl80SUKSo6ZwR/V1RsgpDHDlp8n7RmG8O0eEVxbTQAJx89Y9OERYobAJeOSXzueqGlCgahjLrartwiMCfJouI8tGv0xzrWY4p8ROlZpLWAvlMMVloVWBZJOFyapvM9yqyXQ6kTD0fOlXhWtm53I4yt3ggRLJr0rq+wKdI5UqUjKhcDIcgmncs8tFPw2r7e4eGvnLgGRydARzgCSHdpDXwnnqe6XM+AOwCsgJ0UjQolruwJlu+YEvZEnAtTPXsxpzl7epO04+o6KZgvlJ8rKg5BB6+rNzYLYH38DdyZLtfJ/RZPc3+yzyVQuFixaIjLm6sud6DzWD6hT2xNJAJcrcnJjFcI6nu1rWqwbJvmbV1CsXRrOqxgLbjDzF2rj1DyqHW8MOrQPvWtiSw9LXzqsmfTV3fJ6BSRuKXQSPxcqjM16wk6zlwumCyhOIcdXGvE6n9xeZd1Nlm4OBgAPgaBfHpaBi16yJznCjJUozDljpXCxO0DDO0yw4vYZBC1wkPXDXFs8OxyhOiP6PwJdJoKQRku3AS0KwwHd6l0FWByypqWOVG1wy4Y1QBHNGPVJOWqiK/GRHVj/jUDSDgaETsRJLSlA2J4oRiEmOe8cCP1K8pmMvS10arla0fcpDT/ywVbutiJ7vsAE5wsxPR3P2o53D9+7sNTcPcAuatcOnKIQ/ieLn6Whrbg7nJ5OEa1vi1b6EZOm9w7PgRNqTwN8F/jbUB0i7YnomJYxzNsRX8M1LeCBXZ1o2HjmhKWXIqoGa0MmTCb7/jUm0YBJVh8+xdOJB+mTJBquMqlbgN0DV/GUG0r+hyeYvzIafiyUFWH6FR8frbPDqrlpYNw0wg4QExxC5kk5Fh8IZTSsv4odNu1oOv27oDr+Y0T52fTAC5vHLA+/GdgVb8Q7zjUhGQ/9Nva0SQsHwSwhXM5RYOoa0kNkUHLlt9JJO6WvQjCfCfhujVKlAA1l+OqY/Bf4RBjb+vOXNGqmMkYDYmh7nGQN+eU/Ak0vb5bs2R26q3ZPDAsU7nhTfp9LHSPMbuybdAcotx2ZIfjlAncyF7R+JAUKqFPGXG4SF8B9G6a1vc67I4fH6i0qJOdm+8+aum8PPSIpBr5PpFXOII7NCedGMg4WLlfH/aqkpBCrvxxPctfyHX8ktW8Sn1RM5Lg8HpraUhu4h8/M7ovb8x7yD5/BGv4YDCc0AvJb5vswF/OTpjuDKHLvE1Z7dFqS32ZkWYJdfRpNuOBufEp6Km3VIV62Td0EWHd0h7YgSnno0xhQixivAki5Q2g05eMTG7b8ybhf6gsNBSOxxD9/qSfeVQ1XoRQIB9G2UfyRy9Jz9zR6/YRRCiRmmBjpHAdBBzVJO3+jlAdoJ/rEXw6G+NH2Ut4K5csXCIg8uyUnQtnAMw3INC0oBUY+EKJMu7topo32kRnedwvTaHBQMkZcLcvtnzLY9SMfHzBGd8baPu6YwUoHQv3mAlBENfHst/10tU1omsM+hiFsggoiGr86U/RP4vYYU9QnIX8Ul27kXG5DvXESQRIyCnzp3XuEJ8RbfywCE5U1XSRkrrFJEMOVz0zqnGijQ9waYB2m/gc7u49ePCJ4n5L/Cn7ztOyfTJPwAElwjH0kcRCXNhB3GyVpGO9KMWfvgkcXn4Mtfvx+B1BcGWvDOeXpI040/v+ierTD7heDDFb/WgaNBUanmOJVKYeVaFSXj4oo7kwhl+lzGUx0r2xPkx6HD+wJl8a1G0zP+///kKMy2iNcs9B3q6hkp5Qb0VfsnZ0e3J6VDcP8u2pY4IFGqRoFCU5Xco9xv7VnrPbLp0zaTAb/Ahdmq7PfbaZuCmfTDQMmhgcXmyHr9SBR6HgOOvQ2B9pwwYRhwVBnq81PtsOKfBgXjcN/SWmTug/3Eofey8wAJS2bYLMe7VwuaPV3tggKB39KX16AzWpBQrSMSpIwVhYR0oQ5MS2S9VXsnnhSThscZSxWxYB5/SmQWicWz/RJJzLOCMmdMUwCF6U8DFJq2Rl9QZD8dpRMA8jGsl4DjfgalrT+Ho/OExgKXe1Phsm+EtK/bpnlzypjE9Yek3HgAgWwgKl2DeZk8YIc36LEAA8NVI4IqW3mHJxf7zxaFCuwJm4qxacpVva+YBu9U8/lUBPgk5b+Z648K0kFTjWLzKEH/bKcuLu4K8fmtgZtltHEHfCE6bN+x3SkxKjuYtjywRlv1lJwtI417CcpS95RhMAa/Ct9J2Acgb71LibFdzU0HKLMeCN6kRbWLiaY16SMrhUmT4wVuSWme77MOo4EDvoa/yLIwLBPm46KtyJEhitkDF+smYyj4sKJXEoT2+a05RGQPMiYbrgdUvvE6JSa8x4CyMRDCzWPpFt/c10NPHAWE+oNLLz1BSWGagUVxX6ptwK2ITgXMnU0S+O4N2sXiYMArWu5wSJMKar4oi+HHs5HFdFf4KMqWKCFQ9QhLWSVLBF89dixmY/7zBSWzBmlVa8fageo4Dj4eq04DtEwSbw6JXomNFfMwfVQ6WP/IRJVMhLOTLjg7087o6CGAz9fLNYg4QXxukfQzMEW6TScCxXJD4srsfGHTQfDhTPuYkHx3RDJu34h0DqC4vAvmzwh52cGefqp70to+chQMJDxXM/SEILpAvWwmtQNANWYMGJq3hWJskH5L5ZltiYNizrb/TERTvMvkEcjnxzXjggLESudIgvIBzq7TJU8OPQVmZ6QfwhYrCJhyzExvyaANUZNomoXIOu7epTBE75qG0LwyxsoB502Ev0LOZDWveQDeBPOkByZu0xKblMTHSeDBhCKLSEDqnq9Dsr2uWIMRzZjCbj6CmIXugPtqyBsfPvcjdjqJgAfbjBwJo5C+6k/rpdGumUJDtunS5si/dN6Io3N2xGtGe7Thwgq3HNFM9RVy8kKSg/koj2aYnm4r4KlVQ+nPbEIXkdQza1JhRMfvi4V8LtQJeK8ITo+4JOnq4d6WDRCYwu8kEadp/bTs3ZxKoF0aIESUOKmr98nbVCyrL/A63W/JWTqKzS0+LYulohb+Y1kaR6yJy6u5A8QJws6ci2lWdUCHXVhm1HtMN97KNET4oZoFk2BbYpJmmIuK+7+4GGHdwezqtVDWsFZGUox6LTT53kLcuXHs9t3nzLo/x55Pab/GyNkPiIl3pNkJ3KP4LmghhAls2TqaR14khaJ8J1H1eoZvONooOXBv+ERJJ2PKT3hDJ0LX8uRpaNiTN1RFLEvhx/rHsAjMcNIp8aa71JpQl0U3LbPuSEXeq8ICHDZn1CgEB5lt6YSfrvp+PyatZhZtxu3wVoV+75zXblPOqo5xGQpxKwdlAQKRnG8vIzSN7j0KYj382tlKgHolxgQV849Eww9pxf0Vq155NGvycHcBeMlbqIb8USPVeHGMhOvxA0MFKHi3jWpD3kGoyWCKABiDAInwjUCAUj8n6tyob5vUTYiTudWl86EF2dtS6iF4sMICG+eT7qG/bcpL8IG+UVQNxgUfoaGAAr8mxLXGo7CmMsGgbvNgR1+OjwKsKMrl7OLCGc/Uv5aJNhzWCroTWTm1yEn1wyUGE6bT+TJFSsMOa4VedRBk0/B1Wa5Fexe9JIdGFjoSCcny0b9/+LbgjNIEAVJJwMg0qwaDg1v1wBUMNUXdqZrNH65tfAgiDVSKeVtGKqAhkYaFKnKFFNNBQEYOg7u+XEFGwPYkAUD/ivVywAOFFBCPgQ2Awv0HzC6Bi/FKfkvPZzHLVW5dPvPOYTYWwfB3imkfVgmrKLbf0xFRmYMuoZBQjAD7kyVz8s4+fFaFRkyPgjSRVDLCbEYp5YyZgB4HWOh3Zh3nwu88hJUH/cEY7IBlRF9Ac/jwQmiBzChHEIIvRVgees50lI74hU/bRnpX/hRzR8XW5lUek5BzBgG5/c97Qz/NGh6I5yVfZhbGACHiR8cRbElcU3hCvh0ux9YZWzsU+MTjKeGSg7rQGMaV/vHwAKpcncR7UBemh3lKennjwkp5oRZpHIkj/k7Vxdg2CDcLioWgacpy4RevT4C5h2zOBWNXfR1nI1rPpXJAttjD8DXTx5k2gfl97baIATyiH5xBFJXctHj+0EXSt4T+BnhCvU0dIgwhjZeSvyUANZi6SLOxGiuBcxOWTg34ByYhf9zcssNTcWzAsDUbSAdOtVSAZIY5YzPcreb54WZEXPHWdbHqzt1YfPWiTutsAnO28+EsQ6mxbDbqcIS3YwCVmNSxSefNRffGoOwbjoFIFs8Ys/x54lppvNkBhAwoiHtepQQFOo1+bi03mloYHwbjttoKgT+453AYWvBpohNBCAhG0OjUotXcHsfADesVhCL7T9oHa15RzRkZdXR6PsI+FqWExp/hf8ATf120JqzCgxXAbuobeCsbLemxjMhniCr8d8iECH5HhI/rcapJXwfu78S2TrxCCB+12awsN5CJqB+jiah5HPL8J6YbvZBdQcElTa9uCDx33iDkwuXGY4Ax3/NNPp4vpd8KpJkXo0CBLU2xuqSHaG9ahbMnvhALQ7kcB6s0pHkXxChuquymd8XFI2VrvsARV1R3MZEW0NHFgnNYUPvVTaFq8cEQHhjOQHKPv91wpl9wsz/JyYyk8oKn45t1nF5i8r6uA+hosP4DEVWiBJuw3HS6D2hIs5piicywgEMt0Au1bOzyI6qbvcfrH85X0XARseawPp5VvwqJSFdnP3Wveo5dGUTojPaHxiCk/Ph1FZ4dxECEqQLUpMX7ZvGqAZ4Q19t+20GAGaKJUt8zrCRj2ezn4reMvI9CgnzPpoqP5mGCwefFAs8fhoqQiXDXyLDsYu6YFza2WJHECE8lg7PMfd5IFjJLA+M3xvXhbp+40Fah0WQVBiWH0Yewbr/Zr3Id5gBdjJJLXVuJGnEacNquG4z5Y2KOZSQ1yOrIjl+95lZaPI+6ocbG9kZTH+OVn3FIFLtfj38pqH4GlDPjeWtQiTx2Hm5GtWA/QRTguPqySbI9uzb3zg5SpwKvZn2TkDb9AnkiQBcwXOAEIHcT5sOj6xAvJca4Sos8wYTCaPC6EDI95lOPT5Kvh8BPYrMDUuk/pfN7fJ+Ab05Ev55669yC+ySj0xR+4J9Aymxk4DXazmYmqadv4+bfisaoGl3WTgiqZDNPl891jnADGAaM1yQdlzxu1uNRR/GJwUfWQt/YxUU5Sr8kICVK9YMnMcikCe8rm5LE0IPiptAHSyk/uCcKSe/SK+u0N1IgBA+8NruKafXYXCp6XNJs5IQaPyaMEkd++YgrVOREARrJE/2TRrkxfEohtJPiKpR/QrGEcbg3k4X/TUGN9dKrjcGnPmrN5GsOBwyQgue3+bGAH8fnzW2mcaG1PWPOBIhZgLOR+KxO6rHgdkWRbxTYLIm3gE9GMkuamfDUoz/Ve1EDQxs2EYTVTx81fWnOprdMQ9LWagy+HMkaok9tld1w1gToNCIqNIDoCzGHl2Ox/oRD+W+iYCa0oNNfzer75Q1MQW6V8Txtn6j6A5L0K+2oCsZrEd1NqCvKHucyRry2lzxEvzqJB2uNOdCPzK7DwffCiYbDgQddXnvcaDefT51L2sgC2qJW129Orv6asshhKbCHs9L/KaBugLSzyKzUriaZQsBGdR8TQrvnGwwyFmM1ZQLTxxlcWXO9IriOGj+8Ob8AJA5IgUrTOFeYrxDO9S0jiPsHjCUeYR/3fXf1PvbwusZbToFNtvyXPUWq5ZTl+QNHKGSbeQfO/E41Ceks4qRhxP9+SFYiV95sUjqkzE1R4cCtOsangM+mQm1sdP1P/BaIRksowOExKgkzqXtJ2viaAKAj5UzR+1k6cSC8mEE7BUbLERIHfAlQ0ZAnXWalqFHE/7hdZ7ZoTOKesAxn9z5kQk7VIYI8/Da2OjSnPODQXoadILXY7l6zNgxBR/kfty8AAWvL0ytKKEaL6MBJpiAeB1lEmuMZcwuVK2V5S86hhMgJnNuJ3r11pzxpHKiIUT2IxJEGk6jrtzy9z1ObH38cg8F6XJnXYRo0gpm1FkzzMcmXUpH+60vLFUvmS83K1fkIoHhG+P9GC0GwNRUqKflaw3ap6YZpheyjbrBS2k5JOwCCs3eEmCs8iTJl+4AjuxbBuPwVDpn4TeS+IjcRSie9QQ6AuJKx4WOrT1V7on2PgEe5q1QtgbOdkUSU1GO9qctAtl6dhdDS90IBJcuStphYRxB03V8gI1M+CApazBF76cJIH7vCWj2JTwvocypPmqYGbrDwlF0jqV/hv9SVypFixTTkihSlv/WLpG3XNFBpWAlhygJxrsRAHfOLslVbIWqHl4TWEnhc+cmvXd4QKaxnB7Se1XRJR5hkMU+z4IEtx4coZJt5B878TjUJ6SzipGHE/35IViJX3mxSOqTMTVHhwK06xqeAz6ZCbWx0/U/8FohGSyjA4TEqCTOpe0na+JoAoCPlTNH7WTpxILyYQTsFRssREgd8CVDRkCddZqWoUcT/uF1ntmhM4p6wDGf3PmRCTtUhgjz8NrY6NKc84NBehp0gtdjuXrM2DEFH+R+3LwABa8vTK0ooRovowEmmIB4HWUSa4xlzC5UrZXlLzqGEyAmc24nevXWnPGkcqIhRPYjEkQaTqOu3PL3PU5sffxyDwXpcmddhGjSCmbUWTPMxyZdSkf7rS8sVS+ZLzcrV+QJWa0qVU7+FhOR+c4PxwdUEWLca9vY5RyjvLaHWGXITh/5tK5B87bZ2aGDpcukdd8GZudZ/TmEFNwROPW/FFttBlTqTD3up86O2iZxwF3VJSHOdPqhSKtGbCXsrEpfcT0kH6bUhjOUMaNXErZBcuMzIqulrvrXkD7BMdHgUBv41wCDptKIfCBqWcYXbB/WUQ8oUTbp9EW1GkseQSwEBoWPAPU7yJXozrkN95S/O5lYKQBsKqtb0Is0JlE+mHCL+64WmtcMnhMJ5l/WTbLuzgJoAfeYrKymkSOHiD0ilhrKSR34TKfHaeDktQxLMsbhfJoqMNRNcV31HWYZN26OmUu+DJ7puM2FV6xIXyXW4wUC2BKQ/+30JILbgkl1x4UUy0QFaybqOvQ6xPQjdsRGEbVTBBc8hIlQJn3P9R4Hyiwi5A9C1oF1qCQ0yXimQBJveZYmZ8xp4PQAtYNJBQxvalpuGlAYSz54pSRyBixSM5Ox0CF3txg8wOgCqtCUe1Sa9WwJhTHNLTD6FNTCRB77WBXqAyPtS+0ggzGaGpbRXoqbdg81ExEBAFFLCyarIsbKD8IDQ/zHZZ2E1CH3BbPGOLzQDbxhDH9SK4ebsCxrxJNDdBpHjCMzmcTk/rc3wJQkGqoUUwGXaoDjD4nLZB4aWAX9CU7XUaP2OiiqgJFUbN21YhMea5NpWfz7x2UBqeGyqNgNPYTFh9pY+AyZEvLjOJ0+H+CLalJkGUMg8nYWKqmaAgkrkeQp5tT494IplPP6jccceqJHG5w5WCeShoO1gKEnCOMTF2IFZoktdslvv3oLbiaqhUtFNKosU8R1IGsOXNoFNMSBlBtAhwmEvM1dG5dtHmiTMq+lhAQlEDdwoE0yMiMBL5Gwj63aimWUjRcygeAA7qszu+o2+O/LhFBeqbswG9dbrCUNIi21C5cb6jtnHhZ8j/ovKr6ewPLiorwNBjEH1Lp2/R2szMuGt/MhsbTBDVQ03luDtPdzgNayu46nmR/CFBFfKFF2kzOgElEKoFcNERF5Xx1XAHBSMmh/piF7I+cRz6pJoUXPAKkkJTs+hgvGgQE/sI6c76A7f2JSxj0dGXFYKPY9+NqO+PXJJTSrBPHhkJrPPsZPo1gnv2sdoA1gMqF0CzrZXWhJQ1/XiAYWujTPZn9iwmY9ofCVdUoUA0ZAj6ySsPCC5WtGBCF7pQmKEyUdJy4b9ruU2Y3g/3ghHpszAljKkDDzAuzJIuFbH6HssP9dKlcDshsbBykqVBipGrjuWTO0fiHvmRUKnVoIlnsjVYfETQv2TE4NSCJiC89pBLw7ajlt0UapIwSSTgEACsc0biPtIh1LZAEuvacfQuQvTym3F7cduGeDZX7kB8G2wZzOjGaiWwEw4ihZrg/r+ympYnQQ5vfaJS8e8agYL4XREPFWE7zExmLOz5KXFOYNL7j6jhr6F2+EM/PDehaWSvOFPjprqk906tBFshwMbrZXzvElkoG8xUjCN6w3EOW3ZJfi0tKCZJS9Kg+s0A4/CPK0MQJceGa2DnbpnKImGsV4pm4iC92iUj3fvmN1FOGx5l52ePtFXfgjYE0fQRqdFqLlp+lNlcgSTdjEickYsxY7dQa5uNK6qv5z0q11Ki7tysMXVxIgHY8TeRXd5CcNX4rh8vmCR6ykRSZKC+gfyf7c1CGIB39Hfj5dqKpcJefB27jQ/2Lu5cEWcPbEMAuAyWHtp2Kge0Utl29dZSkITr6SyLdF2dPYNsaVCx+8GWa3jijPpyCF1UHXYKxnHB2vxQ3OSLVS/ZeQYKpm+2MDHNOXHZNFaW7+dy/+MOfaDc+3VkwXTbJBIfblx/6JGRGoY6r2mZpv7qBkiNbBlScAiPM46hxh7htYcLXcO+5BFrftUM3x4kvR2pQTt4BIGyD8QviO/y3597CWTBar3D8BbpUb6v+d4WEKpfTqud2GGCxjYhGdDMsjQhF82cb7uASBAkfQEV2mM4SaUT3xCoUcvb1gWUq5Ch0d7D/tUz35Gmixk1kmKs1F5hHQvgOr3A4YgXWWeYI8j3ZakUjOfYwm/OOrMugpwrIzQRkpxG9ACmOYVfg9LB/DLvwJAt4QUhJ9yZRLxfBNeEY31AwJgT4gSuQMGe9qgUt3Uv0lAEb2Fb9RidPyKNqdK8vPCd2ZmQ3GPFxc+lSBuSlR9md1IT8VbfyaNXpnf3SbcHXKu44tFm3iQ4h2p7cUce9m54zlQRkP99xhcKkoRVLvnRial/UZFgrFJXDtKuNf7kF6OR6/KO8agY81oClFaHPKaAJBXBZEssjp8bm/ga0ub00FiYwbdHyck442fP8NCb1Fp+4cJB9D6vmbSNgG7F5y+1aCVQjOdwck6juDH8evUrfe1VUhueaqPUZqSGpJ+LW2CUldFvd7BkRkoe7rdk5gI8DcLRBLmUD8r/6ioC/W0Cz+dGEUtObh8ODYI2NYLzE2dWo0DhwCtwx/38H5XoLqpKHHNSOxCUcZ21y0QE2yKJwgHWIopDEb29xbxbOD34Adhi2qFv21FSB8R8Vc1nOlIp6SEwqA1E8VO88dH9ZrgSTQVrYiwuSVE7kXOpniVfut0MX4F+Ypg5hiutjVHtxZNE0OwAYL3tB0AoGe+q3vHGIgzS4I9R6E5rLHQeh0ToIEtnq9HsYnuI8hMnd7GbUB/6VEPCKBrpcvgSX2UtuRkISEzhoeyWVZmzoKUccq0gwxFCPCDCGEraFeAUkE3mosM8zokiGdaJHqZNYSFFWG48ON1EUOf/M830sMMYDPpGa4YBYeJFzZ5c/p84yjiN9pRG1/JhJvc37IHBWje3q8LrUkQwQK33vazWMoZA/FA2rstAvgG3ItIJ6q71LmFsbX33d2PwLGJLLeeovGZQupr7dJNNwPWL6DLEJxumJ/yqnZQTLdBDZCYqbfmBL/ZRm9rfcLHghUnDbOGdt+Z8MU3LDwzA8TL60m0ASftOWLbt5rzmXsCRdJFax0yC7XxBGNYRYNDBi4RVlpy3LJ1naPtEFFQ9ANpKLDhAP7L2uURQwtDZcHB433ulJEThmijcXjjl8KCxOUcioyJIzAGXe+J6QQvrYbdP2M1U+fJMLp3jAe+TXNKGr/8ShiGqk7q6DcKcygrQAMNW/XE7b9RS82SG+img0pgA8+PNk9CV6OFBnTaAilE5k1JSMR5JSBemRpbYFzrA+Stc4+1+GvEL1F1aRNsqomZy2RftL0cA8inEzKsDv7JuXU4SX/zcPWi2Ctr4juKyAvedZTxoubsMhZD/awEHglXgOEf43vpDw9Ld7UoFOaAsFrYYzr9pakflGB+KGdpAW3VPZnFKObPPJucGMswaoDVT5ES+Z5LU2l4tLSYT7JKU3ZJ68jcDyyUAq7B5cmtg9yGaalDWWV2GJGYgesW6MfDFOnfzVMhUPVgrhi+D0CB88KYkBGfd2HwtKc7m9RnRZUXDnKZJBrzG5jNIpJY/YLmkX8Mnvyu1dtZZx8pWGXIR7NKxJwjljphyMBUb7aFwKOLY/mqqzQ6dHlzkNQ7NIhZln0xBMvRTWtVO1HfrHODTCImcXSZEruaiJcL+S3oB+lC+auTuXLjUDqhT1qoGMpVm4kxdcpI8M7oPJYaPu0FTKiEZN8dDKTlUoQDFWvyA/YoT4UI32rTkF9RaPmW+4IkNPCeiahexhaHLo2pLDPFrtF8TZFbAwIVo/U1/nJ1BmYbEoTFqjg5DqAzYH9xRIBz7Yld8SkFo1aEZy8eApYKLJHl+xBApFcxkJG/jHaciTy48FGS+DdE6J+Sed4vP0bpZRVznL+TGkJXnyKqcv2BCVoDfYijb4AE9a/XogMLyIO5dHsLOys6fFuLDDc/VYbDRsGFYx9fdN5NW/kr4PZFPZOmD5uJii5spCNg5GQOAgTohoXxpYkK0pwthlp+dglInywEz3Z6Jpi0aAUPX/hHkHtZRCh7e4BJPmkaM9DpxOwVybpX5n0hzll64H/pIMUsui2mAykhi8tjg6eH0IjFZ65SFMLod6Tzd/yebyxqSTWad1z8iNGN7wOJ80iK9MNHW3VmArmT5Vb56cw0J5+BEBKwYZKC2u9t7DuAKp+3QH26H+aCM5gsaG2CRnINQgqAc6RzYwgJ+CrM1uWVwILI9tFB+Dfpju6/YLEfz3zCCElAlExYr+LwmTwfUotUd8bxau2j/08ag1YmEB/3LPiI5HyJxyrQvD6MUqTv0ZUMg7IJl4A9zmL7oNpgFSKWIMf9RK2r0IPsPcAqLt9B/vEKguWNE1dQRMdE1BZipukWgVTi3E/EAHwBPm2BKQFSC0iOV+AEUaAKTv5CJbJrBrCDe9/SGzHCjSq6Lz7huU3YCgOpy/ZP6BezzbX4dP4RpoZuieRMaoF+FesNUz8EnR3EWPQBXTXW9YQq0irMBJneiep2RL9/yUnXpQLdK8AfJYETmCh1gBHJJBvPg4P+UQoHqvuUnm1N1KkLHwDJH03QiAnWSW6PcdAcAHpmkzIfGUULzLtMkIx5sFoFdeZ/UbMG2ut7VjYjbNzPzmq8Hzrag5uliDuj9clNPxcH9Phvj8FvZgkiWG7KuatCCCKMOdpKT1Ur546e8EP6XxlnFFvLQ6kDkKEJsmNf6GYLgPemLsmtJECF/HB1ndqblbOP6GIAfl96f9nOAl/ahateswPzwZUlEiAdpYeg7E6FRTcTeENcdh1pjHd3SeK44RvbIGCEkRY3PAYfSYD4KeNtko5bihHa7yJufZBXZCMrAY7SGcbcUou9+jzTSZTrG8WdKPFKLIqG+uXRmcOy3LGS7kIvguCsMfbBn5Vg9+SmONpcC4Njfka3TCmyer0rMdUyBGXBX1bWRKoIIkxoq2jmZX0jB+c36tzfWkP19mRD2gmdDonZfl6ZrEad4fYMHg9o7dxCiepd9lN+2GgCQhYeTkcAgsiEFOdVyNgwY5SAaCqvNkWUAJGAptjWShPLonKwWIqAPn19Q/DE1opGEgvXVl2Zw5ag1z/wnsnHhEmEgFTbNoGJC8d5OFG13Wtf7DaKTnuEwJ35Rno0lLm2VEUDVXWLRkuT9ui7UlhCmVtU95Vi8Ui4L7+IZPJGcMJp30dVwEAGqXU/XfOIMyp6PDCov//Kg6JZo7ljjABg28gbZLekdEkqnZ5UNmePJ+6UhgWKvZkFDWEi9rMcKzXws2a6NcbJgFqBu2YJkd0pYnEONjNPyQpDpTA0iLc52Wtz7WMzPcBHCXW9y3CN3cZYEsA4I6v/yb7ZaRVab71ogE/H1bnpzUbyvGUBR6XyEV1WP6tBuksF+Q8pPo4iMRtEWQlSRJpTwvMaHaciqO0dKWevLDIg+wTxa1R8vz5WlkDlI2iiiLSIs/Y/KOox49OWeN+cNbbLwtWJZTa6M9+T1VUUEKCxzUNclXPkhzc9/eJ0uOyrtLUFyIr04yyi7mb1s35s+CDUSEYwzJCCeGS+6uu5uwZfMwehA+CWCtwKzcRwQkyc8KJAiZLyNlXnIqkJ9AwQFK13QYZ9P7I6E35ddKEHubVj4cmtNuQEW/mzhu0/jiU2NVJFIveT9BIoR55rN3ckDsk0yL7UmNlHNhUXxMkg8J/aXoH/DRg5JLYFdFi8KDy1vmgBayvjdGoJm42MOpDVSy8ZCSKCZptcZiAG7ArQV06uxodpKlePDlbkS5zdPcLkWDIHiI8UpBZK+9hfAu62nCEDiEY1fAh3/oFbtPA9nSM6zkJ2hZ4pITa9XVLIsggfSA/KOAjcDuUGGZA0XeaUK5fshQtnhyKl1NZe/J23WsciY4HnfE/DmAq/QzUIOq1dsr2E3b+tDpoY2CY3Tz/YhpH2hD2NeI6+9aXuZbhJK6TJ0EnfC9SspNJPgiaWrcVSKHTJ//oLn4hVzRwbPrxtgIrbBm4G9/IMwXVanvpigPsM7cYVVohnvyJiIcRmJy4JCITIC951lPGi5uwyFkP9rAQeCVeA4R/je+kPD0t3tSgU5oCwWthjOv2lqR+UYH4oZ2kD5tyIA1ulTz1Fju3TtdXLwiUmKeOHMuNaVMCqXYB1a8i2DLKdjUf876MU/qcXdjwF/sIAbAHuqPTOrSL9l8SSRTX9D1gCgIsdlbxAz+qHZELKFF/aiSqd/tifdH3gTYBAVdWgKvTVYpmJG/AgnBa2gs9zdTVJkmcWHAw0P6rkfQa5XjoStlK1G+IUMdrGgd2GmLkW08Zxe/uOWIMhIK7eh/BpU95X/SKg6FDPq0IjvgdQ2miUIEi3Gaz8XHDUUmUDlT6YttrrlAY5AWk/tniXgfH+zGrbw0gq79z5lVbYScC1YCeS7rNxVXfvhUNr0sYIGJAdAvaUBeisQcIQDvXBibIfov07jT/d8KtxU8XpGwQzdESvpO2n7rrGMrj1JErCqxhMCDJ/cuuU3qLxFDSxCoojUrHHGcV0QEPKvCfbf0OBKqNAPNP7neV+vXKqnvXINLACMsqy/Vb2LwFhtAG1RUfvUX6+6FR8RpeEV3IzHEA6iFa2PLt3AiXxAI6w64zHF6A128loH+Q0a4YMUMQngEUd0KtFrZ7IPS2gbew8AQngTZjDX8dYYkDn1vzgfQXCmqwEzTm9uaHK/XXwwlhlh1VXIViY2cKXQtHzyA3NgEU0yiubXYWCUHjnuCfbpRDFuHr2K2GDHga5pA9s5PbFA3Pt1ZMF02yQSH25cf+iRkRqGOq9pmab+6gZIjWwZUnAIjzOOocYe4bWHC13DvuQRa37VDN8eJL0dqUE7eASBsg/EL4jv8t+fewlkwWq9w/AW6VG+r/neFhCqX06rndhhgsY2IRnQzLI0IRfNnG+7gEgQJH0BFdpjOEmlE98QqFHL29YFlKuQodHew/7VM9+RposZNZJirNReYR0L4Dq9wOGIF1lnmCPI92WpFIzn2MJvzjqzLoKcKyM0EZKcRvQApjmFX4PSwfwy78CQLeEFISfcmUS8XwTXhGN9QMCYE+IErkDBnvaoFLd1L9JQBG9hW/UYnT8ijanSvLzwndmZkNxjxcXPpUgbkpUfZndSE/FW38mjV6Z390m3B1yruOLRZt4kOIdqe3FHHvZueM5UEZD/fcYXCpKEVS750Ympf1GRYKxSVw7SrjX+5BejkevyjvGoGPNaApRWhzymgCQVwWRLLI6fG5v4GtLm9NBYmMG3R8nJOONnz/DQm9RafuHCQfQ+r5m0jYBuxecvtWglUIzncHJOo7gx/Hr1K33tVVIbnmqj1GakhqSfi1tglJXRb3ewZEZKHu63ZOYCPA3C0QS5lA/K/+oqAv1tAs/nRhFLTm4fDg2CNjWC8xNnVqNA4cArcMf9/B+V6C6qShxzUjsQlHGdtctEBNsiicIB1iKKQxG9vcW8Wzg9+AHYYtqhb9tRUgfEfFXNZzpSKekhMKgNRPFTvPHR/Wa4Ek0Fa2IsLklRO5FzqZ4lX7rdDF+BfmKYOYYrrY1R7cWTRNDsAGC97QdAKBnvqt7xxiIM0uCPUehOayx0HodE6CBLZ6vR7GJ7iPITJ3exm1Af+lRDwiga6XL4El9lLbkZCEhM4aHsllWZs6ClHHKtIMMRQjwgwhhK2hXgFJBN5qLDPM6JIJyLh8jjBEt3QsiKDslivqG/6AIn+A+KD32LZ/95ctXyNT0EGQfE0iKKSvb2DGoVwAIPZQeULRK30gF96zgn3QEQ4+MNZB7FkROhnfBzFA9AFg49dgZkjlxK6b+NPuXDQX+ObsscJEzsl8d2eBMBNQAXIMs0HFA27g7vlUb19ZtwyJ4KqEfZKWbCjx8sq9nc4f3BUVRheIYvrrdcWfZo1RC8XpnZGNlCj0QL9Dr4iSlyHIJHRH1c8+Hr8huE5W1bkMYZ6cYYvcsfptIT3Bse/mIqa486lW7Hww3R7tQBpvQQv9IWVbLP5JUNkvB/wT/1cBywrS/EUinEKu+RHT2tCUIBa0qPBRRM9/G8me/ksqBibYtosXUAWXDmE51ZcSQlEjDFU411DtNnNqFXas+JBCHteMe/v8ilgk9HO2f9blERM9tCIVqS7VSjMPnftvQoAZsoDM0NjWLLbi+H8F2+agCLpFVCF4p1YN17jNnG2QCQQV/zxDNSlnhmTWo1T9/8AatcuuQaIWEgdmAgGbOBkUIp2qzE6mltZw83cab6HGcCS6ZKwCqlWrn54DhfYXaeELkLT0qpMCAAo8gHv9VMtuE2mqL8UXPpV7kZ6k2eBYiQKp0JTAskJmjxYzUZgV8ZgOHyiTnOJs8Ll2dgS0tlrbJy2SvStDOfJZcjgA9wmznQplPKQDmBkJTY2zZzUv+DAKQ87em+n0+bYm73jzEfdxAh2FaJexmNy4wSJKXax0Cie+yYnCZg23LN70Wo3L1rAGJoPKXdrSEwxOhW8hno1LB61JYsKBuSIzbEnCCBkbuRt963Jesx0N/ugQGea42XMLJEJyrE3Yof72Tia0leodKIqnsLfs61rgqsHRW0QDfCMp6tbhJcGgaAvly7DO9IMGyqjyzwMVRwQoSpAURz+sIWtK9QH19lOi0AFRh5ID1h95LsMjckOgO4hvzj1eNtond3QDBfp87eK8sJjhaD6kBOtpuyxlYsylVjpsmL7XNiTlXX8Wf2V7PTe3oRDtB4sWPyHRP6hL79vrHriAlq0hH2Px3VOW+qPh79e0oyyrXgplPKQDmBkJTY2zZzUv+DAaT5HnulJULFi4upaRrllNGTvVs03Cm66tq1OcaJY3NALJJazWIKQ2F030rabLHg8JWAxfTJWmdWA14/6U+RFAAtLydWO4+B6BlsGR9JN+PA3x1nCuXjrLvWtvRrdefR0ihLdOcynDCmOnZnZGFW3PGR/G7pF9XJtBEikUTxzB2SXykvjq+HLp0kiRcD7fplsIlJEzdRe4EhxbLVlIZCaGG9WPZaCQTUCvPYVnXeOEByPc5yvGTnCOOhkd5md2zqsj9XRoX89RV9N5AVWC5SXfGeTc9rtXkF1AuzuGJTtOCCCLWUVVVibotKqQwYD6efsfvqH+peVunB+7xtyHvqytAjc09Igoh2YPJKfiz5XkVAc4izjYRWwcMpPFFtu30v4EhjHVn87prSLyWu2TUCnYAi7P9lm0jHWc7N42o8NY4wKOHhaPWU/qtrCdlxpumDkRgLQSLrCi01gymoQc7YR/IYq0EP+/0UPApC1pVPXyKgbVjTQdLae9nNaylaH/SXYOOmrybeVBY6eKe9UEYwfrGwvOZRmZr+jASrvXhxzp3CJ8i5+Zpx+amqp6ME455IYTg4wNeiL/JygOU4crCIICHlW0G52uVH+mxRb/pCFlIQtdnVp/coWFXDXgHM7/nKEbhUKndqjS3/mzEko9FrqZGaGVe1RXo9V1IYmbLKSw6wYI2mJhVe+QEzVaRWdpSwcoQBCrr0NDFWqcAVF9iRmAIVN4u0E8OBx3QCCXEsMRdiOCshWFub1T8+jthJ6Uxm4hNEYNmI2tj+RhikFW8fTfBVJ8TTm+1WkdB6WxUdmbwCJ30pdw2YSUCdAC7y1sT10nB9j6o8FKmeFFS8oSs6vzBu8o6MXUey+ASx9twaEpAAOxOJIbrOwVd/XlZjZlTOETaaovxRc+lXuRnqTZ4FiJD49CTVnlBJ2H+B42ymhCPxY/BUngvJAWLCspFyK1PjsdVKum9svax3z+cV5vatILH76h/qXlbpwfu8bch76srRXGBDuYD3dwYBDjldFw8/gOwmXU+ganpTM2ALcO7SGwJGz0p0NzUhbKF8HjkAjPjQXxkYBMQSsXwWGSNfPj79gg9xnnWk0HL2Xc5ZRY0WU5A6evDvioeec7D7v7c7bu3xJMOv087lFr/DFItDiik2cUIgd2iZxMlpxBdwJRCmT5B9diHCJt/vZoBc1n0lbFUhz/vFwS1HCtvf89FbiR9CwJnCGq8oyCKywruDhZfw/KC6soOEuOQW41OfUXWPCJvxAP2OXJyvyjphjyw/J8D30c71NvfZ2cRtHzMv0HI1OFIGbscZQTuj7fX5V6VtzZVCZ9zAJf4UKTYFuW+YLkDmAYKec/1Puwxg0dDjnAZ1bwIl5jba9G3Zeq+BjDu1GAjRuIdbaltiprEUzk3P7kENcPsMrvC6ru24QRWH2vAeh4B8WNKO74sH4mDfuqAsMzSxSfLMZ1c5EmUTu+SKs/6moQcYb9UsOjl0N0tPXSPxZRKDbK4yxcc6CttGLTNKijGQpynBb0WhUAvxKHv3/csswOKDglzoKJTIL7ev9RROloFqkytblYUbSAtTqs2pQp8gZsHDjZWmex4+yBn3t0vPQArqs2PWYRQfn8Quo5A0aREzJoMnGuDteHOSeR3WTNLCRAdQ1n6fN+bNtxLXM4nPYUMvokci1+jSdGIn5QQIuaDRxFEGUgL+D9+Q6z03ZkYCRMz3ye3GJ2WphEV33FLUwY93w1MdjKWU3SaLqY2B5uAAugHdNgOh3E2XAfxQ7EZxa556+mPXSpYZ2+sfjDnB4LUCiJEDyBj6Yiq13EkyjYHO7p6ovrwre/0XVCdlphUySjVvKGZs3EQ9o59mvnPPUh9y3Bnx+g/ps599A7SbVpDJi80M2VwaSQrbmvwNoOCQ5yRncu2Ma41uRyK4HALZ4pecCUvxAZwxJyiM0y8h15DJi80M2VwaSQrbmvwNoOCSW6JUFtb1OrhTEH6PsvA/4cfBt0Q4oEg7uMjm5a3qa7KJzYC/gClrK3Qb6uC4eP8xb4Mvk9qVqcPVjx62/A9aQXi2G/8qqvg1MlL6LYe9O8FtZTUGhK5zo1f7YfuM6JNwplPKQDmBkJTY2zZzUv+DALLgyfI8B7GNRZl7xo4UE5BGi+ZlVKzE+X3c+qnmVfHyQD6lEGItwo0wPEKrcNoPkJwHuni6/ENcEEe5+UOuY4CDMlxiLSr1O3s+kKidY8BgtTgCnwB7vjtFSFko+7veEPmO/yjYr3z15oSZPpbNrKIKqpRgzhRSKbUftLS6hU8x3H8qqQWiFxEl4womXwJOsi1KhEqlc9muLOQ6FNqAFiAiLK21+0yH0bjCzizZBlwQXOq7sjo2b4C1uMt9akz5sTXPSNeWg7E8TlMPRyEvIiJn6uRE42NqOH7lAUlWcCdyOWUFyniaa1Dvjwv4cx1WYSTLg5o9WZSF3KEg5QaVNqJdJKzO6zGtAjQR67R9gy5CPknR07AAlPYASDGqUh52sEJe9go7bnwlYpq9K9f0OrDojngIoE47WenVFaUjOl1hgdYZGdqKM+3mgGmDlOQNYAXkvLtegFnIeaHJWPyrZ/DW2wgsO58Hi5B8kpRXozMwtYD/XhdevE7z9BhBInK70hKj86x5tccBguC3tMaYsCC/dpTMec06tSlvwMVaiv/gj7/YJdFPQ2wda8DKhjIJsIBKK0leXk7B1yVld6yjhUHrer6+3/1ELM6BCQiSXiSSakU1ckEVV43hVFt7WMzNEINY/BnJzp85761j0B8QrtEvl+nOMLNlW27vWEhqT7XBk+5nVjkAUo6TOjsFkHaLUHyyr+HQHg1saPAgvtSdfGA3wzWLiA4s3q++yB9UBjXhYCt4yspQcoowbrsORq3D4hJmxsBdH3Gm/ajRuga8MLHLFCG4IJCLxLui/pNxvc6CcX6iQlNwKkWaB9VjYEbQUcBXIH26L7p+Gsx3h8Bm9GFIZp6ubBJb7N9z+HCqEzPxXrAix4s6bXvE7aEz50CDQfj3d1Fo4iU67uCWk+0PqCG5AhZ+vf/ZVyWBy7PdwF7BG6Y3hxUYzsnXqKjAy6M2AHqx6Py3nDB508TDwQYQ1zAWv8+KPt+8zmPLGwR2ycZgb1/twAbrg0w7ZZpvoZKRYW18rt9N7hvla5tgltU3cuAcsK0vxFIpxCrvkR09rQlCFMVED6Gaqv32agqG5GENIO1eF03gAbMSUAfsqdEfLrJa5G8NTV0vsXZkZwcrYtig00B71s7zRdMpTOQYxMkzgaK/uymSMdklKhHZGCeHTeElCBBSotPCJ11tnI/nPNHR81qJH4CMUIJ2JsistHuIUNHEUQZSAv4P35DrPTdmRgJEzPfJ7cYnZamERXfcUtTBj3fDUx2MpZTdJoupjYHm4HlR0L1yZ2P8+kwv+0thqN
+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
diff --git a/unitgrade_private2/__pycache__/__init__.cpython-36.pyc b/unitgrade_private2/__pycache__/__init__.cpython-36.pyc
deleted file mode 100644
index 55b1e08fb7a2e153288f98c9683097b615a31d04..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 888
zcmZuv&1=*^6rVSlWYe^@#gBrX)LTG;Q1BokLJQs&w3W)T5VDzRo9*U<nb}sC>}h)~
z{vG~3-sbAbe?c$4msBmqS>DIKWZwI|-!HqHo6)cFxAd9E*mrj0;D7c8%_Qg~lQ3hW
zKEep(n)IZ&gb|m%3@+KolLHxI6cP?t9R0vMY<QSc6FNTH2HGB)IYwvM6sEj|6)e3j
z_gZfS<|*caGGHy&&#f;3-{HV)(1PSE{$*z=>|h$UtQ7>|$^&+Uu->uv>?7To;2odt
zONKy#;bQwp7q+NQ9_Lwps*)se{9@w7Y*A)0xb?g)8?B5f>T2Qd*Oht_uQ^^DCz{Nj
zx`8Zom6gf`>QiB?aejG*CFeJ~sH_upqbj%cr%Bor`Poc4A?IZi`!1*_Q<Yn{c3jL<
z+VvTnD?O==a$Hspj=wT}59#>%cJJl*gHhUy?fg`Y_v?IKs>+)2yejO8&ZJ6l;(2D(
ze=2EO;9F^$G@o%HS~I=CrIjGI@1kR{fxid@i!eUIs2^Z82YQBwB1h}wA)T(}VJlJ-
zhOwtfK^>3_(Z!&*C@1W_yN{XM=!f@I-NA~Xu8iv)^na&OZ5^$f_5zcC({y6J7QZzV
zdV2|0Ons7FdRP45TH;EOu${PK=umG>-x%VdW#ix$PEB((ZG?)~nT&aln@G70KI*}1
zl}TF5(4LGFaXX%Vh<OZ$vEL7%jva;FX5G^p?K)OELc&*NE$1`!ni%dnh7j^73jN<Q
C#>7Ve

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

literal 918
zcmZuvO=}cE5UuX%nVlUI4Sqxj9yGTBS-f}&B4Pr9hXpkuvMh|V)172CJ0EoSCK@KE
z<Qn`737+zo`s&HQ;K{0)1Y@w5eqCEVT~)7MZ7nWFfb0Ek@5^%!;3xgLxzGo1aGL>w
z1j%MF>P|LdvM)U;PT7b{Uk0Zz@?=kjcnZlrK^*<UH!$4HD9H8l(dgq|$8B~HEKJ!s
zZ`cJp_FCI(ybESlEu0Io7&KhJu)bssJK+p$&@jnQ`1j>wVSCfCfksdnXC8xXcnKfi
zBYdVe6MW;J;Cl&JOfWoJ+Sa+v%iX70n(e8<VBq-S#EIEakzO))C##BDD`WDiJn}cH
zQay|Nj#tKsI<<SQCv#n<g>r%Vnj34JU+kmH`L)hV>qJ$n(%riblGJ&&KT}S~c~Qr{
z3#!RfW!Cj~@|jB7IK2a<CzVl-%hIu(OVAIo9lzhLuZ_2i(q?SuduqH<W%ELn){N(6
zZg+JmRe~80Qmg*sNs=7DN|HhS4G9s=<Pb?KLEXNO0Biw&5fc#Mxq_!&MsLRG?rM=u
zlC=^opm8M;T#%}47<)QEukI0$mNC;yWK;beJVMJYbOm(nx{Dse5rFH*i2r0HKh0sA
z@huvEGwL<#H8^)D_>*I1#ndPHrFX`+fnUk}0|oA6F9nI+3ND5YXFwAXP4wg7R@IuQ
z=|u#bfhv_T?^rw__bn<>M@6et(zOW@fKw}1J-vc<%r;}cOF$9ZrnWrW+Z*B9z-@cN
VS4Ab~GxeJK-9`*q$fGFq{{R*Z#^L|~

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

literal 944
zcmZWnO>fgc5Zzg?9VfIUh%bo)D%^Z=3P*$x5~asnTB#x&jN{!lPU8=)Hz`E!DZN(w
zh4$FLv{z321y0P^ErhbGeIAdKH}mFgyt&z9xIXU%@dJmkAM~=mFvs5GsX_$FB+S^T
zeZmN2S2|Lh!-z{)dgpB9$d2^!DJ1N(p!XC1!-fY5k=!m910T-^Jk=7xuqj;f8m{2X
zX=0~#uAq8p*rlKdSk3j0aV6BS;=qhogXAmzefvz9&eX42EvStP2iPIDCUCDX&ik)e
z^<{@avp*ps&jNYe6>>_34SK_6|4^qU&5yT}IGLz03@tw$TQOT^@io|cNs*OWRaIK#
zOLw=()r+8Oc~MzW#%5wWGSzvUDeI}PX=N(wW+#}kZmHAUSW%QJxA$*JqB2cRX37dV
z&&t5HUNN4k#MtgpI#W@@(^)7zE-GcY%q<*UGyMoh^y}kbQe<ji<`Xs8Es}Yra#IcF
zd1{VzELDW%7O_$PXI>AYD8-*eQCNOMIV3VVMafFg{I?JoY~b#}7Genc31$+Y{LP}6
z3~UVBz~II(c10e;FmSYoS=}M%A_SoO6jSFdJjTdww8h&&QQ?XsFs`2>{!@|if3C<7
zU;b9qd&a5p7NY&n&%lVOOP4`97yOX%HS_lwn*V0q{9KUbjqPG+xgKj0rD+U-cSnIH
znR*ieZ$c5vfVYYsQu>apUMowhSkmW;8fTnF8anzJ#sM4zZd-sDn*lePo3Cqh4RJFn
V|7}*t`Aof|**A<n_`KKi-QO!K$2|Z5

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

literal 1392
zcmZuxOK%%D5aw_nTCE;+5<5=PG;j}1p&W!DK+>Wxi~@0iq6edi8>Cn$Sgb`#T6-Td
zN#$X1FI9`Cr=tHrI_97BH}Kk%`x6Qj?r>$-0a`9N94=?R`DQq~&pMru;J6#zO+N7m
z`NMAB9}aH5#3^@BFv1`skzHv9IgM!UL=LRpyOCR;U#wo_F^@US{ShLc!9MBvr-(uJ
zdep4vTun+QpQmcF%ZH^%R4I%*Nf{qfYji%kxHfTG7V-cH(PT~*WJxNjKvM>D`s>xo
z(awS{$-=?+?sM{xJRwiX_hd|dLHk2@m%R9HKr65Em8X2|sm7enp=#&`o_t<8Dp)kN
zvjnsWs-_BcFbCb-Bvts9phrtL8NEStXr=Z13~`UYJ$|ITpUDX73<K5H?i_Z>91z)M
z-lC)3C2ATNIilis<Vu+T6TL}T1Cc>>4?kF}X;^~zv(~R@iaUzCs|@4+0GJ=JCg!(R
z=XcHG0lCZ$Gh44(y0zF~p*_(phI4V<?&>(<CaIA(ZIp}X7`vrzEN<!+vTLhbx{Wv=
z&S}-rpgSXqx76A*AWpH?WN5|3uvg&XyoOWWMlr_XzF5biL50-clB0%jHT{hqyZhuF
z5k8vq97Fr}4ICNB-a*vP(t^uam9gM?ZSdDOkG~i^lU&Gwnoam%w;axLUMM-36{#AF
zgz<PP(wB+i|9$gd!1y#P-&lwK^o<F(vs9{KnNN2%ElJD3$0r~sJq%dB<S{lF<3)Vl
zef{mM9449ELFK~JKzRE1+1c4iJ1)wVIbxsO*-!H{OT^YF&G^<dQ4_g^&045*lydg5
zfma6lz1zl%t$}gNDKCsGc*0C5r&+4%)J^kv#-&QjLK@eG6t>xgEv;#!g`D!CGTkv(
zvYd$_U->v0LU|%7#@sY{f%U<!1w$N`X<=xINS2QA`D+A}CXh+aYZA?`UJv=yMl;?k
zk)lr+$9c(S8INP*j?#i5ZoLEtiR1-3nr50$OM!F`OlPH@yO;*@N|X{Nh+}IS$Gxs;
zJ>}N?ah6DF8s$u_(yt|qjK506z!L*;L^EkX8c(W3DC6*gMP6P<^;fi_D__?a^d4y4
zCc^%sM9Y?G<9}~5z$1Ad1)(9d;W~9`7rGGOY{MOT3ql&e8m<BE*QpO7+@m3FgLs5K
zJ=p6tgzXu#@o(Qf=wGUr*CakdEAgon)^o+qHrh(7DF)lCY<BGDBQ14|jgj$j{sCq`
Bg3JH_

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

literal 1425
zcmZuxOK%%D5aw`qrPb<DC$VeCH4OJw<sdmZBsmyHfw~X$V4!t@plXA~Mx>;5_GOZC
z5`%lGS~LX;wEYLtF@K5ZttX#*3(&g5mEE{Vx!`a}&V2I?Iozn-4hXhyKIulUT|)k_
zlk3gF$%okGJ_<${BxGPmnm|eiG<60JEZ5zETkT(s-oRrXbC~-*3~CIHNVj&5804@^
z&1%ZkBxmwbtR@G1n2Si|!nl)|@gcQFm#u@NkKMA6KLa6}%*dQ9NJ$lF%3wx+*(x3F
z%;|#69b9)GAsZLJ8S=_j?h<)_mq7J>jdDzWLX2bgfIR-{TUvT$O?j%OJyoC48I*Nh
z$DN0zqx^Y8I}1P?zig;L`!mpuby5Z|33@bjgV7D511qiP1H?UHC!Z_tM>2vcYhSgr
zJA(r<14MS2H*afqftm(Jo>K8U@+YkJ1HDaH9g#tGj^CNDXjp*wyV7rHiZhC{n+)TB
z2beRk2Ijn3<$TNH0r^kHH}8^PLEgEZGv>QmHg$8p#sX`vn+*H>T|29y2kWGYw{Bx!
zaY9B-wK2b~o5;DPHgyYe-kZ^~twFa(6z{WnXh59ft&pJ=SIu4)mJ+#zU2dTm<B>mJ
z#iN806M9KbLAaX!Mo-)$@`{KWnsgmQd%Fgn8c1Hjpq0cKm!Zl-!PCm%^{4$wp7Oq$
zPI&(yA5K%ADcPT9u^Nkr@vso_X{7kuEBE@07fJrYI`oPcCfG}2sfKx4?5|_wKe3au
zF2>1Ed59IrcotrkXKydbhfyN;QMvLl5S;&YadC0h3bTA^j;LqbM{yb_k=Pl<3EwFq
zHIX}5&6$cvF=y`^cxIs2-7;Qi4UC%?JTtD~5i@}-l2}z4o5snMOBLstG_DOP>}wGA
zL`^-;WWk5ZbjDoCd@6=~>Ek2_<%uX8bJO4%o(w)G3~`*tnV~r%Svsc1pCh0&zKl{{
zk!XDUe8>wM&3Mm5j6Ojara7A?JPeIHiZh0|)!;vgB+t;%G~%?#1=4+D+DrA)#nh2k
zq?9mz7+TXX>~>7^OK#0SN+KyuJ)f#&`jv!{sVx&R@P&bJKoe;|8c(W7DC6*q4ZO69
zT3gZ@-1w}zplhI2bqM<t6HR+eYyW$b_9r5DQ4ktH3+_;tcAx`3_7-f@O$ewDD>(Yq
zZVdvo31|z%1N7;_VYe<eP%~@)R@}Yb8}-dKiEXqJA6Q{Mm+WkXFSUxIzqib0-@Y1Y
Lsbg%6jGyxl)Q5)a

diff --git a/unitgrade_private2/__pycache__/docker_helpers.cpython-38.pyc b/unitgrade_private2/__pycache__/docker_helpers.cpython-38.pyc
deleted file mode 100644
index 64a1893f40852651e6f4f6145d3b8ddb4b5e6dcb..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 3165
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
Jg2VQw{{ye@S>gZy

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

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

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

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

diff --git a/unitgrade_private2/__pycache__/hidden_create_files.cpython-38.pyc b/unitgrade_private2/__pycache__/hidden_create_files.cpython-38.pyc
deleted file mode 100644
index 495660ae33400dda27e6cf64c7f939036a688a98..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4588
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
a75&g(BN(LS&`d+9><85?d%}6qasC4{Dd9!{

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

literal 4665
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
CujMNM

diff --git a/unitgrade_private2/__pycache__/hidden_gather_upload.cpython-36.pyc b/unitgrade_private2/__pycache__/hidden_gather_upload.cpython-36.pyc
deleted file mode 100644
index 7aa51f153e94d74ee8abd09983ea96ac0bc500f0..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/unitgrade_private2/__pycache__/hidden_gather_upload.cpython-38.pyc b/unitgrade_private2/__pycache__/hidden_gather_upload.cpython-38.pyc
deleted file mode 100644
index 07472b0de4bf0b0f74be03f08a47140647e9cb27..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4107
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
QdmFXy{=3?s`};rsFLbe-ssI20

diff --git a/unitgrade_private2/__pycache__/hidden_gather_upload.cpython-39.pyc b/unitgrade_private2/__pycache__/hidden_gather_upload.cpython-39.pyc
deleted file mode 100644
index 5c2e1ae6b68171c81e7ddf38fb9d45d3f1968a79..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4210
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
F{{pLyr|JLz

diff --git a/unitgrade_private2/__pycache__/token_loader.cpython-38.pyc b/unitgrade_private2/__pycache__/token_loader.cpython-38.pyc
deleted file mode 100644
index 31836c22ea1ea42dda4ca41936fce6eb9ec9f4b6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 978
zcmZuv!EVz)5S?AGQ#WngP>N_J4)mBFf`r5cRTWZuL#hN-1+s#So81&Q8#~!`DpA?u
z&>lE|_=V)ipYRQPMI87APRzJf8zk16H@h?Ac{8(n+-fxe*VkX+`yT?}Cmj|S+TaC>
z{emDtG7ZtSW)Z8;JmR(XB2RMZT|p$2FU63X&$Yb~HEO*y3OFzrEk{iTs(H48$j(-0
zE!xjn6e^g33Z?%L@U*7ZBy2&{R`*o<l3}bM9j(hobYHR~=q&xlir}!%NZqUk>SdID
z6uXB|z>Jkx^_+hTD^{`@pF_ppz%zISui-6V#h|^)E4`U0`J7ckdQx0L<(C3E{6oi0
zVTj@%9v=<Fb%bJf5r|_8>z~5`yxZyVidDSilHb}k(B@U5z#2-g6qg=@$>YhY#1tLx
z&@D+-B&oK}PYX4&9d2mw&L5jJD>}aOjIxeRA~88nv|~fZ&cB19tNZhE|9S7&Dr0-a
z^n>ah<o)SLWrgicv$QxhiBvIWIZq1pA4`!BRTk?UqfB@F(TOn<wWup<57-9Z;1`?Z
zkL%FxuFm_3wtHO)>?}L)<l?Cl`B-I67?nsT&TO7JpMJ4U=+qX@vkF10%+TCA4cEM;
z9i&=0HgL?EHaZMZnpFa7>>5^Z=bCo~P>iJ*U?E%Q0c-ML(`-^y5XYk=&EohXe6lkz
z)3n&>)<o$i?5MNh#Hr3t9M7$5jMM&5D?^>${+uNv6~|7bM)#v_!fs-1dYaYaT-e8T
za<{VJjoNpI8#f;$R1!5wS;tB70k1hVMB}*39Mk3j@zYT7nc@8=3ys$!sJjn#N4cD8
awMWm;K0*js{qbO%^g3&JArHyM1O68u`}k-8

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

literal 181
zcmWIL<>g`kg6WlVi6Hthh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o11%*(xTqIJKxa
zrld3@HO3`BximL5ucSDpG%vFxy(lpyHNK!Ivn;VB6;s40COJPPHLElwJvBbHA~Clh
hCp9KMJ`<=hK3=b&@)n0pZhlH>PO2Tq&d)&1007uJF(Lo}

diff --git a/unitgrade_private2/codejudge_example/codejudge_sum.py b/unitgrade_private2/codejudge_example/codejudge_sum.py
deleted file mode 100644
index 8a43e38..0000000
--- a/unitgrade_private2/codejudge_example/codejudge_sum.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Implement https://www.codejudge.net/docs/quickstartfiles#the-problem
-from unitgrade.unitgrade import QuestionGroup, Report, QPrintItem
-from unitgrade.unitgrade_helpers import evaluate_report_student
-from cs101courseware_example import homework1
-import random
-
-class SumItem(QPrintItem):
-    ls = []
-    def __init__(self, question, *args, **kwargs):
-        super().__init__(question, *args, **kwargs)
-
-    def compute_answer_print(self):
-        random.seed(42)
-
-        from unitgrade_private.codejudge_example.sumfac import sumlist
-        return sumlist(self.ls)
-
-class SumQuestion(QuestionGroup):
-    title = "Sum of two integers"
-    def __init__(self):
-        pass
-
-    class FactorialQuestion(QPrintItem):
-        n = 3
-        def compute_answer_print(self):
-            from unitgrade.unitgrade_private.codejudge_sum import factorial
-            return factorial(self.n)
-
-class Report1(Report):
-    title = "CS 101 Report 1"
-    questions = [(ListReversalQuestion, 5), (LinearRegressionQuestion, 13)]
-    pack_imports = [homework1] # Include this file in .token file
-
-if __name__ == "__main__":
-    evaluate_report_student(Report1())
diff --git a/unitgrade_private2/codejudge_example/sumfac.py b/unitgrade_private2/codejudge_example/sumfac.py
deleted file mode 100644
index f429a12..0000000
--- a/unitgrade_private2/codejudge_example/sumfac.py
+++ /dev/null
@@ -1,6 +0,0 @@
-def sumlist( ls ):
-    return sum(ls)
-
-if __name__ == "__main__":
-    sumlist([1, 4, 4])
-
-- 
GitLab