Cette page décrit la structure de Macao-Legacy et l'emplacement des données de contenu.
*À plusieurs reprises, on a besoin de décrire un motif de nommage : dans ces cas, le caractère `#` correspond à un chiffre, et `_` à n'importe quel caractère alphanumérique. Quand ces caractères sont répétés, ils décrivent par défaut un champ de longueur variable (exemple: `###` désigne de 1 à 3 chiffres)*
---
**Modules** : Macao est composé de 3 modules (Macao 1, 2 et 3). Macao 1 et 2 partagent la même base de code `macao_12`, Macao 3 a été développé plus tard et réside dans `macao_3`.
Un module contient une ou plusieurs parties _(ex:"Reconnaîtrelessyllabes")_, qui elles-mêmes peuvent contenir d'autres (sous-)parties. Côté code, une partie a la même représentation qu'un module, c'est un élément sans contenu propre, décrit seulement dans le manifeste [`imsmanifest.xml`](https://gitlab.tetras-libre.fr/macao/macao-legacy/-/blob/main/Basilisk/MACAO/macao_12/imsmanifest.xml)
-[x]Descendants dans l'arbre -\> éléments `<item>`
---
## Sous-parties
On appelle sous-parties les parties de dernier niveau, les "feuilles" de l'arborescence. Dans le panneau de gauche, ce sont les éléments non dépliables _(ex: "Reconnaître les syllabes en anglais oral")_. Une sous-partie contient plusieurs **activités**, dont la première est affichée quand on sélectionne la sous-partie. Une sous-partie est décrite dans un fichier `sco/MosEtp###`, qui déclare un objet `MosSCO` pour définir son contenu.
```js
oSco=newMosSCO("MosEtp129","> Reconnaître les syllabes en anglais oral","MACAO","MACAO 1 - S'entraîner à la reconnaissance","","macao_fusion_ss_barre","fr");
```
Peu d'infos utiles : nom du fichier, titre (déjà défini dans le `<title>`), titre du "stage" (constant), titre du module parent (déjà connu grâce au manifest), et quelques champs constants.\
Ensuite quelques lignes inutiles, puis on passe à la déclaration des pages.
```js
oSco.tabPages[oSco.tabPages.length]=newPageContenu("Repérer les syllabes orales","pg861","exercice","");
oSco.tabPages[oSco.tabPages.length]=newPageContenu("Repérer les syllabes écrites","pg60","exercice","");
Le plus important est l'ID de la page `"pg###"`, et éventuellement le type (`"exercice"` ou `"cours"`), le titre de la page étant déclaré aussi dans la page elle-même.
**Données à extraire :**
- Dans le manifest
- [x] ID -\> attribut `identifier`
- [x] Titre -\> élément `<title>`
- Dans le fichier `MosEtp###.html`
- [~] Titre -\>`<title>`
- [x] Liste des pages (titre, ID) -\> arguments de `new PageContenu()`
---
## Activités, ou pages
Les "unités de navigation". La section centrale de Macao affiche toujours 1 activité, dont le nom est indiqué en haut à droite _(ex: "Repérer les syllabes orales")_. Une activité peut être un cours (sans saisie interactive) ou un des 4 types d'exercices (`QC, QM, TAT, GD` dans `MosMtr/scripts/contenu/ClasseExercice___.js` + `ClasseCours.js`). Elle est décrite dans un fichier `contenu/pages/pg###.html`, qui déclare un objet `Cours` ou `Exercice___` pour définir son contenu.
**Données à extraire (communes à toutes les activités) :**
- [x] Type d'activité -\> premier appel de constructeur `new ___()`
-[x] [Commentaires](#commentaires) -\> éléments `<div id="divCmt___">` dans `<div id="zoneInvisible">`
- [ ] Dans les descriptions, commentaires, blocs HTML divers
**Exemple QCM** : `pg8412.html`, page _"Vérifier la place de l'accent primaire (3)"_ dans la sous-partie _"\> Utiliser les marques de l'accentuation"_
Il s'avère que les 9 exercices QCM sont tous dans la même sous-partie, et sont utilisés sémantiquement comme plusieurs QCU : \
Dans cet exemple, on a 3 mots ayant chacun 3 réponses possibles dont 1 bonne, mais l'exercice est implémenté comme un QCM de 9 choix possibles ; on peut tout à fait cocher les 3 choix pour "narrator". C'est un exemple de cas particulier étrange qui devra être corrigé manuellement.
</details>
**Données à extraire :**
- [x] Consigne -\>`<div id="STY_question">`
- [x] Choix de réponses
- [x] Correction -\> dans la fonction `entrerDonnees()`, `exo.tabStylesR[nr] = CODE_V` ou `CODE_F` pour chaque valeur de `nr`
- [x] Commentaires de succès et d'échec -\>`divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### ExerciceQM
_(Question Multiple?)_\
Comme ExerciceQC mais avec plusieurs questions, chacune ayant une seule bonne réponse.\
- [ ] Choix de réponses -\> tableau dans `<div id="STY_texteQM">`, chaque ligne (`<tr>`) est une question, chaque cellule de colonne (`<td>`) est une case à cocher. Son `id` indique aussi ses coordonnées (ex: `id="lienRepImg13"` = ligne 1 choix 3)
- [ ] Correction -\> dans la fonction `entrerDonnees()`, `exo.tabStylesR[nr] = '3'` indiquent le numéro du choix correct pour chaque numéro de ligne `nr`
- [x] Commentaires de succès et d'échec -\>`divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### ExerciceTAT
Un texte à trous, avec pour chaque "trou" une liste déroulante de choix de mots.\
**Quantité :** 12
<details>
<summary>Exemple</summary>
`pg20.html`, page _"Ecoutez et complétez (2)"_ dans la sous-partie _"\> Reconnaître les déterminants"_\
- [ ] Éléments à déplacer -\> éléments `<div id="exoGDd#">` (le `d` est pour _déplaçable_, et est suivi de son numéro/ID)
- [ ] Cibles de déplacement -\> éléments `<div id="exoGDc#">` (le `c` est pour _cible_, suivi aussi de son numéro/ID)
- [ ] Correction -\> liste de `new PaireGD(deplacable, cible, correct, decalageX, decalageY)` indiquent pour chaque déplaçable sa cible associée et si il est juste (`ng` = faux, `nw` = juste).
- [ ] Positions de tous les éléments -\> offsets CSS `absolute`, sûrement à refaire manuellement.
- [x] Commentaires de succès et d'échec -\>`divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### Inutilisés
ExerciceCURS, ExerciceEXP, ExerciceSEQ
---
## Pages d'aide ou "docs"
Dans `contenu/pages/`, les fichiers `*.htm` et `pgd###.html` sont des pages d'aide. Au lieu d'être chargées dans la section centrale, elles peuvent être ouvertes dans une nouvelle fenêtre pop-up avec la fonction `SCO_ouvrirDoc()`, souvent appelée depuis un lien `<a>` dans les pages classiques.
```html
cliquez pour voir la définition d'un <ahref="javascript:parent.SCO_ouvrirDoc('pgd171','PAGE')">phonème</a>
```
Ces pages peuvent inclure des objets Flash comme les autres, mais pas d'exercice.
## Contenus des pages
### Commentaires
Certains exercices ont des commentaires, des blocs HTML structurés chargés dans une `<div id="zoneInvisible">`, qui sont déplacés dans la `<div id="STY_zoneCommentaire">` à droite en réponse à certaines actions.
- Commentaire de succès : `<div id="divCmtSucces">`
- Commentaire d'échec : `<div id="divSugg#">`, numérotés à partir de 1
- Autres commentaires : `<div id="divCmt#">`, numérotés à partir de 1, contiennent un petit texte d'aide.
:warning: Les commentaires **peuvent contenir de la mise en forme et des objets Flash** (peut-être même des images ?)
### Images
Les images intégrées dans le contenu d'une page sont reconnaissables par un `id="MosImg###`, à la différence de celles utilisées pour l'UI (boutons). Leur chemin est toujours dans `contenu/media/`.
Idem que Macao12 avec `imsmanifest.xml`, mais le nommage devient `seq######`
## Sous-parties
Idem que Macao12, mais le nommage devient `act######`. De même, le fichier `sco/MosEtp###.html` devient `sco/act######.html`.\
Des fichiers XML `sco/md_act######.xml` font leur apparition pour chaque sous-partie, mais contiennent des métadonnées pour SCORM qui ne nous intéressent pas.
À la fin du `imsmanifest.xml`, un tag `<resource ... identifier="rsrcact######" ...>` décrit les dépendances de la sous-partie, sous la forme d'une liste de fichiers : pages `pg###.html`, images, SWFs... Potentiellement utile, ou bien redondant si on les retrouve dans le contenu HTML des pages.
Même format pour le contenu (JavaScript) de la sous-partie, avec `new MosSCO(...)` et presque le même pour les lignes `new PageContenu()`, qui ont ici 6 paramètres string au lieu de 4, le dernier indiquant le type d'activité (`"COURS"`, `"QC"`, `"TAT"`, etc...).
Cependant, Macao 3 (ou très probablement MOS Chorus) semble avoir essayé d'obfusquer les définitions des réponses dans le code, peut-être pour éviter qu'un étudiant puisse ouvrir les *devtools* et déduire facilement les réponses correctes. C'est toujours possible en lisant le code (puisque l'appli fonctionne toujours sans serveur), mais complexifié par l'utilisation de techniques... exotiques.
Les sections suivantes sur chaque type d'exercice détaillent ces changements.
### ExerciceQC
L'initialisation des choix ne se base plus sur des indices, mais sur des ID.
- Les éléments HTML des choix (ex: `<div class="STY_reponseQC" id="lienrep627" ...>`) portent chacun un ID de la forme `repX` (la partie `lien` est ignorée et `X` est un nombre).
- À cet élément HTML correspond un objet JS déclaré comme
```js
varoItem=newItemReponse('rep678');
```
où le paramètre du constructeur est décodé par une fonction `decodeX`, définie [ici](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceQC.js#L567), qui remplace les caractères `0 1 2 3 7 8 9` entre eux et conserve les autres. Le résultat est le vrai ID du choix correspondant.
- Cet objet JS est initialisé avec `oItem.init("42", "", "", "");`, où le premier paramètre indique la justesse du choix. Si le dernier caractère est `1`, c'est un choix juste, sinon faux.
- Chaque choix peut être associé à un commentaire de suggestion, de la façon suivante :
Le premier paramètre est l'ID du commentaire, le huitième est l'ID du choix.
À la vérification, si la réponse de l'utilisateur est incorrecte, l'application affiche le commentaire d'un des choix sélectionnés ; les commentaires des choix justes sont prioritaires, le reste de la sélection est arbitraire (ex: si 1 choix juste et 1 choix faux sont cochés, le commentaire du choix juste sera affiché).
### ExerciceTAT
Le texte à trous existe maintenant en variante "sélection" (menu déroulant) et "libre" (champ texte), tous les deux des `new ExerciceTAT()`. La différence semble se remarquer avec des lignes de la forme
```js
exo.tabSelects[exo.tabSelects.length]='1';
```
qui définissent quels champs sont des sélecteurs (exemple: comparer `pg4487.html` et `pg1919.html`).
Autre changement, le format des réponses. Tous les libellés sont maintenant obfusqués :
Heureusement la fonction de décodage `decodeX()` est statique (clé fixe, ne dépend pas d'autres attributs de l'activité) : [source](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceTAT.js#L774)
Le 2e paramètre indique à quel champ appartient la réponse. Le troisième indique la correction, mais ce n'est plus simplement `"ng"` pour faux ou `nw` pour juste, mais une valeur numérique. La logique se passe dans la fonction `exo_ajouterReponse(...)` ([source](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceTAT.js#L75))
La réponse ajoutée est correcte si le `reste` vaut -1.
```
reste == -1
correction - 2*num - decalY - 1 == -1
correction - 2*num - decalY == 0
correction == 2*num + decalY
correction == 2*num + (nChamps + scoreTotal) % 2
```
On a donc besoin d'extraire en plus le nombre de champs et le `scoreTotal` pour déterminer si chaque réponse est vraie ou fausse.
\ No newline at end of file
Cette page décrit la structure de Macao-Legacy et l'emplacement des données de contenu.
*À plusieurs reprises, on a besoin de décrire un motif de nommage : dans ces cas, le caractère `#` correspond à un chiffre, et `_` à n'importe quel caractère alphanumérique. Quand ces caractères sont répétés, ils décrivent par défaut un champ de longueur variable (exemple: `###` désigne de 1 à 3 chiffres)*
---
**Modules** : Macao est composé de 3 modules (Macao 1, 2 et 3). Macao 1 et 2 partagent la même base de code `macao_12`, Macao 3 a été développé plus tard et réside dans `macao_3`.
Un module contient une ou plusieurs parties _(ex: "Reconnaître les syllabes")_, qui elles-mêmes peuvent contenir d'autres (sous-)parties. Côté code, une partie a la même représentation qu'un module, c'est un élément sans contenu propre, décrit seulement dans le manifeste [`imsmanifest.xml`](https://gitlab.tetras-libre.fr/macao/macao-legacy/-/blob/main/Basilisk/MACAO/macao_12/imsmanifest.xml)
- [x] Descendants dans l'arbre -\> éléments `<item>`
---
## Sous-parties
On appelle sous-parties les parties de dernier niveau, les "feuilles" de l'arborescence. Dans le panneau de gauche, ce sont les éléments non dépliables _(ex: "Reconnaître les syllabes en anglais oral")_. Une sous-partie contient plusieurs **activités**, dont la première est affichée quand on sélectionne la sous-partie. Une sous-partie est décrite dans un fichier `sco/MosEtp###`, qui déclare un objet `MosSCO` pour définir son contenu.
```js
oSco=newMosSCO("MosEtp129","> Reconnaître les syllabes en anglais oral","MACAO","MACAO 1 - S'entraîner à la reconnaissance","","macao_fusion_ss_barre","fr");
```
Peu d'infos utiles : nom du fichier, titre (déjà défini dans le `<title>`), titre du "stage" (constant), titre du module parent (déjà connu grâce au manifest), et quelques champs constants.\
Ensuite quelques lignes inutiles, puis on passe à la déclaration des pages.
```js
oSco.tabPages[oSco.tabPages.length]=newPageContenu("Repérer les syllabes orales","pg861","exercice","");
oSco.tabPages[oSco.tabPages.length]=newPageContenu("Repérer les syllabes écrites","pg60","exercice","");
Le plus important est l'ID de la page `"pg###"`, et éventuellement le type (`"exercice"` ou `"cours"`), le titre de la page étant déclaré aussi dans la page elle-même.
**Données à extraire :**
- Dans le manifest
- [x] ID -\> attribut `identifier`
- [x] Titre -\> élément `<title>`
- Dans le fichier `MosEtp###.html`
- [~] Titre -\>`<title>`
- [x] Liste des pages (titre, ID) -\> arguments de `new PageContenu()`
---
## Activités, ou pages
Les "unités de navigation". La section centrale de Macao affiche toujours 1 activité, dont le nom est indiqué en haut à droite _(ex: "Repérer les syllabes orales")_. Une activité peut être un cours (sans saisie interactive) ou un des 4 types d'exercices (`QC, QM, TAT, GD` dans `MosMtr/scripts/contenu/ClasseExercice___.js` + `ClasseCours.js`). Elle est décrite dans un fichier `contenu/pages/pg###.html`, qui déclare un objet `Cours` ou `Exercice___` pour définir son contenu.
**Données à extraire (communes à toutes les activités) :**
- [x] Type d'activité -\> premier appel de constructeur `new ___()`
-[x] [Commentaires](#commentaires) -\> éléments `<div id="divCmt___">` dans `<div id="zoneInvisible">`
- [ ] Dans les descriptions, commentaires, blocs HTML divers
**Exemple QCM** : `pg8412.html`, page _"Vérifier la place de l'accent primaire (3)"_ dans la sous-partie _"\> Utiliser les marques de l'accentuation"_
Il s'avère que les 9 exercices QCM sont tous dans la même sous-partie, et sont utilisés sémantiquement comme plusieurs QCU : \
Dans cet exemple, on a 3 mots ayant chacun 3 réponses possibles dont 1 bonne, mais l'exercice est implémenté comme un QCM de 9 choix possibles ; on peut tout à fait cocher les 3 choix pour "narrator". C'est un exemple de cas particulier étrange qui devra être corrigé manuellement.
</details>
**Données à extraire :**
- [x] Consigne -\>`<div id="STY_question">`
- [x] Choix de réponses
- [x] Correction -\> dans la fonction `entrerDonnees()`, `exo.tabStylesR[nr] = CODE_V` ou `CODE_F` pour chaque valeur de `nr`
- [x] Commentaires de succès et d'échec -\>`divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### ExerciceQM
_(Question Multiple?)_\
Comme ExerciceQC mais avec plusieurs questions, chacune ayant une seule bonne réponse.\
- [ ] Choix de réponses -\> tableau dans `<div id="STY_texteQM">`, chaque ligne (`<tr>`) est une question, chaque cellule de colonne (`<td>`) est une case à cocher. Son `id` indique aussi ses coordonnées (ex: `id="lienRepImg13"` = ligne 1 choix 3)
- [ ] Correction -\> dans la fonction `entrerDonnees()`, `exo.tabStylesR[nr] = '3'` indiquent le numéro du choix correct pour chaque numéro de ligne `nr`
- [x] Commentaires de succès et d'échec -\>`divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### ExerciceTAT
Un texte à trous, avec pour chaque "trou" une liste déroulante de choix de mots.\
**Quantité :** 12
<details>
<summary>Exemple</summary>
`pg20.html`, page _"Ecoutez et complétez (2)"_ dans la sous-partie _"\> Reconnaître les déterminants"_\
- [ ] Éléments à déplacer -\> éléments `<div id="exoGDd#">` (le `d` est pour _déplaçable_, et est suivi de son numéro/ID)
- [ ] Cibles de déplacement -\> éléments `<div id="exoGDc#">` (le `c` est pour _cible_, suivi aussi de son numéro/ID)
- [ ] Correction -\> liste de `new PaireGD(deplacable, cible, correct, decalageX, decalageY)` indiquent pour chaque déplaçable sa cible associée et si il est juste (`ng` = faux, `nw` = juste).
- [ ] Positions de tous les éléments -\> offsets CSS `absolute`, sûrement à refaire manuellement.
- [x] Commentaires de succès et d'échec -\>`divCmtSucces` et `divCmtSugg#` _(cf. commentaires d'activité)_
### Inutilisés
ExerciceCURS, ExerciceEXP, ExerciceSEQ
---
## Pages d'aide ou "docs"
Dans `contenu/pages/`, les fichiers `*.htm` et `pgd###.html` sont des pages d'aide. Au lieu d'être chargées dans la section centrale, elles peuvent être ouvertes dans une nouvelle fenêtre pop-up avec la fonction `SCO_ouvrirDoc()`, souvent appelée depuis un lien `<a>` dans les pages classiques.
```html
cliquez pour voir la définition d'un <ahref="javascript:parent.SCO_ouvrirDoc('pgd171','PAGE')">phonème</a>
```
Ces pages peuvent inclure des objets Flash comme les autres, mais pas d'exercice.
## Contenus des pages
### Commentaires
Certains exercices ont des commentaires, des blocs HTML structurés chargés dans une `<div id="zoneInvisible">`, qui sont déplacés dans la `<div id="STY_zoneCommentaire">` à droite en réponse à certaines actions.
- Commentaire de succès : `<div id="divCmtSucces">`
- Commentaire d'échec : `<div id="divSugg#">`, numérotés à partir de 1
- Autres commentaires : `<div id="divCmt#">`, numérotés à partir de 1, contiennent un petit texte d'aide.
:warning: Les commentaires **peuvent contenir de la mise en forme et des objets Flash** (peut-être même des images ?)
### Images
Les images intégrées dans le contenu d'une page sont reconnaissables par un `id="MosImg###`, à la différence de celles utilisées pour l'UI (boutons). Leur chemin est toujours dans `contenu/media/`.
Idem que Macao12 avec `imsmanifest.xml`, mais le nommage devient `seq######`
## Sous-parties
Idem que Macao12, mais le nommage devient `act######`. De même, le fichier `sco/MosEtp###.html` devient `sco/act######.html`.\
Des fichiers XML `sco/md_act######.xml` font leur apparition pour chaque sous-partie, mais contiennent des métadonnées pour SCORM qui ne nous intéressent pas.
À la fin du `imsmanifest.xml`, un tag `<resource ... identifier="rsrcact######" ...>` décrit les dépendances de la sous-partie, sous la forme d'une liste de fichiers : pages `pg###.html`, images, SWFs... Potentiellement utile, ou bien redondant si on les retrouve dans le contenu HTML des pages.
Même format pour le contenu (JavaScript) de la sous-partie, avec `new MosSCO(...)` et presque le même pour les lignes `new PageContenu()`, qui ont ici 6 paramètres string au lieu de 4, le dernier indiquant le type d'activité (`"COURS"`, `"QC"`, `"TAT"`, etc...).
Cependant, Macao 3 (ou très probablement MOS Chorus) semble avoir essayé d'obfusquer les définitions des réponses dans le code, peut-être pour éviter qu'un étudiant puisse ouvrir les *devtools* et déduire facilement les réponses correctes. C'est toujours possible en lisant le code (puisque l'appli fonctionne toujours sans serveur), mais complexifié par l'utilisation de techniques... exotiques.
Les sections suivantes sur chaque type d'exercice détaillent ces changements.
### ExerciceQC
L'initialisation des choix ne se base plus sur des indices, mais sur des ID.
- Les éléments HTML des choix (ex: `<div class="STY_reponseQC" id="lienrep627" ...>`) portent chacun un ID de la forme `repX` (la partie `lien` est ignorée et `X` est un nombre).
- À cet élément HTML correspond un objet JS déclaré comme
```js
varoItem=newItemReponse('rep678');
```
où le paramètre du constructeur est décodé par une fonction `decodeX`, définie [ici](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceQC.js#L567), qui remplace les caractères `0 1 2 3 7 8 9` entre eux et conserve les autres. Le résultat est le vrai ID du choix correspondant.
- Cet objet JS est initialisé avec `oItem.init("42", "", "", "");`, où le premier paramètre indique la justesse du choix. Si le dernier caractère est `1`, c'est un choix juste, sinon faux.
- Chaque choix peut être associé à un commentaire de suggestion, de la façon suivante :
Le premier paramètre est l'ID du commentaire, le huitième est l'ID du choix.
À la vérification, si la réponse de l'utilisateur est incorrecte, l'application affiche le commentaire d'un des choix sélectionnés ; les commentaires des choix justes sont prioritaires, le reste de la sélection est arbitraire (ex: si 1 choix juste et 1 choix faux sont cochés, le commentaire du choix juste sera affiché).
### ExerciceQM
Question Multiple, plusieurs questions (une par ligne) avec les choix en titre de colonne. Il n'y a que 3 ExerciceQM dans Macao3 donc on peut aussi les extraire manuellement.
Idem que pour QC, les indices sont remplacés par des ID obfusqués.
-`oItem = new ItemReponse('rep###')` déclare une "question" qui correspond à une ligne du tableau `<tr id="trReprep###">`
:warning: L'ID est à décoder avec la fonction [`decodeX()`](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceQM.js#L452)(ex:`rep991` devient `rep228`)
-`oItem.init("rep###")` déclare la réponse correcte, qui correspond à une colonne `<td id="col###">`
- :warning: L'ID est à décoder avec une *autre* fonction : [`decodeY()`](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceQM.js#L485)
### ExerciceTAT
Le texte à trous existe maintenant en variante "sélection" (menu déroulant) et "libre" (champ texte), tous les deux des `new ExerciceTAT()`. La différence semble se remarquer avec des lignes de la forme
```js
exo.tabSelects[exo.tabSelects.length]='1';
```
qui définissent quels champs sont des sélecteurs (exemple: comparer `pg4487.html` et `pg1919.html`).
Autre changement, le format des réponses. Tous les libellés sont maintenant obfusqués :
Heureusement la fonction de décodage `decodeX()` est statique (clé fixe, ne dépend pas d'autres attributs de l'activité) : [source](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceTAT.js#L774)
Le 2e paramètre indique à quel champ appartient la réponse. Le troisième indique la correction, mais ce n'est plus simplement `"ng"` pour faux ou `nw` pour juste, mais une valeur numérique. La logique se passe dans la fonction `exo_ajouterReponse(...)` ([source](https://gitlab.tetras-libre.fr/macao/macao-legacy/blob/main/Basilisk/MACAO/macao_3/MosMtr/scripts/contenu/ClasseExerciceTAT.js#L75))