diff --git a/slides/build_slides.sh b/slides/build_slides.sh
index c6e3356008874027fbbbe9f2162447b867453953..6a708ff9c7391160fcba7e0924bcb426e0498865 100755
--- a/slides/build_slides.sh
+++ b/slides/build_slides.sh
@@ -6,12 +6,12 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
 
 # Build the book first, because mdbook will create any empty sections
 echo "Building book"
-RUST_LOG=info mdbook build ${SCRIPT_DIR}
+RUST_LOG=info mdbook build "${SCRIPT_DIR}"
 # Then build the slides
 echo "Building slides"
-RUST_LOG=debug mdslides --template ${SCRIPT_DIR}/template.html --output-dir ${SCRIPT_DIR}/slides --mdbook-path ${SCRIPT_DIR} --index-template ${SCRIPT_DIR}/index-template.html
+RUST_LOG=debug mdslides --template "${SCRIPT_DIR}/template.html" --output-dir "${SCRIPT_DIR}/slides" --mdbook-path "${SCRIPT_DIR}" --index-template "${SCRIPT_DIR}/index-template.html"
 # TODO: move assets copying to mdslides
 cp -r "${SCRIPT_DIR}/book/figs" "${SCRIPT_DIR}/slides"
 # Then run the tests (which is slow)
 echo "Testing book"
-RUST_LOG=info mdbook test ${SCRIPT_DIR}
\ No newline at end of file
+RUST_LOG=info mdbook test "${SCRIPT_DIR}"
\ No newline at end of file
diff --git a/slides/src/SUMMARY.md b/slides/src/SUMMARY.md
index 2303dbe4a6ea1b89a2a9d23de05e80dbb31ca2f3..90da9f734a904dafe45661ccde7ca0c2f6db0346 100644
--- a/slides/src/SUMMARY.md
+++ b/slides/src/SUMMARY.md
@@ -17,7 +17,9 @@
 - [Traits](traits.md).
 - [Tests](tests.md).
 - [Vecteurs](vec.md).
+- [Les Strings](string.md).
 <!-- - [Itérateurs](iterators.md).
 - [Unsafe Rust](collections.md).
 - [Lifetimes](lifetimes.md). -->
+- [Unsafe](unsafe.md).
 
diff --git a/slides/src/control.md b/slides/src/control.md
new file mode 100644
index 0000000000000000000000000000000000000000..a284a42955cd149a49b9e53ad3455176cc421f9b
--- /dev/null
+++ b/slides/src/control.md
@@ -0,0 +1,98 @@
+# Les structures de contrôle
+
+## Les branchements conditionnels
+
+```rust [3-5|6-8|9-11|]
+fn main() {
+    let x = 15; 
+    if x < 10 {
+        println!("{} est plus petit que 10.", x);
+    } 
+    else if x >= 10 && x < 20 {
+        println!("{x} est plus grand ou égal à 10 et plus petit que 20.");
+    } 
+    else {
+        println!("{x} est plus grand ou égal à 20.");
+    }
+}
+```
+
+## C'est des **expressions**
+
+```rust [2|4-10|4,6,9,10|]
+fn main() {
+    let x = -1;
+    let sign = 
+        if x > 0 {
+            1 // pas de ;
+        } else if x < 0 {
+            -1 // pas de ;
+        } else {
+            0 // pas de ;
+        }; // attention au ;
+}
+```
+
+## La boucle infinie: `loop`
+
+```rust [] ignore
+fn main() {
+    let mut x = 0;
+    loop {
+        println!("En boucle!");
+        x += 1;
+    }
+}
+```
+
+## Sortie avec `break`
+
+```rust [3,10|8|]
+fn main() {
+    let mut i = 0;
+    let j = loop {
+        println!("{}, en boucle!", i);
+        i += 1;
+        if i == 10 {
+            println!("Fin de la boucle!");
+            break i; // i est optionnel
+        }
+    }; // attention au ;
+}
+```  
+
+## La boucle `while`
+
+```rust [3,6|]
+fn main() {
+    let mut i = 0;
+    while i != 10 {
+        println!("{}-ème boucle!", i);
+        i += 1;
+    }
+    println!("Fin de la boucle!");
+}
+```  
+
+## La boucle `for` et `continue`
+
+```rust [2,7|3-5|]
+fn main() {
+    for i in 0..10 {
+        if i % 2 == 0 {
+           continue;
+        }
+        println!("{}-ème boucle!", i);
+    }
+    println!("Fin de la boucle!");
+}
+```  
+
+## La boucle `for` ++
+
+```rust ignore
+for i in collection {
+    // instructions
+}
+```
+
diff --git a/slides/src/figs/ferris.png b/slides/src/figs/ferris.png
new file mode 100644
index 0000000000000000000000000000000000000000..43670489a4eec797ed4f239223da47c550156679
Binary files /dev/null and b/slides/src/figs/ferris.png differ
diff --git a/slides/src/figs/mem_cp.png b/slides/src/figs/mem_cp.png
new file mode 100644
index 0000000000000000000000000000000000000000..e1640ca99a366cdf7ae69292bca37cfff7a31875
Binary files /dev/null and b/slides/src/figs/mem_cp.png differ
diff --git a/slides/src/figs/mem_mv.png b/slides/src/figs/mem_mv.png
new file mode 100644
index 0000000000000000000000000000000000000000..23450801090a77dd13d4a0cc212a06d778ddcc1b
Binary files /dev/null and b/slides/src/figs/mem_mv.png differ
diff --git a/slides/src/figs/mem_ref_vec.png b/slides/src/figs/mem_ref_vec.png
new file mode 100644
index 0000000000000000000000000000000000000000..02e14a6f185a0d867058de549d582f7cf5f7e6a2
Binary files /dev/null and b/slides/src/figs/mem_ref_vec.png differ
diff --git a/slides/src/figs/mem_vec.png b/slides/src/figs/mem_vec.png
new file mode 100644
index 0000000000000000000000000000000000000000..94c932d166e097a6f6e74d04efb1747f572fbb6a
Binary files /dev/null and b/slides/src/figs/mem_vec.png differ
diff --git a/slides/src/introduction.md b/slides/src/introduction.md
index b34667caade3ca50432769f8dcb0ebd4f012edbf..5ed4f86b362b3515c84aeab435c41053ebe4b32a 100644
--- a/slides/src/introduction.md
+++ b/slides/src/introduction.md
@@ -36,7 +36,7 @@
 
 - Une mascotte super mignonne
 
