diff --git a/docs/community/training/debugging/example-python-vs-r.md b/docs/community/training/debugging/example-python-vs-r.md
deleted file mode 100644
index 3f4a8326..00000000
--- a/docs/community/training/debugging/example-python-vs-r.md
+++ /dev/null
@@ -1,112 +0,0 @@
-# Example: Python vs R
-
-=== "Overview"
-
- Here we have provided SIR ODE model implementations in Python and in R.
- Each script runs several scenarios and produces a plot of infection prevalence for each scenario.
-
- You can download each script to debug on your computer:
-
- - [sir_ode.py](sir_ode.py)
- - [sir_ode.R](sir_ode.R)
-
-=== "Python"
-
- ```py title="sir_ode.py" linenums="1"
- --8<-- "sir_ode.py"
- ```
-
-=== "R"
-
- ```R title="sir_ode.R" linenums="1"
- --8<-- "sir_ode.R"
- ```
-
-??? bug "The model outputs differ!"
-
- Here are prevalence time-series plots produced by each script:
-
- === "Python plot"
-
-
- 
- Model outputs for the Python script.
-
-
- === "R plot"
-
-
- 
- Model outputs for the R script.
-
-
-??? note "Some initial thoughts ..."
-
- - Is it obvious whether one of the figures is correct and the other is wrong?
-
- - The `sir_rhs()` functions in the two scripts appear to be equivalent — but are they?
-
- - The `default_settings()` functions appear to be equivalent — but are they?
-
- - The `run_model_scaled_beta()` and `run_model_scaled_gamma()` functions also appear to be equivalent.
-
- - Where might you begin looking?
-
-??? info "Commentary"
-
- > I've heard that dicts (and other mutable data types) are passed by reference, as such a function could change the “local” value of a variable, which causes an error when using the “global” variable in another function.
- >
- > This would also be good for showing that your test cases aren’t perfect.
- >
- > You can run function 1 tests and get good answers, and then run function 2 test and get good answers, but this is because they are not sharing the state of the mutable variable.
- > Sounds like a great inclusion as a mini chapter.
-
- These are great ideas! The one drawback of the mutable data example is that it won't work in R, because it's copy-on-write. But that's no big deal. In fact, now that I think about, this difference us surely worth highlighting! People who are familiar with only one of these two languages need to be aware of this important difference if they begin using the other language.
-
- I've come up with an example of shared mutable state resulting in incorrect model outputs.
-
- !!! quote "The R Language Definition"
-
- The semantics of invoking a function in R argument are **call-by-value**.
- In general, supplied arguments behave as if they are **local variables** initialized with the value supplied and the name of the corresponding formal argument.
- Changing the value of a supplied argument within a function **will not affect** the value of the variable in the calling frame.
-
- — [Argument Evaluation](https://cran.r-project.org/doc/manuals/r-patched/R-lang.html#Argument-evaluation)
-
- !!! quote "Python Programming FAQ"
-
- Remember that arguments are **passed by assignment** in Python.
- Since assignment just **creates references** to objects, there's no alias between an argument name in the caller and callee, and so no call-by-reference per se.
-
- — [How do I write a function with output parameters (call by reference)?](https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference)
-
- ??? info "Output messages"
-
- Here are the output messages printed by each script:
-
- === "Python"
-
- ```text
- beta = 1.0 gamma = 0.5
- beta = 1.5 gamma = 0.5
- beta = 1.5 gamma = 0.35
- ```
-
- === "R"
-
- ```text
- beta = 1.0 gamma = 0.5
- beta = 1.5 gamma = 0.5
- beta = 1.0 gamma = 0.35
- ```
-
- ??? bug "Parameters differ!"
-
- There's a difference in the parameter values for the third scenario:
-
- ```diff
- beta = 1.0 gamma = 0.5
- beta = 1.5 gamma = 0.5
- - beta = 1.5 gamma = 0.35
- + beta = 1.0 gamma = 0.35
- ```
diff --git a/docs/community/training/debugging/example-square-numbers.md b/docs/community/training/debugging/example-square-numbers.md
new file mode 100644
index 00000000..ca1471e2
--- /dev/null
+++ b/docs/community/training/debugging/example-square-numbers.md
@@ -0,0 +1,97 @@
+# Example: Square numbers
+
+[Square numbers](https://en.wikipedia.org/wiki/Square_number) are positive integers that are equal to the square of an integer.
+Here we have provided example Python and R scripts that print all of the square numbers between 1 and 100:
+
+
+
+You can download these scripts to run on your own computer:
+
+- [square_numbers.py](square_numbers.py)
+- [square_numbers.R](square_numbers.R)
+
+Each script contains three functions:
+
+- `main()`
+- `find_squares(lower_bound, upper_bound)`
+- `is_square(value)`
+
+The diagram below shows how `main()` calls `find_squares()`, which in turn calls `is_square()` many times.
+
+```mermaid
+sequenceDiagram
+ participant M as main()
+ participant F as find_squares()
+ participant I as is_square()
+ activate M
+ M ->>+ F: lower_bound = 1, upper_bound = 100
+ Note over F: squares = [ ]
+ F ->>+ I: value = 1
+ I ->>- F: True/False
+ F ->>+ I: value = 2
+ I ->>- F: True/False
+ F -->>+ I: ...
+ I -->>- F: ...
+ F ->>+ I: value = 100
+ I ->>- F: True/False
+ F ->>- M: squares = [...]
+ Note over M: print(squares)
+ deactivate M
+```
+
+??? info "Source code"
+
+ === "Python"
+
+ ```py title="square_numbers.py" linenums="1"
+ --8<-- "square_numbers.py"
+ ```
+
+ === "R"
+
+ ```R title="square_numbers.R" linenums="1"
+ --8<-- "square_numbers.R"
+ ```
+
+## Stepping through the code
+
+These recorded terminal sessions demonstrate how to use Python and R debuggers from the command line.
+They cover:
+
+- How to define breakpoints;
+- How to inspect the current values of variables; and
+- How to step through, and over, lines of code.
+
+!!! tip "Interactive debugger sessions"
+
+ If your editor supports running a debugger, **use this feature!**
+ See these examples for [RStudio](https://support.posit.co/hc/en-us/articles/205612627-Debugging-with-the-RStudio-IDE), [PyCharm](https://www.jetbrains.com/pycharm/features/debugger.html), [Spyder](https://docs.spyder-ide.org/current/panes/debugging.html), and [VS Code](https://code.visualstudio.com/docs/editor/debugging).
+
+=== "Python debugger"
+
+
+
+ Video timeline:
+
+ 1. Set a breakpoint
+ 2. Show current location
+ 3. Step into `is_square()`
+ 4. Return from `is_square()`
+ 5. Show updated `squares` list
+ 6. Add a conditional breakpoint
+ 7. Stop at the conditional breakpoint
+ 8. Continue until the script ends
+
+=== "R debugger"
+
+
+
+ Video timeline:
+
+ 1. Set a breakpoint
+ 2. Step into `is_square()`
+ 3. Return from `is_square()`
+ 4. Show updated `squares` list
+ 5. Add a conditional breakpoint
+ 6. Stop at the conditional breakpoint
+ 7. Continue until the script ends
diff --git a/docs/community/training/debugging/example-perfect-numbers.md b/docs/community/training/debugging/exercise-perfect-numbers.md
similarity index 71%
rename from docs/community/training/debugging/example-perfect-numbers.md
rename to docs/community/training/debugging/exercise-perfect-numbers.md
index 64bf908f..a5d66dfc 100644
--- a/docs/community/training/debugging/example-perfect-numbers.md
+++ b/docs/community/training/debugging/exercise-perfect-numbers.md
@@ -1,4 +1,4 @@
-# Perfect numbers
+# Exercise: Perfect numbers
=== "Overview"
@@ -22,7 +22,7 @@
--8<-- "perfect_numbers.R"
```
-??? bug "But there's a problem ..."
+!!! bug "But there's a problem ..."
If we run these scripts, we see that **they don't print anything**:
@@ -30,6 +30,12 @@
How should we begin investigating?
+
+!!! tip "Interactive debugger sessions"
+
+ If your editor supports running a debugger, **use this feature!**
+ See these examples for [RStudio](https://support.posit.co/hc/en-us/articles/205612627-Debugging-with-the-RStudio-IDE), [PyCharm](https://www.jetbrains.com/pycharm/features/debugger.html), [Spyder](https://docs.spyder-ide.org/current/panes/debugging.html), and [VS Code](https://code.visualstudio.com/docs/editor/debugging).
+
??? note "Some initial thoughts ..."
- Are we actually running the `main()` function at all?
diff --git a/docs/community/training/debugging/exercise-python-vs-r.md b/docs/community/training/debugging/exercise-python-vs-r.md
new file mode 100644
index 00000000..a73a8a6d
--- /dev/null
+++ b/docs/community/training/debugging/exercise-python-vs-r.md
@@ -0,0 +1,58 @@
+# Exercise: Python vs R
+
+=== "Overview"
+
+ Here we have provided SIR ODE model implementations in Python and in R.
+ Each script runs several scenarios and produces a plot of infection prevalence for each scenario.
+
+ You can download each script to debug on your computer:
+
+ - [sir_ode.py](sir_ode.py)
+ - [sir_ode.R](sir_ode.R)
+
+=== "Python"
+
+ ```py title="sir_ode.py" linenums="1"
+ --8<-- "sir_ode.py"
+ ```
+
+=== "R"
+
+ ```R title="sir_ode.R" linenums="1"
+ --8<-- "sir_ode.R"
+ ```
+
+!!! bug "The model outputs differ!"
+
+ Here are prevalence time-series plots produced by each script:
+
+ === "Python plot"
+
+
+ 
+ Model outputs for the Python script.
+
+
+ === "R plot"
+
+
+ 
+ Model outputs for the R script.
+
+
+!!! tip "Interactive debugger sessions"
+
+ If your editor supports running a debugger, **use this feature!**
+ See these examples for [RStudio](https://support.posit.co/hc/en-us/articles/205612627-Debugging-with-the-RStudio-IDE), [PyCharm](https://www.jetbrains.com/pycharm/features/debugger.html), [Spyder](https://docs.spyder-ide.org/current/panes/debugging.html), and [VS Code](https://code.visualstudio.com/docs/editor/debugging).
+
+??? note "Some initial thoughts ..."
+
+ - Is it obvious whether one of the figures is correct and the other is wrong?
+
+ - The `sir_rhs()` functions in the two scripts appear to be equivalent — but are they?
+
+ - The `default_settings()` functions appear to be equivalent — but are they?
+
+ - The `run_model_scaled_beta()` and `run_model_scaled_gamma()` functions also appear to be equivalent.
+
+ - Where might you begin looking?
diff --git a/docs/community/training/debugging/solutions.md b/docs/community/training/debugging/solutions.md
new file mode 100644
index 00000000..b0031f3b
--- /dev/null
+++ b/docs/community/training/debugging/solutions.md
@@ -0,0 +1,50 @@
+# Exercise solutions
+
+## Perfect numbers
+
+Perfect numbers are equal to the sum of their proper divisors — all divisors except the number itself.
+
+For example, 6 is a perfect number.
+Its proper divisors are 1, 2, and 3, and 1 + 2 + 3 = 6.
+
+The mistake here is that the `divisors_of()` function only returns divisors **greater than one**, and so the code fails to identify any of the true perfect numbers.
+
+Interestingly, this mistake did not result in the code mistakenly identifying any other numbers as perfect numbers.
+
+## Python vs R
+
+If you're only familiar with one of these two languages, you may be surprised to discover that they have some fundamental differences.
+In this exercise we demonstrated one consequence of the ways that these languages handle function arguments.
+
+!!! quote "The R Language Definition"
+
+ The semantics of invoking a function in R argument are **call-by-value**.
+ In general, supplied arguments behave as if they are **local variables** initialized with the value supplied and the name of the corresponding formal argument.
+ Changing the value of a supplied argument within a function **will not affect** the value of the variable in the calling frame.
+
+ — [Argument Evaluation](https://cran.r-project.org/doc/manuals/r-patched/R-lang.html#Argument-evaluation)
+
+!!! quote "Python Programming FAQ"
+
+ Remember that arguments are **passed by assignment** in Python.
+ Since assignment just **creates references** to objects, there's no alias between an argument name in the caller and callee, and so no call-by-reference per se.
+
+ — [How do I write a function with output parameters (call by reference)?](https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference)
+
+- In R the `run_model_scaled_beta()` and `run_model_scaled_gamma()` functions **do not modify** the value of `settings` in the `demonstration()` function.
+ This produces model outputs for the following parameter combinations:
+
+ - β = 1.0 and γ = 0.5;
+ - β = 1.5 and γ = 0.5; and
+ - **β = 1.0 and γ = 0.35**.
+
+- In Python the `run_model_scaled_beta()` and `run_model_scaled_gamma()` functions **do modify** the value of `settings` in the `demonstration()` function.
+ This produces model outputs for the following parameter combinations:
+
+ - β = 1.0 and γ = 0.5;
+ - β = 1.5 and γ = 0.5; and
+ - **β = 1.5 and γ = 0.35**.
+
+!!! success "Answer"
+
+ The value of β is different in the third combination.
diff --git a/docs/community/training/debugging/using-a-debugger.md b/docs/community/training/debugging/using-a-debugger.md
index 09296ff3..8e228a10 100644
--- a/docs/community/training/debugging/using-a-debugger.md
+++ b/docs/community/training/debugging/using-a-debugger.md
@@ -1,118 +1,65 @@
# Using a debugger
-!!! tip
+The main features of a debugger are:
- A debugger is a tool for examining the state of a running program.
+- **Breakpoints:** pause the program when a particular line of code is about to be executed;
- Debuggers can help us to find errors because they show us what the code **is actually doing**.
+- **Display/print:** show the current value of local variables;
-!!! question
+- **Next:** execute the current line of code and pause at the next line;
- What is the "state" of a running program?
+- **Continue:** continue executing code until the next breakpoint, or the code finishes.
-How to use a debugger to examine the program state:
+Slightly more advanced features include:
-- Breakpoints
-- Conditional breakpoints
-- Printing values
-- Stepping into and over lines
-- Understanding the call stack and interpreting tracebacks
+- **Conditional breakpoints:** pause the program when a particular line of code is about to be executed **and** a specific condition is satisfied.
-## Code: Square numbers
+- **Step:** execute the current line of code and pause at the first possible point — either the line in the current function **or** the first line in a function that is called.
-[Square numbers](https://en.wikipedia.org/wiki/Square_number) are positive integers that are equal to the square of an integer.
-Here we have provided example Python and R scripts that print all of the square numbers between 1 and 100:
+For example, consider the following code example:
-
+=== "Python"
-You can download these scripts to run on your own computer:
+ ```py linenums="1" hl_lines="4"
+ def first_function():
+ total = 0
+ for x in range(1, 50):
+ y = second_function(x)
+ total = total + y
-- [square_numbers.py](square_numbers.py)
-- [square_numbers.R](square_numbers.R)
+ return total
-Each script contains three functions:
-- `main()`
-- `find_squares(lower_bound, upper_bound)`
-- `is_square(value)`
+ def second_function(a):
+ result = 3 * a**2 + 5 * a
+ return result
-The diagram below shows how `main()` calls `find_squares()`, which in turn calls `is_square()` many times.
-```mermaid
-sequenceDiagram
- participant M as main()
- participant F as find_squares()
- participant I as is_square()
- activate M
- M ->>+ F: lower_bound = 1, upper_bound = 100
- Note over F: squares = [ ]
- F ->>+ I: value = 1
- I ->>- F: True/False
- F ->>+ I: value = 2
- I ->>- F: True/False
- F -->>+ I: ...
- I -->>- F: ...
- F ->>+ I: value = 100
- I ->>- F: True/False
- F ->>- M: squares = [...]
- Note over M: print(squares)
- deactivate M
-```
+ first_function()
+ ```
-??? info "Source code"
+=== "R"
- === "Python"
+ ```R linenums="1" hl_lines="4"
+ first_function <- function() {
+ total <- 0
+ for (x in seq(49)) {
+ y <- second_function(x)
+ total <- total + y
+ }
+ total
+ }
- ```py title="square_numbers.py" linenums="1"
- --8<-- "square_numbers.py"
- ```
+ second_function <- function(a) {
+ result <- 3 * a^2 + 5 * a
+ result
+ }
- === "R"
+ first_function()
+ ```
- ```R title="square_numbers.R" linenums="1"
- --8<-- "square_numbers.R"
- ```
+- We can use a **conditional breakpoint** to pause on line 4 (highlighted) only when `x = 42`.
-## Stepping through the code
+- We can then use **step** to begin executing line 4 and pause on line 11, where we will see that `a = 42`.
-The recorded terminal sessions demonstrate how to use Python and R debuggers from the command line.
-They cover:
-
-- How to define breakpoints;
-- How to inspect the current values of variables; and
-- How to step through, and over, lines of code.
-
-!!! tip "Interactive debugger sessions"
-
- If your editor supports running a debugger, **use this feature!**
- See these examples for [RStudio](https://support.posit.co/hc/en-us/articles/205612627-Debugging-with-the-RStudio-IDE), [PyCharm](https://www.jetbrains.com/pycharm/features/debugger.html), [Spyder](https://docs.spyder-ide.org/current/panes/debugging.html), and [VS Code](https://code.visualstudio.com/docs/editor/debugging).
-
-
-=== "Python debugger"
-
-
-
- Video timeline:
-
- 1. Set a breakpoint
- 2. Show current location
- 3. Step into `is_square()`
- 4. Return from `is_square()`
- 5. Show updated `squares` list
- 6. Add a conditional breakpoint
- 7. Stop at the conditional breakpoint
- 8. Continue until the script ends
-
-=== "R debugger"
-
-
-
- Video timeline:
-
- 1. Set a breakpoint
- 2. Step into `is_square()`
- 3. Return from `is_square()`
- 4. Show updated `squares` list
- 5. Add a conditional breakpoint
- 6. Stop at the conditional breakpoint
- 7. Continue until the script ends
+- If we instead used **next** at line 4 (highlighted), the debugger would execute line 4 and then pause on line 5.
diff --git a/docs/community/training/debugging/why-is-debugging-useful.md b/docs/community/training/debugging/why-are-debuggers-useful.md
similarity index 55%
rename from docs/community/training/debugging/why-is-debugging-useful.md
rename to docs/community/training/debugging/why-are-debuggers-useful.md
index 26684769..ba755e4a 100644
--- a/docs/community/training/debugging/why-is-debugging-useful.md
+++ b/docs/community/training/debugging/why-are-debuggers-useful.md
@@ -1,16 +1,18 @@
-# Why is debugging useful?
+# Why are debuggers useful?
-Many of the errors that take a long time for us to find are relatively simple **once we find them**.
+!!! tip
-We usually have a hard time finding these errors because:
+ A debugger is a tool for examining the state of a running program.
-1. We read what we expect to see, rather than what is actually written; and
+ Debuggers are useful because they show us what the code **is actually doing**.
-2. We rely on assumptions about where the mistake might be, and our intuition is often wrong.
+Many of the errors that take a long time for us to find are relatively simple **once we find them**.
+
+We usually have a hard time finding these errors because:
-!!! info
+1. **We read what we expect to see**, rather than what is actually written; and
- Debugging forces us to verify our assumptions and to observe what the code is actually doing.
+2. **We rely on assumptions** about where the mistake might be, and our intuition is often wrong.
Here are some common mistakes that can be difficult to identify when reading through your own code:
diff --git a/mkdocs.yml b/mkdocs.yml
index b9c16cdd..01773df3 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -110,12 +110,14 @@ nav:
- "Learning objectives": community/training/debugging/learning-objectives.md
- "Debugging manifesto": community/training/debugging/manifesto.md
- "What is debugging?": community/training/debugging/what-is-debugging.md
- - "Why is debugging useful?": community/training/debugging/why-is-debugging-useful.md
+ - "Why are debuggers useful?": community/training/debugging/why-are-debuggers-useful.md
- "Using a debugger": community/training/debugging/using-a-debugger.md
- - "Example: Perfect numbers": community/training/debugging/example-perfect-numbers.md
- - "Example: Python vs R": community/training/debugging/example-python-vs-r.md
+ - "Example: Square numbers": community/training/debugging/example-square-numbers.md
+ - "Exercise: Perfect numbers": community/training/debugging/exercise-perfect-numbers.md
+ - "Exercise: Python vs R": community/training/debugging/exercise-python-vs-r.md
- "Techniques and tools": community/training/debugging/techniques-and-tools.md
- "Resources": community/training/debugging/resources.md
+ - "Exercise solutions": community/training/debugging/solutions.md
markdown_extensions:
- admonition