diff --git a/unitgrade/__init__.py b/unitgrade/__init__.py
index d7f3cb7b866d6bd68c0370f98b5b5162bf5490fe..605eedf9521bbb549018417e8ade8e8c9e7a6f40 100644
--- a/unitgrade/__init__.py
+++ b/unitgrade/__init__.py
@@ -1,5 +1,6 @@
 from unitgrade.version import __version__
 import os
+
 # DONT't import stuff here since install script requires __version__
 
 def cache_write(object, file_name, verbose=True):
@@ -28,4 +29,4 @@ def cache_read(file_name):
     else:
         return None
 
-from unitgrade.unitgrade import Hidden, myround, mfloor, msum
+from unitgrade.unitgrade import Hidden, myround, mfloor, msum, Capturing, ActiveProgress
diff --git a/unitgrade/__pycache__/__init__.cpython-38.pyc b/unitgrade/__pycache__/__init__.cpython-38.pyc
index 57e9c8499c7c715af060fa5dac373ccf7e32da49..dc097231ab1cc676f96b6e553c3f3a9d29cccfee 100644
Binary files a/unitgrade/__pycache__/__init__.cpython-38.pyc and b/unitgrade/__pycache__/__init__.cpython-38.pyc differ
diff --git a/unitgrade/__pycache__/unitgrade.cpython-38.pyc b/unitgrade/__pycache__/unitgrade.cpython-38.pyc
index e2fdc61918eb16cd7180fda4503cdcf6bc966acf..5601367584ffb2dd33f99e057b47d73958c6bf42 100644
Binary files a/unitgrade/__pycache__/unitgrade.cpython-38.pyc and b/unitgrade/__pycache__/unitgrade.cpython-38.pyc differ
diff --git a/unitgrade/__pycache__/unitgrade_helpers.cpython-38.pyc b/unitgrade/__pycache__/unitgrade_helpers.cpython-38.pyc
index 29fcc07326d80d9125066f6a3ef9ee265e53a622..d7f1dcc24f9053facd9ab6146edd241ac30a3ca1 100644
Binary files a/unitgrade/__pycache__/unitgrade_helpers.cpython-38.pyc and b/unitgrade/__pycache__/unitgrade_helpers.cpython-38.pyc differ
diff --git a/unitgrade/__pycache__/version.cpython-38.pyc b/unitgrade/__pycache__/version.cpython-38.pyc
index d8b1642642aadb9136268b7e9bd9759eb8164c3a..79890100982f99dfa74eaaa28454b969f4f9d8fb 100644
Binary files a/unitgrade/__pycache__/version.cpython-38.pyc and b/unitgrade/__pycache__/version.cpython-38.pyc differ
diff --git a/unitgrade/unitgrade.py b/unitgrade/unitgrade.py
index df8a7f815e4fdd3cc4a09d6db5f906b9fd633a58..e57ccbc0b1637ecfaa96a429a631809113040604 100644
--- a/unitgrade/unitgrade.py
+++ b/unitgrade/unitgrade.py
@@ -11,6 +11,9 @@ from io import StringIO
 import collections
 import inspect
 import re
+import threading
+import tqdm
+import time
 
 myround = lambda x: np.round(x)  # required.
 msum = lambda x: sum(x)
@@ -71,8 +74,11 @@ class QItem(unittest.TestCase):
     title = None
     testfun = None
     tol = 0
-
+    estimated_time = 0.42
+    _precomputed_payload = None
     _computed_answer = None # Internal helper to later get results.
+    # _precomputed_payload = None
+
     def __init__(self, working_directory=None, correct_answer_payload=None, question=None, *args, **kwargs):
         if self.tol > 0 and self.testfun is None:
             self.testfun = self.assertL2Relative
@@ -82,6 +88,8 @@ class QItem(unittest.TestCase):
         self.name = self.__class__.__name__
         self._correct_answer_payload = correct_answer_payload
         self.question = None
+        # self.a = "not set"
+
         super().__init__(*args, **kwargs)
         if self.title is None:
             self.title = self.name
@@ -105,7 +113,14 @@ class QItem(unittest.TestCase):
             print(f"Element-wise differences {diff.tolist()}")
             self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")
 
-    def precomputed_resources(self):
+    # def set_precomputed_payload(self, payload):
+    #     self.a = "blaaah"
+    #     self._precomputed_payload = payload
+
+    def precomputed_payload(self):
+        return self._precomputed_payload
+
+    def precompute_payload(self):
         # Pre-compute resources to include in tests (useful for getting around rng).
         pass
 