-![Ferris](figs/ferris.svg)
+![Ferris](figs/ferris.png)
 
 ## Une brève histoire du Rust
 
diff --git a/slides/src/ownership.md b/slides/src/ownership.md
index 7517cef3d983838ac63be3c9e06302e223b9b876..97993087f07e278267b9d7fa3af48ccaf8650869 100644
--- a/slides/src/ownership.md
+++ b/slides/src/ownership.md
@@ -46,20 +46,26 @@ fn main() {
 } // x sort de la portée et sa valeur est détruite
 ```
 
-## Allocation de la mémoire (1/3)
-
-- Façons principales d'allouer/désallouer dynamiquement de la mémoire.
-    1. Manuellement (C/C++, ...): on ordonne à l'OS d'allouer/désallouer de la mémoire sur le tas. 
-        a. Oublier de désallouer la mémoire allouée (fuite mémoire/memory leak).
-        b. Désallouer de la mémoire trop tôt (dangling pointer et comportement indéfini).
-        c. Libérer la mémoire à double.
-    2. Automatiquement: on a un "garbage collector" (java, scala, ...).
-        a. Consomme des ressources.
-        b. Est une "boîte magique": il fait ce qu'il veut.
+## Allocation de la mémoire: Manuelle
+
+* Manuellement (C/C++, ...): on ordonne à l'OS d'allouer/désallouer de la mémoire sur le tas. 
+    - Oublier de désallouer la mémoire allouée (fuite mémoire/memory leak).
+    - Désallouer de la mémoire trop tôt (dangling pointer et comportement indéfini).
+    - Libérer la mémoire à double.
+    
+## Allocation de la mémoire: Garbage collection
+
+* Automatiquement: on a un "garbage collector" (java, scala, ...).
+    - Consomme des ressources.
+    - Est une "boîte magique": il fait ce qu'il veut.
+
+## Allocation de la mémoire: Rust
+
 - En Rust on contrôle où et quand on alloue/désalloue à la compilation:
     - Difficulté: il faut suivre des règles **très** strictes.
+    - Garbage collection "à la compilation".
 
-## Allocation de mémoire (2/3)
+## Allocation de mémoire (tas)
 
 - Les types vus jusque là sont stockés dans la pile: leur *taille est connue* à la compilation.
 - Que se passe-t-il lorsque la taille est *inconnue à la compilation*?
@@ -76,9 +82,9 @@ fn main() {
 } // x/y sortent de la portée, il sont détruits et la mémoire est libérée
 ```
 
-## Allocation de mémoire (3/3)
+## Allocation de mémoire (Vec)
 
