diff --git a/README.md b/README.md
index ab6f7b6307c8b32562fa4d3b97ee2a2ae2c2c7ec..a6882f010f91525d2fb8e69dfc23c11471171860 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,9 @@
 
 ## Semestre 2023 Printemps
 
-[Configuration pour la salle de TP](CONFIGURATION.md)
-
-[Questions sur le cours](https://forge.univ-lyon1.fr/programmation-fonctionnelle/lifpf/-/issues/?sort=updated_desc&state=all&label_name%5B%5D=Question)
+- [Configuration pour la salle de TP](CONFIGURATION.md)
+- [Rappels git et gitlab](gitlab.md)
+- [Questions sur le cours](https://forge.univ-lyon1.fr/programmation-fonctionnelle/lifpf/-/issues/?sort=updated_desc&state=all&label_name%5B%5D=Question)
 
 | jour  | heure         | type     | supports / remarques                                                                      |
 | ----- | ------------- | -------- | ----------------------------------------------------------------------------------------- |
@@ -23,7 +23,8 @@
 | 13/03 | 8h            | CM       | [Diapositives](cm/lifpf-cm5.pdf)                                                          |
 |       | 9h45 ou 11h30 | TP       | [Sujet](tp/tp5.md), [corrigé de l'exercice 1](tp/tp5.ml)                                  |
 | 20/03 | 8h            | TD + QCM | [Sujet](td/lifpf-td5-enonce.pdf)                                                          |
-|       | 9h45 ou 11h30 | TP       | [Sujet](tp/tp6.md) <br> Groupe de TP, horaire et salle sur [tomuss]                       |
+|       | 9h45 ou 11h30 | TP       | [Sujet](tp/tp6.md)                                                                        |
+| 27/03 | 9h45 ou 11h15 | TP       | [Sujet](tp/tp7.md) <br> Groupe de TP, horaire et salle sur [tomuss]                       |
 
 ###### Évaluation
 
diff --git a/files/gitlab-1-new-project.png b/files/gitlab-1-new-project.png
new file mode 100644
index 0000000000000000000000000000000000000000..9e57004d4e06fff0730ae0fc696f9037b00e596f
Binary files /dev/null and b/files/gitlab-1-new-project.png differ
diff --git a/files/gitlab-2-blank-project.png b/files/gitlab-2-blank-project.png
new file mode 100644
index 0000000000000000000000000000000000000000..aa52115ce61631643c351b15a7ba9e892cbbde90
Binary files /dev/null and b/files/gitlab-2-blank-project.png differ
diff --git a/files/gitlab-3-cfg-project.png b/files/gitlab-3-cfg-project.png
new file mode 100644
index 0000000000000000000000000000000000000000..8b5bfb53a389a095da59fee86a123023cd7a6e91
Binary files /dev/null and b/files/gitlab-3-cfg-project.png differ
diff --git a/files/gitlab-4-clone-url.png b/files/gitlab-4-clone-url.png
new file mode 100644
index 0000000000000000000000000000000000000000..996de27e395334df6d26818b22e3e00ec755d678
Binary files /dev/null and b/files/gitlab-4-clone-url.png differ
diff --git a/files/vscode-1-src-ctl-view.png b/files/vscode-1-src-ctl-view.png
new file mode 100644
index 0000000000000000000000000000000000000000..37260aaa8b929bf50710d03b3d149ef6fc47d401
Binary files /dev/null and b/files/vscode-1-src-ctl-view.png differ
diff --git a/gitlab.md b/gitlab.md
new file mode 100644
index 0000000000000000000000000000000000000000..4a453dd16c1568638ca2a717330ba5ac11afd442
--- /dev/null
+++ b/gitlab.md
@@ -0,0 +1,120 @@
+# Rappels sur l'utilisation de git et Gitlab
+
+## Site forge.univ-lyon1.fr
+
+Le site https://forge.univ-lyon1.fr héberge une forge logicielle (Gitlab) qui permet d'héberger des projets, par exemple les TPs de LIFPF.
+Il est possible de donner des droits à d'autres utilisateurs, par exemple pour travailler en binôme (dans un projet depuis le menu "Project information > Members").
+
+## Créer un nouveau projet
+
+Un fois connecté(e), il est possible de créer un nouveau projet (bouton bleu à droite).
+
+![gitlab-1-new-project](files/gitlab-1-new-project.png)
+
+Choisir de créer un projet vierge (blank project).
+
+![gitlab-2-blank-project](files/gitlab-2-blank-project.png)
+
+Donner un nom au projet, choisir un répertoire parent (typiquement votre nom d'utilisateur) et laisser cochée la case du README, puis lancer la création via le bouton "Create project".
+
+![gitlab-3-cfg-project](files/gitlab-3-cfg-project.png)
+
+## Récupérer un projet sur sa machine (clone)
+
+Depuis le projet dans le navigateur, cliquer sur le menu du bouton "Clone" et copier l'URL de clone HTTPS.
+
+![gitlab-4-clone-url](files/gitlab-4-clone-url.png)
+
+Depuis le répertoire où on veut placer le dossier du projet, lancer la commande suivante en remplaçant `<url_du_projet>` par la valeur copiée depuis le navigateur:
+
+```shell
+git clone <url_du_projet>
+```
+
+Cela créée un répertoire ayant le nom du projet.
+
+Certaines commandes `git`, en particulier `clone`, `pull`, `push` et `fetch`, demanderont probablement un login et un mot de passe. Ce sont ceux de votre compte Lyon 1.
+
+## Synchroniser son travail
+
+Remarque: lors de l'utilisation de VSCode, il est conseillé d'ouvrir le répertoire complet du projet et pas seulement un fichier (via la commande `code nom_du_répertoire` ou via le menu "_File > Open folder_").
+
+Avant de commencer à travailler lancer la commande suivante dans le répertoire du projet:
+
+```shell
+git pull
+```
+
+Cette commande va répcupérer les dernière mise à jour de votre projet et les appliquer dans le répertoire du projet.
+
+On peut alors commencer à travailler sur les fichiers.
+Une fois que le travail stabilisé (par exemple à la fin d'une partie d'un TP), on peut _comiter_ les modifications.
+Pour cela, on commence par identifier les fichiers à _comiter_, via la commande `git add`. On peut faire autant de git add que l'on souhaite. La commande git status permet de lister les modifications par rapport à la dernière version _comitée_ par exemple:
+
+```shell
+❯ git status
+On branch main
+Your branch is up to date with 'origin/main'.
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+	titi.ml
+	toto.ml
+	tutu.ml
+
+nothing added to commit but untracked files present (use "git add" to track)
+
+❯ git add titi.ml
+
+❯ git add toto.ml tutu.ml
+
+❯ git status
+On branch main
+Your branch is up to date with 'origin/main'.
+
+Changes to be committed:
+  (use "git restore --staged <file>..." to unstage)
+	new file:   titi.ml
+	new file:   toto.ml
+	new file:   tutu.ml
+```
+
+Une fois les modifications ajoutée, on peut lancer la commande `git commit` en indiquant un message:
+
+```shell
+❯ git commit -m "tp7: partie 1.2 terminée"
+[main bfec856] tp7: partie 1.2 terminée
+ 3 files changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 titi.ml
+ create mode 100644 toto.ml
+ create mode 100644 tutu.ml
+```
+
+**Attention**, les modification ne sont pas encore répercutées sur forge.univ-lyon1.fr. Pour le faire, il faut utiliser `git push`:
+
+```shell
+❯ git push
+Enumerating objects: 4, done.
+Counting objects: 100% (4/4), done.
+Delta compression using up to 10 threads
+Compressing objects: 100% (2/2), done.
+Writing objects: 100% (3/3), 314 bytes | 314.00 KiB/s, done.
+Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
+To https://forge.univ-lyon1.fr/EMMANUEL.COQUERY/lifpf-tp7.git
+   17d2e59..bfec856  main -> main
+```
+
+Remarque: VSCode intègre des outils graphiques (vue latérale) pour gérer les opérations `add`, `commit`, `pull` et `push`. Il permet également de voir les modifications apportées au fichiers et facilite la résolution des conflits (cf ci-dessous).
+
+![vscode-1-src-ctl-view](files/vscode-1-src-ctl-view.png)
+
+### Conflits
+
+Lors d'un travail à plusieurs, il est possible que le dépôt ait été édité entre le premier `pull` et le `push`. Dans ce cas `git` refusera de faire le `push`. Il faut alors faire un `pull` pour intégrer les modifications distantes avant de faire le `push`.
+
+Si `git` ne parvient pas à fusionner les modifications, il se peut qu'il génère des conflits, visibles via `git status`et dans VSCode (lettre C à côté du fichier).
+Dans ce cas, il faut éditer le fichier et rectifier à la main son contenu.
+On peut ouvrir la vue latérale `git` dans VSCode et cliquer sur le fichier pour voir les conflits. Pour chaque conflit, VSCode proposera de prendre une des deux version, voir les deux. Souvent, cela ne dispense pas d'aller éditer le code pour le rectifier.
+
+Une fois les fichiers éditer, on les ajoute comme pour une modification usuelle.
+Il suffit ensuite de _comiter_ et pousser (`push`) les modifications.
diff --git a/tp/tp7.md b/tp/tp7.md
new file mode 100644
index 0000000000000000000000000000000000000000..620138b3311093d3bbf769f54255bc15a121af36
--- /dev/null
+++ b/tp/tp7.md
@@ -0,0 +1,181 @@
+# TP7 - Applications OCaml
+
+> **Attention sur les machines de TP** les projets `dune` ne fonctionne pas bien
+> dans les répertoires utilisateurs sur les machines de TP. Il faut donc
+> travailler dans un répertoire local de la machine. Utilisez `/tmp/p123456789`
+> comme répertoire de travail, où `p123456789` est votre login étudiant.
+>
+> Il est préférable de travailler avec un projet forge (voir [rappels gitlab](../gitlab.md))
+
+## 0. Compléments API OCaml
+
+### 0.1. Entrées sorties en OCaml
+
+En OCaml, il existe deux types permettant de lire et d'écrire dans des fichiers, sur les entrées/sorties standard, sur une socket réseau, etc:
+
+- `in_channel`: ce type représente des objets (des canaux) à partir desquels on peut lire des octets
+- `out_channel`: ce type représente des objets (des canaux) dans lesquels on peut écrire des octets
+
+Comme dans beaucoup de langages, les entrées / sorties standard et erreur sont prédéfinies dans le module `Stdlib` (qui est ouvert automatiquement dans chaque fichier):
+
+- `stdin: in_channel`: entrée standard
+- `stdout: out_channel`: sortie standard
+- `stderr: out_channel`: sortie erreur
+
+Pour lire dans un fichier, on utilise `open_in: string -> in_channel` qui fourni un `in_channel` qui lira les octets dans le fichier. Pour écrire, on utilisera `open_out: string -> out_channel`.
+
+Pour lire dans un canal d'entrée, on peut utiliser `input_line: in_channel -> string` pour lire une ligne.
+Remarque: si la fin du fichier est atteinte OCaml génère une exception.
+Cette notion n'ayant pas été vue en cours, les fonctions de lecture du contenu intégral d'un fichier seront fournies si le besoin s'en fait sentir.
+
+Pour écrire concrètement dans un canal de sortie, on peut par exemple utiliser `output_string: out_channel -> string -> unit`. Comme cette fonction ne calcule pas de valeur, elle renvoie une valeur spéciale `()` de type `unit`. `()` est la seule valeur de ce type. Ce type représente les actions en OCaml. C'est un peu l'équivalent du type `void` de C.
+
+Enfin une fois les traitements terminés sur un fichier, il faut le fermer via `close_in: in_channel -> unit` ou `close_out: out_channel -> unit`.
+
+**[Documentation](https://v2.ocaml.org/releases/4.14/api/Stdlib.html#1_Inputoutput)** des entrées/sorties de base en OCaml.
+
+## 1. Application usine de jouets
+
+### 1.1. Reprise de l'usine de jouets
+
+> Terminer la partie 2. du [TP5](tp5.md) sur l'usine de lutins.
+
+### 1.2. Gestion de données JSON
+
+Dans le fichier `lib/dune`, ajouter la bibliothèque `yojson`, en ajoutant au besoin une section `libraries` après `name`:
+
+```ocaml
+(library
+ (name lutins)
+ (libraries yojson))
+```
+
+La bibliothèque `yojson` permet de lire des fichiers au format [JSON](https://fr.wikipedia.org/wiki/JavaScript_Object_Notation).
+Ci-dessous un exemple de fichier JSON:
+
+```json
+{
+  "lutins": [
+    "Harcèlemoutons",
+    "Ravineur",
+    "Courtaud",
+    "Lèchecuillère",
+    "Grattepot",
+    "Lèchebol",
+    "Claqueporte",
+    "Gobeyahourt",
+    "Chipesaucisse",
+    "Zieutefenêtre",
+    "Renifleporte",
+    "Crocheviande",
+    "Volebougie"
+  ],
+  "jouets": [
+    "toupie",
+    "osselets",
+    "ballon",
+    "nounours",
+    "robot",
+    "poupée",
+    "cubes"
+  ],
+  "jours": {
+    "lundi": { "attribution": "longueur_nom", "nombre": "toujours_42" },
+    "mardi": { "attribution": "premiere_lettre", "nombre": "carre_nom" },
+    "mercredi": { "attribution": "longueur_nom", "nombre": "diff_nom" },
+    "jeudi": { "attribution": "premiere_lettre", "nombre": "toujours_42" },
+    "vendredi": { "attribution": "longueur_nom", "nombre": "carre_nom" },
+    "samedi": { "attribution": "premiere_lettre", "nombre": "diff_nom" },
+    "dimanche": { "attribution": "longueur_nom", "nombre": "toujours_42" }
+  }
+}
+```
+
+Les fichiers JSON permettent de représenter des structures imbriquées arbitrairement.
+Une fois lues depuis le fichier cette structure est représentée par un type inductif, [`Yojson.Basic.t`](https://ocaml-community.github.io/yojson/yojson/Yojson/Basic/index.html):
+
+```ocaml
+type t =
+| `Null
+| `Bool of bool
+| `Int of int
+| `Float of float
+| `String of string
+| `Assoc of (string * t) list
+| `List of t list
+```
+
+Attention à la syntaxe avec les quotes inversées `` `   `` devant les constructueurs.
+`Yojson` utilise des constructeurs particuliers qui sont distingués via cette syntaxe.
+En pratique et dans le cadre de ce programme, on pourra les utiliser comme des constructeurs habituels, mais les messages d'erreurs seront un peu différents.
+Il sera ici particulièrement important de **bien spécifier les types des fonctions** qui vont manipuler ces structures.
+
+L'exemple de fichier ci-dessus produira uniquement des structures utilisant les 3 constructeurs suivants:
+
+- `` `String`` pour les valeurs textuelles comme par exemple `"Harcèlemoutons"` qui sera représenté par la structure `` `String "Harcèlemoutons"``
+- `` `List`` pour les listes de valeurs comme `[ "toupie", "osselets"]` qui sera représentée par la structure: `` `List [ `String "toupie"; `String "osselets"]``
+- `` `Assoc`` pour les dictionnaires clé-valeur comme `{ "attribution": "longueur_nom", "nombre": "toujours_42" }` qui sera représentée par la structure: `` `Assoc [("attribution", `String "longueur_nom"); ("nombre", `String "toujours_42")]``.
+
+Une `` `List`` ou une `` `Assoc`` peuvent contenir des éléments plus complexe que des `` `String``.
+Par exemple la version simplifiée du fichier précédent:
+
+```json
+{
+  "lutins": ["Harcèlemoutons", "Ravineur"],
+  "jouets": ["toupie", "osselets"],
+  "jours": {
+    "lundi": { "attribution": "longueur_nom", "nombre": "toujours_42" },
+    "mardi": { "attribution": "premiere_lettre", "nombre": "carre_nom" }
+  }
+}
+```
+
+sera représentée par la structure suivante:
+
+```ocaml
+`Assoc [
+    ("lutins", `List [ `String "Harcèlemoutons"; `String "Ravineur" ]);
+    ("jouets", `List [ `String "toupie"; `String "osselets"]);
+    ("jours", `Assoc [
+        ("lundi", `Assoc [("attribution", `String "longueur_nom");
+                          ("nombre", `String "toujours_42")]);
+        ("mardi", `Assoc [("attribution", `String "premiere_lettre");
+                          ("nombre", `String "carre_nom")])
+    ])
+]
+```
+
+Dans le module `Usine` ajouter une fonction `get_lutins: Yojson.Basic.t -> string list` qui renverra la liste des lutins à partir d'une structure issue d'un fichier similaire au fichier exemple ci-dessus. Il faudra donc aller chercher la liste dans l'entrée "lutins" et traduire la liste de `` `String``.
+
+Faire de même pour les jouets avec une fonction `get_jouets: Yojson.Basic.t -> string list`. Essayez de mutualiser du code entre ces deux fonctions en créant une ou plusieurs fonctions intermédiaires.
+
+Tester ces deux fonctions via `assert` en utilisant l'exemple de structure ci-dessus.
+
+### 1.3. Configuration de l'usine à partir du fichier json
+
+On souhaite maintenant créer l'association contenant la configuration par jour à partir du contenu d'un fichier JSON structuré comme le fichier exemple précédent.
+Dans le fichier exemple, chaque jour de la semaine se voit associé deux chaînes de caractères:
+
+- la chaîne correspondant à la clé `attribution` va permettre de désigner la fonction à utiliser pour choisir le jouet qui sera fabriqué par un lutin;
+- la chaîne correspondant à la clé `nombre` va permettre de désigner la fonction à utiliser pour, étant donné un lutin et un jouet, savoir combien d'exemplaires du jouet le lutin va fabriquer.
+
+Commencer par créer un module `FonctionsUsine` contenant les fonctions suivantes:
+
+- `longueur_nom (jouets: string list) (lutin: string): string option` qui renverra le `i`<sup>ème</sup> jouet de la liste `jouets` si la longueur du (nom du) lutin est `i` (c.f. [String.length](https://v2.ocaml.org/releases/4.14/api/String.html#VALlength)). On travaillera modulo la longueur de la liste de jouets pour gérer les noms de lutins trop longs.
+- `premiere_lettre` fonctionne comme la précédente, mais en utilisant pour `i` le code ASCII de la premère lettre du nom du lutin (c.f. [Char.code](https://v2.ocaml.org/releases/4.14/api/Char.html#VALcode) et [String.get](https://v2.ocaml.org/releases/4.14/api/String.html#VALget)).
+- `toujours_42: string -> string -> int option` renverra toujours `Some 42`.
+- `carre_nom: string -> string -> int option` reverra la somme des carrés des longueurs des chaînes passées en argument.
+- `diff_nom: string -> string -> int option` renverra la taille de la différence symétrique des ensembles de lettres de chaînes passées en argument. Autrement dit, elle renvoie le nombre de caractères apparaissant dans la première chaîne mais pas dans la deuxième additionné au nombre de caractères apparaissant dans la deuxième mais pas dans la première.
+
+Dans `usine.ml`, créer une fonction `fonctions_choix_jouets (jouets: string list): (string * (string -> string option)) list` qui prend en argument une liste de jouets et créer la liste d'association contenant les paires `("premiere_lettre", FonctionsUsine.premiere_lettre jouets)` et `("longueur_nom", FonctionsUsine.longueur_nom jouets)`.
+On remarque l'application partielle des fonctions `FonctionsUsine.premiere_lettre` et `FonctionsUsine.longueur_nom` pour obtenir des fonctions de type `string -> string option` que l'on pourra placer dans une `configuration`.
+
+Réaliser un travail similaire pour créer une liste d'association pour obtenir les fonctions permettant d'obtenir le nombre de jouets fabriqués par un lutin pour un modèle de jouet.
+
+Créer enfin une fonction `configurations_of_json: Yojson.Basic.t -> ((jour, configuration) Association.assoc_t) option` qui prendra une structure JSON similaire au fichier exemple et construira une structure similaire à la variable globale contenant les configurations de chaque jour (normalement de type `(jour, configuration) Association.assoc_t`). La fonction reverra en fait une `option` qui vaudra `None` si la structure JSON contient des valeurs inconnues pour le nom des fonctions ou s'il y manque des informations (par exemple si elle ne contient pas de jouets).
+
+Pour terminer, dans le module `LutinsApp`, modifier le code de façon à:
+
+- prendre un argument supplémentaire en ligne de commande (le nom du fichier JSON à lire);
+- lire le contenu du fichier via la fonction `Yojson.Basic.from_channel: in_channel -> Yojson.Basic.t` (le `in_channel` étant lui-même obtenu via `open_in` comme expliqué au début du TP);
+- utiliser la structure obtenue pour fabriquer les listes de lutins et de jouets, créer la configurations des jours et enfin calculer la quantité produite pour chaque jouet en fonction du jour indiqué comme autre argument en ligne de commande.