diff --git a/examples/slurm/README.md b/examples/slurm/README.md
index a4cb306db2ab7989795257a811b2406793584cd7..7dc183fdca755be3fd19f3fc65dfb4f5aed08b2f 100644
--- a/examples/slurm/README.md
+++ b/examples/slurm/README.md
@@ -1,7 +1,18 @@
-Examples for Python submit scripts for MPCDF HPC systems:
+# Examples for Python Slurm scripts for MPCDF HPC systems
+
+## Small programs and problem sizes
 
 * sequential program
+
+## Full-node setups for larger problems
+
 * multithreaded program using NumPy/MKL
 * parallel program using Python's multiprocessing (restricted to a single node)
 * parallel program using MPI for Python (mpi4py, multi-node)
 
+Important: Before using full nodes, please check that your program actually
+benefits from these powerful resources, otherwise use shared nodes.
+
+Find up-to-date documentation on Slurm and related topics at:
+https://docs.mpcdf.mpg.de/doc/computing/index.html
+
diff --git a/examples/slurm/python_multiprocessing.py b/examples/slurm/python_multiprocessing.py
index eef585af93b36da8022acddf845c91f67b109b6f..0685961df47a3b5bdb2a65acb8f517baf025888f 100755
--- a/examples/slurm/python_multiprocessing.py
+++ b/examples/slurm/python_multiprocessing.py
@@ -9,8 +9,10 @@ def my_f(x):
   print("{} : {}".format(x, os.getpid()))
 
 # set the number of processes to be used
-#np = mp.cpu_count()   # ... as detected by multiprocessing
-np = int(sys.argv[1])   # ... as passed in via the command line
+try:
+    np = int(sys.argv[1]) # ... as passed in via the command line, if possible
+except:
+    np = mp.cpu_count()   # ... else as detected by multiprocessing
 
 with mp.Pool(np) as p:
   p.map(my_f, range(np))
diff --git a/examples/slurm/python_multithreading.py b/examples/slurm/python_multithreading.py
index 1ec5c68f9367c5ce2e76e9fd8c6ca03a103f5208..d32ef34f83c25c139d33c8451fc353890fc12ec0 100755
--- a/examples/slurm/python_multithreading.py
+++ b/examples/slurm/python_multithreading.py
@@ -5,7 +5,8 @@ import numpy as np
 n = 4096
 M = np.random.rand(n, n)
 
-# the following call may use threading
+# The following call may use multi-threading using the underlying
+# high-performance math libraries NumPy is linked to (e.g. MKL):
 N = np.matmul(M, M)
 
 print(N.size)
diff --git a/examples/slurm/submit_mpi4py.sh b/examples/slurm/submit_mpi4py.sh
index 54077b8b2c2775328a6d7631f19f76fde99efa97..d789d21cb94a963868969cd61aa9ac8992d19d20 100644
--- a/examples/slurm/submit_mpi4py.sh
+++ b/examples/slurm/submit_mpi4py.sh
@@ -1,22 +1,24 @@
 #!/bin/bash -l
-
+#
+# Example job script for using MPI4PY on Cobra@MPCDF.
+#
 #SBATCH -o ./job.out.%j
 #SBATCH -e ./job.err.%j
 #SBATCH -D ./
 #SBATCH -J PYTHON_MPI
 #SBATCH --mail-type=none
-###SBATCH --partition=general   # note: general partition is necessary on DRACO for jobs with >1 nodes, not on COBRA
 #SBATCH --nodes=1
-#SBATCH --ntasks-per-node=32
+#SBATCH --ntasks-per-node=40
 #SBATCH --cpus-per-task=1
-#SBATCH --time=00:01:00   # run time in h:m:s, up to 24h possible
+#SBATCH --time=00:10:00   # run time in h:m:s, up to 24h possible
 
 module purge
-module load gcc/10 impi/2019.8
-module load anaconda/3/2019.03
-module load mpi4py
+module load gcc/10 impi/2019.9
+module load anaconda/3/2021.05
+module load mpi4py/3.0.3
 
-# avoid overbooking of the cores which might occur via NumPy/MKL threading
+# avoid overbooking of the cores which would occur via NumPy/MKL threading
+# as the parallelization takes place via MPI tasks
 export OMP_NUM_THREADS=${SLURM_CPUS_PER_TASK:-1}
 
 srun python ./python_mpi4py.py