@@ -128,8 +143,8 @@ class QItem(unittest.TestCase):
 
         correct = self._correct_answer_payload
         try:
-            if unmute:
-                print("\n")
+            if unmute: # Required to not mix together print stuff.
+                print("")
             computed = self.compute_answer(unmute=unmute)
         except Exception as e:
             if not passall:
@@ -190,8 +205,8 @@ class QPrintItem(QItem):
     def process_output(self, res, txt, numbers):
         return (res, txt)
 
-    def compute_local(self):
-        pass
+    # def compute_local(self): # Dunno
+    #     pass
 
     def compute_answer(self, unmute=False):
         with Capturing(unmute=unmute) as output:
@@ -215,6 +230,7 @@ class QuestionGroup(metaclass=OrderedClassMembers):
     items = None
     partially_scored = False
     t_init = 0  # Time spend on initialization (placeholder; set this externally).
+    estimated_time = 0.42
 
     def __init__(self, *args, **kwargs):
         self.name = self.__class__.__name__
@@ -224,6 +240,11 @@ class QuestionGroup(metaclass=OrderedClassMembers):
             for gt in members:
                 self.items.append( (gt, 1) )
         self.items = [(I(question=self), w) for I, w in self.items]
+        self.has_called_init_ = False
+
+    def init(self):
+        # Can be used to set resources relevant for this question instance.
+        pass
 
 class Report():
     title = "report title"
@@ -239,9 +260,13 @@ class Report():
         import time
         qs = [] # Has to accumulate to new array otherwise the setup/evaluation steps cannot be run in sequence.
         for k, (Q, w) in enumerate(self.questions):
+            # print(k, Q)
             start = time.time()
             q = (Q(working_directory=self.wdir), w)
             q[0].t_init = time.time() - start
+            # if time.time() -start > 0.2:
+            #     raise Exception(Q, "Question takes to long to initialize. Use the init() function to set local variables instead")
+            # print(time.time()-start)
             qs.append(q)
         self.questions = qs
         # self.questions = [(Q(working_directory=self.wdir),w) for Q,w in self.questions]
@@ -257,6 +282,7 @@ class Report():
                 else:
                     print(s)
 
+
     def set_payload(self, payloads, strict=False):
         for q, _ in self.questions:
             for item, _ in q.items:
@@ -268,7 +294,9 @@ class Report():
                         print(s)
                 else:
                     item._correct_answer_payload = payloads[q.name][item.name]['payload']
-                    if "precomputed" in payloads[q.name][item.name]:
+                    item.estimated_time = payloads[q.name][item.name]['time']
+                    q.estimated_time = payloads[q.name]['time']
+                    if "precomputed" in payloads[q.name][item.name]: # Consider removing later.
                         item._precomputed_payload = payloads[q.name][item.name]['precomputed']
         self.payloads = payloads
 
@@ -297,3 +325,31 @@ def extract_numbers(txt):
         print(txt)
         raise Exception("unitgrade.unitgrade.py: Warning, many numbers!", len(all))
     return all
+
+
+class ActiveProgress():
+    def __init__(self, t, start=True, title="my progress bar"):
+        self.t = t
+        self._running = False
+        self.title = title
+        if start:
+            self.start()
+
+    def start(self):
+        self._running = True
+        self.thread = threading.Thread(target=self.run, args=(10,))
+        self.thread.start()
+
+    def terminate(self):
+        self._running = False
+        self.thread.join()
+        sys.stdout.flush()
+
+    def run(self, n):
+        dt = 0.1
+
+        n = int(np.round(self.t/dt))
+        for _ in tqdm.tqdm(range(n), file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100, bar_format='{l_bar}{bar}| [{elapsed}<{remaining}]'): #, unit_scale=dt, unit='seconds'):
+            if not self._running:
+                break
+            time.sleep(dt)
\ No newline at end of file
diff --git a/unitgrade/unitgrade_helpers.py b/unitgrade/unitgrade_helpers.py
index 85b51ff42d9d74a4379dd0cd02a935f231e11ede..5edd3ee7520abdb46fa992f516f78ef6f670b102 100644
--- a/unitgrade/unitgrade_helpers.py
+++ b/unitgrade/unitgrade_helpers.py
@@ -2,7 +2,8 @@ import numpy as np
 from tabulate import tabulate
 from datetime import datetime
 import pyfiglet
