diff --git a/src/ch17-00-async-await.md b/src/ch17-00-async-await.md
index 2598b10e43..4187d6029a 100644
--- a/src/ch17-00-async-await.md
+++ b/src/ch17-00-async-await.md
@@ -102,25 +102,17 @@ to the other. You’re just one person, so you can’t make progress on both tas
at the exact same time, but you can multi-task, making progress on one at a time
by switching between them (see Figure 17-1).
-
-
-Figure 17-1: A concurrent workflow, switching between Task A and Task B
-
-
+Figure 17-1: A concurrent workflow, switching between Task A and Task B
When the team splits up a group of tasks by having each member take one task and
work on it alone, this is _parallelism_. Each person on the team can make
progress at the exact same time (see Figure 17-2).
-
-
-Figure 17-2: A parallel workflow, where work happens on Task A and Task B independently
-
-
+Figure 17-2: A parallel workflow, where work happens on Task A and Task B independently
In both of these workflows, you might have to coordinate between different
tasks. Maybe you _thought_ the task assigned to one person was totally
@@ -129,13 +121,9 @@ on the team to finish their task first. Some of the work could be done in
parallel, but some of it was actually _serial_: it could only happen in a
series, one task after the other, as in Figure 17-3.
-
-
-Figure 17-3: A partially parallel workflow, where work happens on Task A and Task B independently until Task A3 is blocked on the results of Task B3.
-
-
+Figure 17-3: A partially parallel workflow, where work happens on Task A and Task B independently until Task A3 is blocked on the results of Task B3.
Likewise, you might realize that one of your own tasks depends on another of
your tasks. Now your concurrent work has also become serial.
diff --git a/src/ch17-05-traits-for-async.md b/src/ch17-05-traits-for-async.md
index d4447a34b5..7450d02106 100644
--- a/src/ch17-05-traits-for-async.md
+++ b/src/ch17-05-traits-for-async.md
@@ -237,13 +237,9 @@ moving the state machine Rust creates for us. And unlike most other types in
Rust, the futures Rust creates for async blocks can end up with references to
themselves in the fields of any given variant, as shown in the simplified illustration in Figure 17-4.
-
-
-Figure 17-4: A self-referential data type.
-
-
+Figure 17-4: A self-referential data type.
By default, though, any object that has a reference to itself is unsafe to move,
because references always point to the actual memory address of whatever they
@@ -254,13 +250,9 @@ when you make changes to the data structure. For another—more important—thin
the computer is now free to reuse that memory for other purposes! You could end
up reading completely unrelated data later.
-
-
-Figure 17-5: The unsafe result of moving a self-referential data type
-
-
+Figure 17-5: The unsafe result of moving a self-referential data type
Theoretically, the Rust compiler could try to update every reference to an
object whenever it gets moved, but that could add a lot of performance overhead,
@@ -275,13 +267,9 @@ value by wrapping a pointer to that value in `Pin`, it can no longer move. Thus,
if you have `Pin>`, you actually pin the `SomeType` value, _not_
the `Box` pointer. Figure 17-6 illustrates this process.
-
-
-Figure 17-6: Pinning a `Box` that points to a self-referential future type.
-
-
+Figure 17-6: Pinning a `Box` that points to a self-referential future type.
In fact, the `Box` pointer can still move around freely. Remember: we care about
making sure the data ultimately being referenced stays in place. If a pointer
@@ -291,13 +279,9 @@ for the types as well as the `std::pin` module and try to work out how you’d d
this with a `Pin` wrapping a `Box`.) The key is that the self-referential type
itself cannot move, because it is still pinned.
-
-
-Figure 17-7: Moving a `Box` which points to a self-referential future type.
-
-
+Figure 17-7: Moving a `Box` which points to a self-referential future type.
However, most types are perfectly safe to move around, even if they happen to be
behind a `Pin` wrapper. We only need to think about pinning when items have
@@ -342,13 +326,9 @@ characters that make it up. We can wrap a `String` in `Pin`, as seen in Figure
17-8. However, `String` automatically implements `Unpin`, as do most other types
in Rust.
-
-
-Figure 17-8: Pinning a `String`; the dotted line indicates that the `String` implements the `Unpin` trait, and thus is not pinned.
-
-
+Figure 17-8: Pinning a `String`; the dotted line indicates that the `String` implements the `Unpin` trait, and thus is not pinned.
As a result, we can do things that would be illegal if `String` implemented
`!Unpin` instead, such as replacing one string with another at the exact same
@@ -356,13 +336,9 @@ location in memory as in Figure 17-9. This doesn’t violate the `Pin` contract,
because `String` has no internal references that make it unsafe to move around!
That is precisely why it implements `Unpin` rather than `!Unpin`.
-
-
-Figure 17-9: Replacing the `String` with an entirely different `String` in memory.
-
-
+Figure 17-9: Replacing the `String` with an entirely different `String` in memory.
Now we know enough to understand the errors reported for that `join_all` call
from back in Listing 17-17. We originally tried to move the futures produced by