diff --git a/examples/slurm/submit_multiprocessing.sh b/examples/slurm/submit_multiprocessing.sh
index 2316c0518fcd53701d021db9e43b672784dd187b..c1f112c865c70ef0d1feac982f44fd61dc74d0d8 100644
--- a/examples/slurm/submit_multiprocessing.sh
+++ b/examples/slurm/submit_multiprocessing.sh
@@ -1,5 +1,7 @@
 #!/bin/bash -l
-
+#
+# Example job script for using Python-Multiprocessing on Cobra@MPCDF.
+#
 #SBATCH -o ./job.out.%j
 #SBATCH -e ./job.err.%j
 #SBATCH -D ./
@@ -7,14 +9,17 @@
 #SBATCH --mail-type=none
 #SBATCH --nodes=1
 #SBATCH --ntasks-per-node=1   # only start 1 task via srun because Python multiprocessing starts more tasks internally
-#SBATCH --cpus-per-task=32    # assign all the cores to that first task to make room for Python's multiprocessing tasks
-#SBATCH --time=00:01:00
+#SBATCH --cpus-per-task=40    # assign all the cores to that first task to make room for Python's multiprocessing tasks
+#SBATCH --time=00:10:00
 
 module purge
-module load gcc/10 impi/2019.8
-module load anaconda/3/2019.03
+module load gcc/10 impi/2019.9
+module load anaconda/3/2021.05
 
-# avoid overbooking of the cores which might occur via NumPy/MKL threading
+# avoid overbooking of the cores which might occur via NumPy/MKL threading,
+# as the parallelization takes place via processes/multiprocessing
 export OMP_NUM_THREADS=1
 
+# pass the number of available cores via the command line, and
+# use that number to spawn as many workers from multiprocessing
 srun python ./python_multiprocessing.py $SLURM_CPUS_PER_TASK
diff --git a/examples/slurm/submit_multithreading.sh b/examples/slurm/submit_multithreading.sh
index 7cbb5bc989d2d29224a2197ba553cf95b94befa7..dec6259819bc738de180903905e0b1e48a4fd5ad 100644
--- a/examples/slurm/submit_multithreading.sh
+++ b/examples/slurm/submit_multithreading.sh
@@ -1,19 +1,26 @@
 #!/bin/bash -l
-
+#
+# Example job script for using Python with Multithreading (OpenMP, Numba, numexpr) on Cobra@MPCDF.
+#
 #SBATCH -o ./job.out.%j
 #SBATCH -e ./job.err.%j
 #SBATCH -D ./
-#SBATCH -J PYTHON_MP
+#SBATCH -J PYTHON_MT
 #SBATCH --mail-type=none
 #SBATCH --nodes=1
 #SBATCH --ntasks-per-node=1   # only start 1 task via srun because Python multiprocessing starts more tasks internally
-#SBATCH --cpus-per-task=32    # assign all the cores to that first task to make room for Python's multiprocessing tasks
-#SBATCH --time=00:01:00
+#SBATCH --cpus-per-task=40    # assign all the cores to that first task to make room for Python's multiprocessing tasks
+#SBATCH --time=00:10:00
 
 module purge
-module load gcc/10 impi/2019.8
-module load anaconda/3/2019.03
+module load gcc/10 impi/2019.9
+module load anaconda/3/2021.05
 
+# set the correct number of threads for various thread-parallel modules
 export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK
+export NUMBA_NUM_THREADS=$SLURM_CPUS_PER_TASK
+export NUMEXPR_NUM_THREADS=$SLURM_CPUS_PER_TASK
+# pin OpenMP threads to cores
+export OMP_PLACES=cores
 
 srun python ./python_multithreading.py
diff --git a/examples/slurm/submit_sequential.sh b/examples/slurm/submit_sequential.sh
index 3d785aa52d773a89e1b5c099180050a2db9efd1c..1c6dd5f7ef72df71c3b4679b73dca95c74bdbdef 100644
--- a/examples/slurm/submit_sequential.sh
+++ b/examples/slurm/submit_sequential.sh
@@ -1,5 +1,7 @@
 #!/bin/bash -l