-![La représentation en mémoire du vecteur `v = (1,2,3,4)`](figs/mem_vec.svg)
+![La représentation en mémoire du vecteur `v = (1,2,3,4)`](figs/mem_vec.png)
 
 - Pile: 1 pointeur vers le tas, et 2 entiers (longueur et capacité).
 - Tas: 1, 2, 3, 4.
@@ -130,7 +136,7 @@ fn main() {
 - En ne faisant rien on a **deux** propriétaires des données.
 - Illégal: on invalide `y`.
 
-![](figs/mem_mv.svg)
+![](figs/mem_mv.png)
 
 ## Exception au `move`: `Copy`
 
@@ -150,7 +156,7 @@ fn main() {
 
 - *move*: copie uniquement la variable et le propriétaire **change**.
 - *copie*: on duplique la variable **et** les données.
-![](figs/mem_cp.svg)
+![](figs/mem_cp.png)
 
 ## Quand interviennent les `move`?
 
@@ -216,7 +222,7 @@ fn main() {
 
 ## La référence (schéma)
 
-![](figs/mem_ref_vec.svg)
+![](figs/mem_ref_vec.png)
 
 ## Exemple 1
 
diff --git a/slides/src/smart_pointers.md b/slides/src/smart_pointers.md
index d12ad321ce900f5201ac0e687ed5b9993479511c..5f5dbcf559a312c074c721dacd8be714a0a03a0b 100644
--- a/slides/src/smart_pointers.md
+++ b/slides/src/smart_pointers.md
@@ -5,28 +5,33 @@
 - Un **pointeur** est une variable qui contient une adresse mémoire.
 - Cette adresse **pointe** vers des données.
 
-![Illustration: tableau.](figs/mem_ref_vec.svg)
+![Illustration: tableau.](figs/mem_ref_vec.png)
 
 - Question: Quel type de pointeur avons-nous déjà rencontré?
 	- Réponse: La référence.
 
 ## Smart pointers
 
-- Un **pointeur intelligent** est un type abstrait qui rajoute des fonctionnalités au poiteur standard.
+- Type abstrait qui rajoute des fonctionnalités au poiteur standard.
 	- Management automatique de la mémoire.
 	- Vérification de limites.
-- En particulier, ils permettent la désallocation de la mémoire de manière automatique:
-	- On peut avoir plusieurs pointeurs sur un espace mémoire.
-	- Quand le dernier pointeurs est détruit, l'espace mémoire est désalloué.
-	- Permet d'empêcher les fuites mémoires.
-- Il existe différents types: 
-	- Un pointeur unique est le propriétaire de ses données (quand il est détruit les données aussi).
-	- On compte le nombre de références sur des données, quand ce nombre tombe à zéro on détruit tout.
+- Permettent la désallocation de la mémoire de manière automatique:
+	- Plusieurs pointeurs sur un espace mémoire.
+	- Dernier pointeurs est détruit => espace mémoire est désalloué.
+	- Empêche les fuites mémoires.
+
+## Types de pointeurs
+
+- Différents types: 
+	- Pointeur unique, propriétaire de ses données (quand il est détruit les données aussi).
+	- Comptage de références sur des données, quand ce nombre tombe à zéro on détruit tout.
+	- Mutabilité intérieure: les règles de Rust sont imposées à l'exécution.
+	- Accès atomiques: pas de lecture/écriture concurrente possible sur la valeur pointée.
 
 ## En Rust
 
 - Exemples: 
-	- `Vec<T>`, `String`: ces types possèdent de la mémoire et la manipule eux-mêmes.
+	- `Vec<T>`, `String`: ces types possèdent de la mémoire et la manipulent eux-mêmes.
 - Les pointeurs intelligent doivent implémenter deux traits:
 	- `Deref`: comment on déréférence le pointeur.
 	- `Drop`: comment on détruit le pointeur.
diff --git a/slides/src/string.md b/slides/src/string.md
new file mode 100644
index 0000000000000000000000000000000000000000..0834ec963037292512177d991b7c1fe4dd530995
--- /dev/null
+++ b/slides/src/string.md
@@ -0,0 +1,96 @@
+# Les chaînes de caractères
+
+## Généralités
+
+- Deux types de chaînes de caractères: `str` et `String`:
+    - `str`: *string literal* (stocké explicitement dans l'exécutable).
+    - `String`: liste dynamique de caractères UTF-8.
+- `String` est propriétaire de ses données.
+- `str` ne peut être "manipulé" que via `&str`
+
+```rust
+let literal = "Le type de literal est &str.";
+```
+
+## La structure `String`
+
+```console
+ptr       # pointeur sur le tas de char
+len       # nombre d'éléments utilisés
+capacity  # mémoire allouée
+```
+
+## Créer des `String`s
+
+```rust [1|2|3|]
+let mut empty = String::new();
+let hello = String::from("Hello World!"); // converti depuis un &str
+let other_hello = "Hello World!".to_string();
+```
+
+## Modifier des `String`s
+
+```rust [1-2|]
+let mut s = String::from("Hello");
+let s1 = " World!";
+s.push_str(&s1); // On peut aussi faire push_str(" World!")
+println!("{s}");
+```
+
+## Concaténer des `String`s
+
+```rust [1-4|]
+let s1 = String::from("Hello");
+let s2 = String::from(" World!");
+let sum1 = s1 + &s2; // s1 moved
+let sum2 = "Hello".to_string() + &s2; // s2 borrowed
+println!("{sum1} : {sum2}");
+```
+
+## Formatter des `String`s
+
+```rust
+let s1 = String::from("Hello");
+let s2 = String::from("World");
+let formatted = format!("{s1} {s2}!");
+println!("{formatted}");
+```
+
+## Indexer des `String`
+
+```rust compile_fail
+let s = String::from("Hello");
+let t = s[0]; // fail
+```
+
+```rust
+let hello = String::from("Καλημέρα!");
+println!("{}", hello.len());
+```
+
+## Encodage
+
+* UTF-8 `!=` ASCII: encodage à longueur variable (1 à 4 octets).
+* Impossible d'indexer en `O(1)`, car on connaît pas la valeur avant d'avoir lu 1 à 4 octets à chaque fois.
+
+## Mais alors comment faire?
+
+```rust [1-5|6|]
+let hello = String::from("Καλημέρα!");
+for c in hello.chars() {
+    print!("{c}");
+}
+println!("");
+println!("index 3: {}", hello.chars().nth(3).unwrap());
+```
+
+## Le slice de `String`
+
+* Une tranche de `String` est une référence vers un bout de chaîne d'UTF-8.
+* On peut facilement créer des tranches de `String`... invalides.
+
+```rust should_panic
+let hello = String::from("Καλημέρα!");
+let h = &hello[0..3];
+```
+
diff --git a/slides/src/traits.md b/slides/src/traits.md
index 97e1f36b6d3845259fe8e8e9d3c828bfaffabd85..ebbd2436a911b7c2c53185d9f3a21b027a06d0ac 100644
--- a/slides/src/traits.md
+++ b/slides/src/traits.md
@@ -23,12 +23,12 @@ trait Animal { // définition d'un trait
 } // le nombre de méthode est arbitraire
 ```
 
-## Implémentation d'un trait pour un type (1/2)
+## Implémentation d'un trait pour un type
 
-- Tout type qui implémentera un trait devra implémenter **toutes** ses méthodes.
-- Le compilateur saura que tout type implémentant un trait peut appeler ses méthodes.
+- Un type qui implémente un trait doit implémenter **toutes** ses méthodes.
+- Le compilateur sait qu'un type implémentant un trait peut appeler ses méthodes.
 
-```rust
+```rust [5-7|8-15|]
 trait Animal { // définition d'un trait
     fn cri(&self) -> String;
     fn nom(&self) -> &String;
@@ -50,9 +50,9 @@ fn main() {
 }
 ```
 
-## Implémentation d'un trait pour un type (2/2)
+## Implémentation d'un trait pour deux types
 
-```rust
+```rust [15-17|18-25|]
 trait Animal { // définition d'un trait
     fn cri(&self) -> String;
     fn nom(&self) -> &String;
@@ -89,9 +89,9 @@ fn main() {
 
 ## Implémentations par défaut
 
-- Il est pratique d'avoir des implémentations par défaut (les mêmes pour tous les types implémentant un trait).
+- Pratique d'avoir des implémentations par défaut (les mêmes pour tous les types implémentant un trait).
 
-```rust
+```rust [1,3-5,6|]
 trait Animal { // définition d'un trait
     fn cri(&self) -> String;
     fn cri_puissant(&self) -> String {
@@ -110,7 +110,6 @@ impl Animal for Cat { // le bloc où les méthodes du trait sont implémentées
         String::from("Miaou")
     }
 }
-
 fn main() {
     let chien = Dog{};
     println!("Le cri du chien est {} et son cri puissant est {}.",
@@ -126,13 +125,12 @@ fn main() {
 
 - Lors de la définition d'un générique, on peut dire au compilateur si le type implémente un trait.
 
-```rust
-// Cette fonction ne peut pas foncitonner pour tous les types
+```rust [1-5|7-9|10-12|]
 // T implémente PartialEq (les opérateurs <, >)
 fn max<T: PartialOrd>(a: T, b: T) -> T {
     if a > b { a } else { b } // si on peut pas comparer a et b
 }                             // cela ne peut pas compiler, d'où
-                            // le PartialOrd
+                              // le PartialOrd
 fn main() {
     let a = 1;
     let b = 7;
diff --git a/slides/src/unsafe.md b/slides/src/unsafe.md
new file mode 100644
index 0000000000000000000000000000000000000000..5b98b13b5873916e58469261b1c85d2f27b9d53a
--- /dev/null
+++ b/slides/src/unsafe.md
@@ -0,0 +1,90 @@
+# Unsafe Rust
+
+* Compilateur **très pointilleux**:
+    * garanties de sécurité mémoire **très fortes**,
+    * décidées dès **la compilation**.
+* Des fois le compilateur prend **trop de précautions**:
+    * Peut rejeter un code valide lors d'un doute,
+    * Rust `unsafe` donne des pouvoirs supplémentaires,
+    * Tant pis si l'utilisateur·trice les utilise mal.
+* Les opérations de bas niveau sont `unsafe` par définition (p.ex. interactions avec l'OS).
+
+# Nouveaux pouvoirs
+
+* Déréférencer un pointeur brut,
+* Appeler une fonction ou une méthode `unsafe`,
+* Accéder à une variable statique mutable ou la modifier,
+* Implémenter trait `unsafe`,
+* Accéder aux champs des unions.
+
+# Les blocs `unsafe`
+
+```rust [1-3|4-6]
+unsafe {
+    // code unsafe
+};
+let bla = unsafe {
+    // le code peut retourner une valeur
+};
+```
+
+# Mais attention
+
+* Les garanties mémoires sur les références disparaissent en mode `unsafe`
+
+```rust compile_fail
+let a = 12;
+unsafe {
+    let b = &a;
+    let c = &mut a;
+};
+```
+
+# Le type pointeur brut
+
+```rust [1-2|3-4]
+let a = 12;
+let ptr_a: * const i32 = &a as * const i32;
+let mut b = 24;
+let mut_ptr_b: * mut i32 = &mut b as * mut i32;
+```
+
+# Propriétés des pointeurs bruts
+
+* `* const T`/`* mut T`: on ne peut/peut pas modifier la valeur pointée,
+* Aucune garantie que le mémoire pointée est valide,
+* Pas de libération automatique de la mémoire pointée lors de la sortie de la portée,
+* Possibilité d'allouer des données sur le tas: `alloc()` `dealloc()`.
+
+# Déréférencement d'un pointeur brut
+
+```rust [1-3|4-6]
+let mut a = 12;
+let ptr_a = &a as * const i32;
+let mut mut_ptr_a = &mut a as * mut i32;
+unsafe {
+    *mut_ptr_a = 20;
+    println!("{}, {}", *ptr_a, *mut_ptr_a);
+}
+```
+
+# Fonction `unsafe`
+
+```rust [1|2]
+unsafe fn attention_not_safe() {
+    // everything in here is implicitly annotated unsafe
+}
+unsafe {
+    attention_not_safe();
+}
+```
+
+# Remarques
+
+* Garder le code `unsafe` aussi petit que possible,
+* Aide à trouver où peuvent se trouver les erreurs de mémoire,
+* Cacher le code `unsafe` dans une API `safe`,
+* Permet de communiquer avec du code "externe" (des lib C),
+* Annotation `unsafe` d'un bloc: fait tourner ce code c'est promis il marche,
+* Annotation `unsafe fn`: attention cette fonction à des contraintes particulières. 
+
diff --git a/slides/src/vec.md b/slides/src/vec.md
index 04122444b8d8fd32e06168f7b2aa7617cde91314..44018d4cab366b630b1cb982defaf108d3a385cf 100644
--- a/slides/src/vec.md
+++ b/slides/src/vec.md
@@ -106,7 +106,7 @@ fn main() {
 }
 ```
 
-## Lecture d'éléments (2/N)
+## Lecture d'éléments (1/3)
 
 ```rust compile_fail
 struct Int(i32);
@@ -117,7 +117,7 @@ fn main() {
 }
 ```
 
-## Lecture d'éléments (3/N)
+## Lecture d'éléments (2/3)
 
 ```rust
 fn main() {
@@ -133,7 +133,7 @@ fn main() {
 }
 ```
 
-## Lecture d'éléments (4/N)
+## Lecture d'éléments (3/3)
 
 ```rust
 fn main() {