-from unitgrade import Hidden, myround, msum, mfloor
+from unitgrade import Hidden, myround, msum, mfloor, ActiveProgress
+# import unitgrade
 from unitgrade import __version__
 
 # from unitgrade.unitgrade import Hidden
@@ -12,6 +13,10 @@ 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
+#from threading import Thread  # This import presents a problem for the minify-code compression tool.
 
 parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
 To run all tests in a report: 
@@ -62,8 +67,8 @@ def evaluate_report_student(report, question=None, qitem=None, unmute=None, pass
         unmute = args.unmute
     if passall is None:
         passall = args.passall
-    # print(passall)
-    results, table_data = evaluate_report(report, question=question, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute)
+
+    results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute)
 
     if question is None:
         print("Provisional evaluation")
@@ -85,7 +90,10 @@ def upack(q):
     h = np.asarray(h)
     return h[:,0], h[:,1], h[:,2],
 
-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):
+
+
+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):
     from unitgrade.version import __version__
     now = datetime.now()
     ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")
@@ -100,40 +108,71 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
     print(f"Loaded answers from: ", report.computed_answers_file, "\n")
     table_data = []
     nL = 80
-
+    t_start = time.time()
     score = {}
     for n, (q, w) in enumerate(report.questions):
         q_hidden = issubclass(q.__class__, Hidden)
+        # report.globals = q.globals
+        # q.globals = report.globals
         if question is not None and n+1 != question:
             continue
 
         # Don't use f format strings.
-        print(f"Question {n+1}: {q.title}" + (" (" + str( np.round(report.payloads[q.name].get('time', 0), 2) ) + " seconds)"  if q.name in report.payloads else "" ) )
-        print("="*nL)
+        q_title_print = "Question %i: %s"%(n+1, q.title)
+        print(q_title_print, end="")
+        # sys.stdout.flush()
         q.possible = 0
         q.obtained = 0
-
         q_ = {} # Gather score in this class.
+        # Active progress bar.
+
         for j, (item, iw) in enumerate(q.items):
             if qitem is not None and question is not None and item is not None and j+1 != qitem:
                 continue
+            if not q.has_called_init_:
+                start = time.time()
+
+                cc = None
+
+                if show_progress_bar:
+                    # cc.start()
+                    cc = ActiveProgress(t=q.estimated_time, title=q_title_print)
+                from unitgrade import Capturing
+                #eval('from unitgrade import Capturing')
+                with eval('Capturing')(unmute=unmute): # Clunky import syntax is required bc. of minify issue.
+                    q.init() # Initialize the question. Useful for sharing resources.
+                if show_progress_bar:
+                    cc.terminate()
+                    print(q_title_print, end="")
+
+                q.has_called_init_ = True
+                q_time =np.round(  time.time()-start, 2)
+
+
+                print(" "* max(0,nL - len(q_title_print) ) + " (" + str(q_time) + " seconds)") # if q.name in report.payloads else "")
+                print("=" * nL)
+
+            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="")
 
-            ss = f"*** q{n+1}.{j+1}) {item.title}"
-            el = nL-4
-            if len(ss) < el:
-                ss += '.'*(el-len(ss))
             hidden = issubclass(item.__class__, Hidden)
-            if not hidden:
-                print(ss, end="")
-            sys.stdout.flush()
-            import time
+            # 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': iw, '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="")
 
-            # q.possible += possible * iw
-            # q.obtained += current * iw
             if not hidden:
                 ss = "PASS" if current == possible else "*** FAILED"
                 ss += " ("+ str(tsecs) + " seconds)"
@@ -161,7 +200,14 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
     report.obtained = obtained
     now = datetime.now()
     dt_string = now.strftime("%H:%M:%S")
-    print(f"Completed: "+ dt_string)
+
+    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
diff --git a/unitgrade/version.py b/unitgrade/version.py
index 48fef3235794579e6ccc7e4ec49e8b5188c14101..acf3be3eb86fb072c535366ae4b8e590326c2835 100644
--- a/unitgrade/version.py
+++ b/unitgrade/version.py
@@ -1 +1 @@
-__version__ = "0.1.2"
\ No newline at end of file
+__version__ = "0.1.3"
\ No newline at end of file