-
+#
+# Example Slurm job script for a small sequential Python program on MPCDF systems.
+#
 #SBATCH -J PYTHON          # job name
 #SBATCH -o ./job.out.%j    # standard out file
 #SBATCH -e ./job.err.%j    # standard err file
@@ -7,14 +9,11 @@
 #SBATCH --ntasks=1         # launch job on a single core
 #SBATCH --cpus-per-task=1  #   on a shared node
 #SBATCH --mem=2000MB       # memory limit for the job
-#SBATCH --time=0:29:59     # run time, up to 24h
-# Important: You must use the small partition on DRACO for jobs on a shared node,
-# so enable the following line when running on DRACO:
-###SBATCH --partition=small
+#SBATCH --time=0:10:00     # run time, up to 24h
 
 module purge
-module load gcc/10 impi/2019.8
-module load anaconda/3/2019.03
+module load gcc/10 impi/2019.9
+module load anaconda/3/2021.05
 
 # avoid overbooking of the cores which might occur via NumPy/MKL threading
 export OMP_NUM_THREADS=${SLURM_CPUS_PER_TASK:-1}
diff --git a/exercises/Python_Recap_Exercise.ipynb b/exercises/Python-refresher-Exercise.ipynb
similarity index 93%
rename from exercises/Python_Recap_Exercise.ipynb
rename to exercises/Python-refresher-Exercise.ipynb
index 34f0c0e6ec001e5f5a0b5f52a8e614fb7f30307b..df4792b7dc179ad8a6bcd42ccddcab06e112c6c8 100644
--- a/exercises/Python_Recap_Exercise.ipynb
+++ b/exercises/Python-refresher-Exercise.ipynb
@@ -6,8 +6,9 @@
    "source": [
     "# Python for HPC\n",
     "\n",
-    "## Sebastian Ohlmann, Klaus Reuter\n",
-    "## Max Planck Computing and Data Facility, Garching"
+    "### 2018 - 2021 Sebastian Ohlmann, Klaus Reuter\n",
+    "\n",
+    "### Max Planck Computing and Data Facility, Garching"
    ]
   },
   {
@@ -29,7 +30,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -44,7 +45,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 5,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -66,7 +67,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 6,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -76,7 +77,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 8,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -88,7 +89,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 9,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -114,7 +115,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 10,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -123,7 +124,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 11,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -135,7 +136,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 12,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -145,7 +146,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 13,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -163,7 +164,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 14,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -173,7 +174,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 15,
    "metadata": {},
    "outputs": [
     {
@@ -194,7 +195,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 16,
    "metadata": {},
    "outputs": [
     {
@@ -213,7 +214,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 17,
    "metadata": {},
    "outputs": [
     {
@@ -246,7 +247,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 26,
+   "execution_count": 18,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -259,7 +260,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 27,
+   "execution_count": 19,
    "metadata": {},
    "outputs": [
     {
@@ -277,7 +278,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 28,
+   "execution_count": 20,
    "metadata": {},
    "outputs": [
     {
@@ -301,7 +302,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 29,
+   "execution_count": 21,
    "metadata": {},
    "outputs": [
     {
@@ -324,14 +325,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 30,
+   "execution_count": 22,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "pseudo-random word: Florence's\n"
+      "pseudo-random word: dwindling\n"
      ]
     }
    ],
@@ -342,7 +343,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 31,
+   "execution_count": 23,
    "metadata": {},
    "outputs": [
     {
@@ -413,7 +414,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 32,
+   "execution_count": 24,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -425,7 +426,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 33,
+   "execution_count": 25,
    "metadata": {},
    "outputs": [
     {
@@ -478,7 +479,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 34,
+   "execution_count": 26,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -495,7 +496,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 35,
+   "execution_count": 27,
    "metadata": {
     "scrolled": true
    },
@@ -539,7 +540,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 36,
+   "execution_count": 28,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -556,7 +557,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 37,
+   "execution_count": 29,
    "metadata": {},
    "outputs": [
     {
@@ -598,27 +599,31 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 38,
+   "execution_count": 30,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
+      "pi is approximately: 3.142\n",
       "pi is approximately: 3.142\n"
      ]
     }
    ],
    "source": [
     "import math\n",
-    "# print pi to three decimals.  Use string formatting via '{}'\n",
+    "# print pi to three decimals.  Use string formatting via '{}' and .format()!\n",
+    "#?\n",
+    "print(msg)\n",
+    "# print pi to three decimals.  Use string formatting using an f-string!\n",
     "#?\n",
     "print(msg)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 39,
+   "execution_count": 31,
    "metadata": {},
    "outputs": [
     {
@@ -633,7 +638,7 @@
     "# Check if the following sentence is a palindrome,\n",
     "# ignoring capitalization, punctuation, and whitespace.\n",
     "# Use string methods, see https://docs.python.org/3/library/stdtypes.html#string-methods\n",
-    "# palindrome credit: https://www2.cs.arizona.edu/icon/oddsends/palinsen.htm\n",
+    "# Palindrome credit: https://www2.cs.arizona.edu/icon/oddsends/palinsen.htm\n",
     "pal = \"I saw desserts; I'd no lemons, alas no melon. Distressed was I.\"\n",
     "#?\n",
     "#?\n",
@@ -652,15 +657,15 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 40,
+   "execution_count": 32,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "['Advection-withsolution.ipynb', 'Kawai-K5000W-Fret-Noise.wav', 'MPI-solutions', 'Casio-CZ-5000-Synth-Bass-C1.wav', 'Parallel_Exercise_withsolution.ipynb', 'Diffusion_serial_withsolution.ipynb', 'words.txt', 'Diffusion_MPI_withsolution.py', 'Python_Recap_Exercise_withsolution.ipynb', 'NumPy_Exercise_withsolution.ipynb', '.ipynb_checkpoints']\n",
-      "5\n"
+      "['Kawai-K5000W-Fret-Noise.wav', 'Diffusion_MPI_withsolution.py', 'Diffusion_serial_withsolution.ipynb', 'Parallel_Exercise_withsolution.ipynb', 'Casio-CZ-5000-Synth-Bass-C1.wav', 'Python_Recap_Exercise_withsolution.ipynb', 'words.txt', 'Software_engineering_Exercise_withsolution.ipynb', 'MPI-solutions', '.ipynb_checkpoints', 'NumPy_Exercise_withsolution.ipynb', 'Advection-withsolution.ipynb']\n",
+      "6\n"
      ]
     }
    ],
@@ -692,7 +697,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 41,
+   "execution_count": 33,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -707,7 +712,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 42,
+   "execution_count": 34,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -719,7 +724,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 43,
+   "execution_count": 35,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -731,7 +736,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 44,
+   "execution_count": 36,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -764,7 +769,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.7.6"
+   "version": "3.8.8"
   }
  },
  "nbformat": 4,
diff --git a/exercises/solutions/Advection-withsolution.ipynb b/exercises/_solutions/Advection-withsolution.ipynb
similarity index 100%
rename from exercises/solutions/Advection-withsolution.ipynb
rename to exercises/_solutions/Advection-withsolution.ipynb
diff --git a/exercises/_solutions/Casio-CZ-5000-Synth-Bass-C1.wav b/exercises/_solutions/Casio-CZ-5000-Synth-Bass-C1.wav
new file mode 120000
index 0000000000000000000000000000000000000000..4370a5011cf8b525a4e79111b78c0e919726f59e
--- /dev/null
+++ b/exercises/_solutions/Casio-CZ-5000-Synth-Bass-C1.wav
@@ -0,0 +1 @@
+../Casio-CZ-5000-Synth-Bass-C1.wav
\ No newline at end of file
diff --git a/exercises/solutions/Diffusion_MPI_withsolution.py b/exercises/_solutions/Diffusion_MPI_withsolution.py
similarity index 100%
rename from exercises/solutions/Diffusion_MPI_withsolution.py
rename to exercises/_solutions/Diffusion_MPI_withsolution.py
diff --git a/exercises/solutions/Diffusion_serial_withsolution.ipynb b/exercises/_solutions/Diffusion_serial_withsolution.ipynb
similarity index 100%
rename from exercises/solutions/Diffusion_serial_withsolution.ipynb
rename to exercises/_solutions/Diffusion_serial_withsolution.ipynb
diff --git a/exercises/_solutions/Kawai-K5000W-Fret-Noise.wav b/exercises/_solutions/Kawai-K5000W-Fret-Noise.wav
new file mode 120000
index 0000000000000000000000000000000000000000..a7a8ab9b914290c9062eb48f81ed7a78066b0168
--- /dev/null
+++ b/exercises/_solutions/Kawai-K5000W-Fret-Noise.wav
@@ -0,0 +1 @@
+../Kawai-K5000W-Fret-Noise.wav
\ No newline at end of file
diff --git a/exercises/solutions/MPI-solutions/block_data_decomposition.py b/exercises/_solutions/MPI-solutions/block_data_decomposition.py
similarity index 100%
rename from exercises/solutions/MPI-solutions/block_data_decomposition.py
rename to exercises/_solutions/MPI-solutions/block_data_decomposition.py
diff --git a/exercises/solutions/MPI-solutions/ping-pong.py b/exercises/_solutions/MPI-solutions/ping-pong.py
similarity index 100%
rename from exercises/solutions/MPI-solutions/ping-pong.py
rename to exercises/_solutions/MPI-solutions/ping-pong.py
diff --git a/exercises/solutions/MPI-solutions/ring.py b/exercises/_solutions/MPI-solutions/ring.py
similarity index 100%
rename from exercises/solutions/MPI-solutions/ring.py
rename to exercises/_solutions/MPI-solutions/ring.py
diff --git a/exercises/solutions/MPI-solutions/scatter_gather.py b/exercises/_solutions/MPI-solutions/scatter_gather.py
similarity index 100%
rename from exercises/solutions/MPI-solutions/scatter_gather.py
rename to exercises/_solutions/MPI-solutions/scatter_gather.py
diff --git a/exercises/solutions/MPI-solutions/scatter_reduce.py b/exercises/_solutions/MPI-solutions/scatter_reduce.py
similarity index 100%
rename from exercises/solutions/MPI-solutions/scatter_reduce.py
rename to exercises/_solutions/MPI-solutions/scatter_reduce.py
diff --git a/exercises/solutions/NumPy_Exercise_withsolution.ipynb b/exercises/_solutions/NumPy_Exercise_withsolution.ipynb
similarity index 100%
rename from exercises/solutions/NumPy_Exercise_withsolution.ipynb
rename to exercises/_solutions/NumPy_Exercise_withsolution.ipynb
diff --git a/exercises/solutions/Parallel_Exercise_withsolution.ipynb b/exercises/_solutions/Parallel_Exercise_withsolution.ipynb
similarity index 100%
rename from exercises/solutions/Parallel_Exercise_withsolution.ipynb
rename to exercises/_solutions/Parallel_Exercise_withsolution.ipynb
diff --git a/exercises/solutions/Python_Recap_Exercise_withsolution.ipynb b/exercises/_solutions/Python-refresher-Exercise-with-solution.ipynb
similarity index 93%
rename from exercises/solutions/Python_Recap_Exercise_withsolution.ipynb
rename to exercises/_solutions/Python-refresher-Exercise-with-solution.ipynb
index 4cde1fc94eb52f54a8bb50426fe42bfc2eb5c538..a1deb879cc8f2d28126176dedc97c43716056fb1 100644
--- a/exercises/solutions/Python_Recap_Exercise_withsolution.ipynb
+++ b/exercises/_solutions/Python-refresher-Exercise-with-solution.ipynb
@@ -6,8 +6,9 @@
    "source": [
     "# Python for HPC\n",
     "\n",
-    "## Sebastian Ohlmann, Klaus Reuter\n",
-    "## Max Planck Computing and Data Facility, Garching"
+    "### 2018 - 2021 Sebastian Ohlmann, Klaus Reuter\n",
+    "\n",
+    "### Max Planck Computing and Data Facility, Garching"
    ]
   },
   {
@@ -29,7 +30,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -44,7 +45,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 5,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -66,7 +67,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 6,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -76,7 +77,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 8,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -88,7 +89,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 9,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -114,7 +115,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 10,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -123,7 +124,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 11,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -135,7 +136,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 12,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -145,7 +146,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 13,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -163,7 +164,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 14,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -173,7 +174,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 15,
    "metadata": {},
    "outputs": [
     {
@@ -194,7 +195,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 16,
    "metadata": {},
    "outputs": [
     {
@@ -213,7 +214,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 17,
    "metadata": {},
    "outputs": [
     {
@@ -246,7 +247,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 26,
+   "execution_count": 18,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -259,7 +260,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 27,
+   "execution_count": 19,
    "metadata": {},
    "outputs": [
     {
@@ -277,7 +278,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 28,
+   "execution_count": 20,
    "metadata": {},
    "outputs": [
     {
@@ -301,7 +302,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 29,
+   "execution_count": 21,
    "metadata": {},
    "outputs": [
     {
@@ -324,14 +325,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 30,
+   "execution_count": 22,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "pseudo-random word: Florence's\n"
+      "pseudo-random word: dwindling\n"
      ]
     }
    ],
@@ -342,7 +343,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 31,
+   "execution_count": 23,
    "metadata": {},
    "outputs": [
     {
@@ -413,7 +414,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 32,
+   "execution_count": 24,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -425,7 +426,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 33,
+   "execution_count": 25,
    "metadata": {},
    "outputs": [
     {
@@ -478,7 +479,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 34,
+   "execution_count": 26,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -495,7 +496,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 35,
+   "execution_count": 27,
    "metadata": {
     "scrolled": true
    },
@@ -539,7 +540,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 36,
+   "execution_count": 28,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -556,7 +557,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 37,
+   "execution_count": 29,
    "metadata": {},
    "outputs": [
     {
@@ -598,27 +599,31 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 38,
+   "execution_count": 30,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
+      "pi is approximately: 3.142\n",
       "pi is approximately: 3.142\n"
      ]
     }
    ],
    "source": [
     "import math\n",
-    "# print pi to three decimals.  Use string formatting via '{}'\n",
+    "# print pi to three decimals.  Use string formatting via '{}' and .format()!\n",
     "msg = \"pi is approximately: {:.3f}\".format(math.pi)   #$\n",
+    "print(msg)\n",
+    "# print pi to three decimals.  Use string formatting using an f-string!\n",
+    "msg = f\"pi is approximately: {math.pi:.3f}\"   #$\n",
     "print(msg)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 39,
+   "execution_count": 31,
    "metadata": {},
    "outputs": [
     {
@@ -633,7 +638,7 @@
     "# Check if the following sentence is a palindrome,\n",
     "# ignoring capitalization, punctuation, and whitespace.\n",
     "# Use string methods, see https://docs.python.org/3/library/stdtypes.html#string-methods\n",
-    "# palindrome credit: https://www2.cs.arizona.edu/icon/oddsends/palinsen.htm\n",
+    "# Palindrome credit: https://www2.cs.arizona.edu/icon/oddsends/palinsen.htm\n",
     "pal = \"I saw desserts; I'd no lemons, alas no melon. Distressed was I.\"\n",
     "pal = pal.lower().replace(';', '').replace('\\'', '').replace(',', '').replace('.', '')   #$\n",
     "print(pal)   #$\n",
@@ -652,15 +657,15 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 40,
+   "execution_count": 32,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "['Advection-withsolution.ipynb', 'Kawai-K5000W-Fret-Noise.wav', 'MPI-solutions', 'Casio-CZ-5000-Synth-Bass-C1.wav', 'Parallel_Exercise_withsolution.ipynb', 'Diffusion_serial_withsolution.ipynb', 'words.txt', 'Diffusion_MPI_withsolution.py', 'Python_Recap_Exercise_withsolution.ipynb', 'NumPy_Exercise_withsolution.ipynb', '.ipynb_checkpoints']\n",
-      "5\n"
+      "['Kawai-K5000W-Fret-Noise.wav', 'Diffusion_MPI_withsolution.py', 'Diffusion_serial_withsolution.ipynb', 'Parallel_Exercise_withsolution.ipynb', 'Casio-CZ-5000-Synth-Bass-C1.wav', 'Python_Recap_Exercise_withsolution.ipynb', 'words.txt', 'Software_engineering_Exercise_withsolution.ipynb', 'MPI-solutions', '.ipynb_checkpoints', 'NumPy_Exercise_withsolution.ipynb', 'Advection-withsolution.ipynb']\n",
+      "6\n"
      ]
     }
    ],
@@ -692,7 +697,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 41,
+   "execution_count": 33,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -707,7 +712,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 42,
+   "execution_count": 34,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -719,7 +724,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 43,
+   "execution_count": 35,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -731,7 +736,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 44,
+   "execution_count": 36,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -764,7 +769,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.7.6"
+   "version": "3.8.8"
   }
  },
  "nbformat": 4,
diff --git a/exercises/solutions/Software_engineering_Exercise_withsolution.ipynb b/exercises/_solutions/Software_engineering_Exercise_withsolution.ipynb
similarity index 100%
rename from exercises/solutions/Software_engineering_Exercise_withsolution.ipynb
rename to exercises/_solutions/Software_engineering_Exercise_withsolution.ipynb
diff --git a/exercises/_solutions/words.txt b/exercises/_solutions/words.txt
new file mode 120000
index 0000000000000000000000000000000000000000..173e8a551eef0dd10bf9f5d42ae54d3db1d73455
--- /dev/null
+++ b/exercises/_solutions/words.txt
@@ -0,0 +1 @@
+../words.txt
\ No newline at end of file
diff --git a/exercises/c_interfacing/README.txt b/exercises/c_interfacing_exercise_readme.txt
similarity index 100%
rename from exercises/c_interfacing/README.txt
rename to exercises/c_interfacing_exercise_readme.txt
diff --git a/exercises/solutions/Casio-CZ-5000-Synth-Bass-C1.wav b/exercises/solutions/Casio-CZ-5000-Synth-Bass-C1.wav
deleted file mode 120000
index 597152fd989c192846a2bf0319c38b81bb58f6a7..0000000000000000000000000000000000000000
--- a/exercises/solutions/Casio-CZ-5000-Synth-Bass-C1.wav
+++ /dev/null
@@ -1 +0,0 @@
-../exercises/Casio-CZ-5000-Synth-Bass-C1.wav
\ No newline at end of file
diff --git a/exercises/solutions/Kawai-K5000W-Fret-Noise.wav b/exercises/solutions/Kawai-K5000W-Fret-Noise.wav
deleted file mode 120000
index a2ea1d787bf057ce8219958c0aed9ce95c498618..0000000000000000000000000000000000000000
--- a/exercises/solutions/Kawai-K5000W-Fret-Noise.wav
+++ /dev/null
@@ -1 +0,0 @@
-../exercises/Kawai-K5000W-Fret-Noise.wav
\ No newline at end of file
diff --git a/exercises/solutions/words.txt b/exercises/solutions/words.txt
deleted file mode 120000
index 0f04af33cc8bd9182fb76ea19ad078ae07470a48..0000000000000000000000000000000000000000
--- a/exercises/solutions/words.txt
+++ /dev/null
@@ -1 +0,0 @@
-../exercises/words.txt
\ No newline at end of file
diff --git a/notebooks/2a--NumPy.ipynb b/notebooks/2a--NumPy.ipynb
index 97e01fca143cd18a98dac56829da9836095a2132..eca98f9bd570a645506e71b6f975221eb9300139 100644
--- a/notebooks/2a--NumPy.ipynb
+++ b/notebooks/2a--NumPy.ipynb
@@ -1916,14 +1916,13 @@
    },
    "outputs": [],
    "source": [
-    "# TODO : needs update because: AttributeError: 'AxesImage' object has no attribute 'filter'\n",
-    "# from PIL import Image, ImageFilter\n",
-    "# img = Image.fromarray(ascent().astype(\"int32\"), mode=\"I\").convert(\"L\")\n",
-    "# filtered_img = im.filter(ImageFilter.FIND_EDGES)\n",
+    "from PIL import Image, ImageFilter\n",
+    "img = Image.fromarray(ascent().astype(\"int32\"), mode=\"I\").convert(\"L\")\n",
+    "filtered_img = img.filter(ImageFilter.FIND_EDGES)\n",
     "\n",
-    "# f, axs = plt.subplots(1, 2, figsize=(15, 5))\n",
-    "# axs[0].imshow(ascent(), cmap='gray')\n",
-    "# axs[1].imshow(np.asarray(filtered_img), cmap='gray');None"
+    "f, axs = plt.subplots(1, 2, figsize=(15, 5))\n",
+    "axs[0].imshow(ascent(), cmap='gray')\n",
+    "axs[1].imshow(np.asarray(filtered_img), cmap='gray');None"
    ]
   },
   {
@@ -1955,7 +1954,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.8.8"
+   "version": "3.8.3"
   },
   "rise": {
    "enable_chalkboard": true,