diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3487c326..db2fae5e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -276,8 +276,7 @@ Have you tried turning it off and on again?
Example Solution
```elixir
-initial_count = 0
-initial_count + high
+
```
diff --git a/README.md b/README.md
index 5047808a..e61d2969 100644
--- a/README.md
+++ b/README.md
@@ -105,3 +105,4 @@ See [start.livemd](https://github.com/DockYard-Academy/curriculum/blob/main/star
+
diff --git a/exercises/capstone_entity_relationship_diagram.livemd b/exercises/capstone_entity_relationship_diagram.livemd
index 79aace3a..396ce8ae 100644
--- a/exercises/capstone_entity_relationship_diagram.livemd
+++ b/exercises/capstone_entity_relationship_diagram.livemd
@@ -78,7 +78,7 @@ See https://mermaid.js.org/syntax/entityRelationshipDiagram.html for the syntax.
### Requirements
* Document the entities and their fields.
-* Document the associations (many-to-one, many-to-many, one-to-one) in your capstone project
+* Document the associations (many-to-one, many-to-many, one-to-one).
## Commit Your Progress
diff --git a/exercises/games_supervised_score_tracker.livemd b/exercises/games_supervised_score_tracker.livemd
index 43e11c58..8d6949c0 100644
--- a/exercises/games_supervised_score_tracker.livemd
+++ b/exercises/games_supervised_score_tracker.livemd
@@ -60,7 +60,7 @@ Increase the `ScoreTracker`'s score whenever a user wins the game.
```elixir
-# Games.ScoreTracker Should Be A Named Process, So It Is Not Necessary To Send The Pid.
+# Games.ScoreTracker should be a named process, so we don't need to provide the pid.
{:ok, _pid} = Games.ScoreTracker.start_link()
:ok = Games.Score.add_points(10)
:ok = Games.Score.add_points(10)
diff --git a/exercises/group_project_blog.livemd b/exercises/group_project_blog.livemd
index 4bdf65af..bd0d6b96 100644
--- a/exercises/group_project_blog.livemd
+++ b/exercises/group_project_blog.livemd
@@ -124,7 +124,7 @@ $ git init
Edit the `README.md` file initialized in your Phoenix project.
-Include alteast the following information:
+Include at least the following information:
* Project Name
* Project Summary
diff --git a/exercises/stack.livemd b/exercises/stack.livemd
index d65d99fc..24ce5ab0 100644
--- a/exercises/stack.livemd
+++ b/exercises/stack.livemd
@@ -58,7 +58,7 @@ In addition to the above, add documentation and at least one doctest for the `pu
This will be a **pair testing** exercise Using TDD (Test Driven Development). We recommend using Visual Studio Code LiveShare to collaborate.
-1. One student (**the tester**) will write a test
+1. One student (**the tester**) will write a single test
2. The other student (**the implementer**) will implement **only** the code necessary to make the test pass.
3. **Swap roles after each test.**
diff --git a/exercises/supervised_stack.livemd b/exercises/supervised_stack.livemd
index d7c4520a..3cf85f16 100644
--- a/exercises/supervised_stack.livemd
+++ b/exercises/supervised_stack.livemd
@@ -32,9 +32,13 @@ Mix.install([
## Supervised Stack
-Previously we created a [Stack](./stack_server.livemd) [GenServer](https://hexdocs.pm/elixir/GenServer.html) process.
+You're going to create a stack project that starts a name [Stack](./stack_server.livemd) GenServer process under a supervisor.
-We've made a slight modification to the `Stack` process by adding a `start_link/1` function so this named `Stack` can be started under a [Supervisor](https://hexdocs.pm/elixir/Supervisor.html).
+```
+mix new stack
+```
+
+Here's an example Stack GenServer you can use.
```elixir
defmodule Stack do
@@ -63,30 +67,13 @@ defmodule Stack do
end
```
-We're able to push and pop elements off of the stack.
-
-```elixir
-{:ok, stack_pid} = GenServer.start_link(Stack, [])
-
-GenServer.call(stack_pid, {:push, 1}) |> IO.inspect(label: "push")
-GenServer.call(stack_pid, {:push, 2}) |> IO.inspect(label: "push")
-GenServer.call(stack_pid, {:push, 3}) |> IO.inspect(label: "push")
-
-GenServer.call(stack_pid, :pop) |> IO.inspect(label: "pop")
-GenServer.call(stack_pid, :pop) |> IO.inspect(label: "pop")
-GenServer.call(stack_pid, :pop) |> IO.inspect(label: "pop")
-
-# The Final State Is Empty.
-:sys.get_state(stack_pid)
-```
-
-However, there's a bug. If we try to `pop/1` an item off of an empty stack, the process
+We're able to push and pop elements off of the stack. However, there's a bug. If we try to `pop/1` an item off of an empty stack, the process
will crash due to a function clause error because the `handle_call/2` function expects a list with one or more elements.
Uncomment the following code to watch the `Stack` crash.
```elixir
-# {:ok, Pid} = GenServer.start_link(Stack, [])
+# {:ok, pid} = GenServer.start_link(Stack, [])
# GenServer.call(stack_pid, :pop)
```
@@ -102,7 +89,7 @@ def handle_call(:pop, _from, []) do
end
```
-Instead, you're going to start the Stack process under a supervisor so that it will be restarted when it crashes. In the Elixir cell below, start the `Stack` process under a supervisor so that it will restart with an empty stack when it crashes.
+Instead, you're going to start the `Stack` process under a supervisor in your application so that it will be restarted when it crashes.
Example Solution
@@ -117,18 +104,17 @@ children = [
-Keep in mind, if you have already started a supervisor with the `Stack` process, your livebook may crash. You can resolve this issue by simply re-running the cell below to start the supervisor again.
+
-```elixir
+### Crash The Stack
-```
-
-You should be able to send a `:pop` message to the `Stack` process and the [Supervisor](https://hexdocs.pm/elixir/Supervisor.html) will restart the `Stack` process.
+Open the [IEx](https://hexdocs.pm/iex/IEx.html) shell and send the `Stack` a `:pop` message to cause it to crash and restart.
-Uncomment and evaluate the code below to test your supervisor.
+
```elixir
-# GenServer.call(Stack, :pop)
+$ iex -S mix
+iex> GenServer.call(Stack, :pop)
```
## Commit Your Progress
diff --git a/exercises/task_drills.livemd b/exercises/task_drills.livemd
index 47bde063..2704e6e0 100644
--- a/exercises/task_drills.livemd
+++ b/exercises/task_drills.livemd
@@ -40,18 +40,51 @@ This set of drills is for [Tasks](../reading/task.livemd). Follow the instructio
Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) to spawn a task process that returns any response.
+
+Example Solution
+
+```elixir
+task = Task.async(fn -> :ok end)
+
+Task.await(task)
+```
+
+
+
```elixir
```
Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) to spawn a task process that sleeps for six seconds. It should cause a timeout error.
+
+Example Solution
+
+```elixir
+task = Task.async(fn -> Process.sleep(6000) end)
+
+Task.await(task)
+```
+
+
+
```elixir
```
Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) to spawn a task process that sleeps for six seconds. Provide a timeout value to [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) so that it properly awaits the response.
+
+Example Solution
+
+```elixir
+task = Task.async(fn -> Process.sleep(6000) end)
+
+Task.await(task, 7000)
+```
+
+
+
```elixir
```
@@ -60,67 +93,75 @@ Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await/
Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) to spawn a task process that returns any response.
-
-
-### Slow Operation
+
+Example Solution
```elixir
-# 1000 Operations
-{time, _result} = :timer.tc(fn -> Enum.map(1..10, fn int -> Process.sleep(1000) end) end)
-time
+task = Task.async(fn -> :ok end)
+
+Task.yield(task)
```
+
+
```elixir
-{time, _result} =
- :timer.tc(fn ->
- # 1000 tasks
- # 1000 operations -> parallel
- tasks =
- Enum.map(1..10, fn int ->
- Task.async(fn ->
- IO.puts("starting task #{int}")
- Process.sleep(1000)
- end)
- end)
- Task.await_many(tasks)
- end)
+```
+
+Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) to spawn a task process that sleeps for six seconds and returns any response. Notice that the yield is `nil`.
+
+
+Example Solution
-10_009_225
-1_001_494
+```elixir
+task = Task.async(fn -> Process.sleep(6000) end)
+
+Task.yield(task)
```
-### Fast Operation
+
```elixir
-# 1000 Operations
-{time, _result} = :timer.tc(fn -> Enum.map(1..10, fn int -> int * 2 end) end)
-time
+
```
+Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) to spawn a task process that sleeps for six seconds and returns any response. Provide a timeout value to [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) so that it properly returns the response.
+
+
+Example Solution
+
```elixir
-{time, _result} =
- :timer.tc(fn ->
- # 1000 tasks
- # 1000 operations -> parallel
- tasks = Enum.map(1..10, fn int -> Task.async(fn -> int * 2 end) end)
- Task.await_many(tasks)
- end)
+task = Task.async(fn -> Process.sleep(6000) end)
+
+Task.yield(task, 7000)
```
-Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) to spawn a task process that sleeps for six seconds and returns any response. Notice that the yield is `nil`.
+
```elixir
```
-Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) to spawn a task process that sleeps for six seconds and returns any response. Provide a timeout value to [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) so that it properly returns the response.
+Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2), and [Task.shutdown/2](https://hexdocs.pm/elixir/Task.html#shutdown/2) to spawn a task process that sleeps for six seconds. Shutdown the task process if it does not yield any value after five seconds.
+
+Use `IO.puts/2` to prove that the task was shutdown.
+
+
+Example Solution
```elixir
+task =
+ Task.async(fn ->
+ Process.sleep(6000)
+ IO.puts("NOT RAN")
+ end)
+if !Task.yield(task) do
+ Task.shutdown(task)
+end
```
-Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2), and [Task.shutdown/2](https://hexdocs.pm/elixir/Task.html#shutdown/2) to spawn a task process that sleeps for six seconds. Shutdown the task process if it does not yield any value.
+
```elixir
@@ -130,17 +171,34 @@ Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), [Task.yield/2](
Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to spawn two task processes that both return a random number from `1..10`.
+
+Example Solution
+
+```elixir
+task1 = Task.async(fn -> Enum.random(1..10) end)
+task2 = Task.async(fn -> Enum.random(1..10) end)
+
+Task.await_many([task1, task2])
+```
+
+
+
```elixir
```
Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to spawn one hundred task processes that all return a random integer from `1..100`.
+
+Example Solution
+
```elixir
+tasks = Enum.map(1..100, fn _ -> Task.async(fn -> Enum.random(1..100) end) end)
+Task.await_many(tasks)
```
-Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to spawn one hundred task processes that return a list doubled numbers from one to one hundred. i.e. `[2, 4, 6, 8, ..., 198, 200]`.
+
```elixir
@@ -148,13 +206,29 @@ Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), [Task.async/1](http
Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), [String.upcase/2](https://hexdocs.pm/elixir/String.html#upcase/2), and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to concurrently capitalize every string in the list `["apple", "pear", "peaches"]`
+
+Example Solution
+
+```elixir
+list = ["apple", "pear", "peaches"]
+
+tasks = Enum.map(list, fn word -> Task.async(fn -> String.upcase(word) end) end)
+
+Task.await_many(tasks)
+```
+
+
+
```elixir
```
## Task.Supervisor
-Start a [Supervisor](https://hexdocs.pm/elixir/Supervisor.html) with a child `Task.Supervisor` process named `MyTaskSupervisor`. You will use `MyTaskSupervisor` in all of the examples below that need a task supervisor.
+Start a [Supervisor](https://hexdocs.pm/elixir/Supervisor.html) with a child `Task.Supervisor` process named `MyTaskSupervisor`. Use a `:one_for_one` strategy. You will use `MyTaskSupervisor` in all of the examples below that need a task supervisor.
+
+
+Example Solution
```elixir
children = [
@@ -164,13 +238,46 @@ children = [
Supervisor.start_link(children, strategy: :one_for_one)
```
+
+
+```elixir
+
+```
+
Use `Task.Supervisor.async/3` and [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) to start a supervised task process that returns a random number after sleeping for two seconds.
+
+Example Solution
+
```elixir
+task = Task.Supervisor.async(MyTaskSupervisor, fn ->
+ Process.sleep(2000)
+ Enum.random(1..10)
+end)
+Task.await(task)
```
-Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), `Task.Supervisor.async/3` and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to start one hundred supervised task processes that returns a list of doubled numbers from one `1..100`. i.e. `[2, 4, 6, 8, ..., 198, 200]`.
+
+
+```elixir
+
+```
+
+Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), `Task.Supervisor.async/3` and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to start one hundred supervised task processes that returns a random number.
+
+
+Example Solution
+
+```elixir
+tasks = Enum.map(1..100, fn _ ->
+ Task.Supervisor.async(MyTaskSupervisor, fn -> Enum.random(1..10) end)
+end)
+
+Task.await_many(tasks)
+```
+
+
```elixir
@@ -180,13 +287,47 @@ Use `Task.Supervisor.start_child/3` to start a `:temporary` task that crashes af
Use [Supervisor.which_children/1](https://hexdocs.pm/elixir/Supervisor.html#which_children/1) after six seconds to demonstrate that a `:temporary` process is not restarted.
+
+Example Solution
+
+```elixir
+task =
+ Task.Supervisor.start_child(MyTaskSupervisor, fn ->
+ Process.sleep(5000)
+ raise "error"
+ end)
+
+Process.sleep(6000)
+Supervisor.which_children(MyTaskSupervisor)
+```
+
+
+
```elixir
```
-Use `Task.Supervisor.start_child/3` with the `restart: :transient` option to start a `:transient` task that crashes after five seconds.
+Use `Task.Supervisor.start_child/3` with the `restart: :transient` option to start a `:transient` task that crashes after one second.
+
+Use `IO.inspect/2` and `self/0` to demonstrate that the process is restarted, and that the `pid` has changed.
+
+
+Example Solution
+
+```elixir
+task =
+ Task.Supervisor.start_child(
+ MyTaskSupervisor,
+ fn ->
+ IO.inspect(self(), label: "Process restarted")
+ Process.sleep(1000)
+ raise "error"
+ end,
+ restart: :transient
+ )
+```
-Use [Supervisor.which_children/1](https://hexdocs.pm/elixir/Supervisor.html#which_children/1) after six seconds to demonstrate that the `:transient` process is restarted.
+
```elixir
diff --git a/start.livemd b/start.livemd
index 307c5e52..6776c857 100644
--- a/start.livemd
+++ b/start.livemd
@@ -479,7 +479,7 @@ For new students, we recommend that you [start here](reading/start_here.livemd).
* Instruction
* [PicChat: Messages](reading/pic_chat_messages.livemd)
-!-- livebook:{"break_markdown":true} -->
+
### LiveView Authentication
diff --git a/utils/test/test_helper.exs b/utils/test/test_helper.exs
index e4ba82d6..869559e7 100644
--- a/utils/test/test_helper.exs
+++ b/utils/test/test_helper.exs
@@ -1,3 +1 @@
ExUnit.start()
-# avoids issues with module attributes not being loaded.
-System.cmd("mix", ["compile", "--force"], env: [{"MIX_ENV", "test"}])