diff --git a/mcli b/mcli
index ea8a5c24d0ed81d1cc07e83901b1d302363061cf..c9d2fde2822729492a86639f225a96fdf2690fd3 100755
--- a/mcli
+++ b/mcli
@@ -55,12 +55,18 @@ setup
     Initialize Python environment required by extractors
 setup-debug
     (Re)create .env file used by the Python debugger launch config
-extract-rdf
-    Run the extractor to generate RDF from text sources
-extract-mp3 [-y|--yes-overwrite]
-    Extract audio streams from all Flash SWF files
+extract
+    Run the extract stage, to generate RDF from text sources
+transform
+    Run the transform stage, to complete and clean-up the RDF data
+export
+    Run the export stage, to generate Macao-Hugo content pages
 convert
     Run the full conversion process (extract -> transform -> export)
+test
+    Run simple tests on the extracted RDF data
+extract-mp3 [-y|--yes-overwrite]
+    Extract audio streams from all Flash SWF files
 help
     Print this help and exit
 EOF
@@ -264,6 +270,10 @@ export)
     activate_venv
     python "$SCRIPTS_DIR/src/export.py"
     ;;
+test)
+    activate_venv
+    python "$SCRIPTS_DIR/src/test.py"
+    ;;
 extract-mp3)
     for audio_file in "$SOURCES_DIR/contenu/media/"*.swf; do
         "$SCRIPTS_DIR/extract_mp3.sh" "$@" --output-dir "$RESULTS_DIR/audio" "$audio_file"
diff --git a/tetras_extraction/result/full/macao_content.ttl b/tetras_extraction/result/full/macao_content.ttl
index 068c942a4d30a6a6a5cb4a608dd0b4e96e7bea5b..632493145a8f41523fe28c7350a36120e308d728 100644
--- a/tetras_extraction/result/full/macao_content.ttl
+++ b/tetras_extraction/result/full/macao_content.ttl
@@ -884,23 +884,6 @@
     :index 2 ;
     rdfs:subClassOf :pg186 .
 
-:pg186_rep627 a :Reponse ;
-    :__protege_display_name "pg186_rep627 | F" ;
-    :commentaireSugg """<div id="divSugg1" onclick="SPE_clicDansBulle(event,'divSugg1')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Vous vous trompez.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de
-            repérer l'événement dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
-    """ ;
-    :correct false ;
-    :html "" ;
-    :id "rep627" ;
-    :index -1 ;
-    rdfs:subClassOf :pg186 .
-
 :pg186_rep957 a :Reponse ;
     :__protege_display_name "pg186_rep957 | V" ;
     :correct true ;
@@ -3455,24 +3438,6 @@
     :index 2 ;
     rdfs:subClassOf :pg4031 .
 
-:pg4031_rep36 a :Reponse ;
-    :__protege_display_name "pg4031_rep36 | F" ;
-    :commentaireSugg """<div id="divSugg5" onclick="SPE_clicDansBulle(event,'divSugg5')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Vous n'avez pas repéré l'élément principal.<br><br>C'est le mot <i><b>look</b></i> qui montre bien que
-            l'énonciateur s'intéresse aux conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans
-            la salle de bains.</p></div>
-""" ;
-    :correct false ;
-    :html "" ;
-    :id "rep36" ;
-    :index -1 ;
-    rdfs:subClassOf :pg4031 .
-
 :pg4031_rep49 a :Reponse ;
     :__protege_display_name "pg4031_rep49 | V" ;
     :correct true ;
@@ -12072,6 +12037,57 @@
     :titre "Repérer des indices pertinents" ;
     rdfs:subClassOf :seq68058 .
 
+:pg186 a :Activite,
+        :ExerciceQC_QCM,
+        owl:NamedIndividual ;
+    rdfs:label "Quatrième tâche" ;
+    :__protege_display_name "03 | pg186 | Quatrième tâche" ;
+    :aReponse :pg186_rep150,
+        :pg186_rep211,
+        :pg186_rep223,
+        :pg186_rep550,
+        :pg186_rep957 ;
+    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Bien.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de repérer l'événement
+            dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
+    """ ;
+    :commentaireSugg """<div id="divSugg1" onclick="SPE_clicDansBulle(event,'divSugg1')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Vous vous trompez.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de
+            repérer l'événement dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
+    """ ;
+    :description """<div id="STY_question" class="STY_question" style="  "><br>Ecoutez l'énoncé suivant. <br><b>
+        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV9069', 'ecran11.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV43', 'mot11_12.swf', '205', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+        </table>
+    </b><br>Désignez l'indice pertinent pour identifier la forme verbale et sélectionnez la forme verbale employée :
+    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
+    """ ;
+    :id "pg186" ;
+    :index 3 ;
+    :titre "Quatrième tâche" ;
+    rdfs:subClassOf :act957420 .
+
 :pg3531 a :Activite,
         :ExerciceQC_QCM,
         owl:NamedIndividual ;
@@ -12125,6 +12141,69 @@
     :titre "Deuxième tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
+:pg4031 a :Activite,
+        :ExerciceQC_QCU,
+        owl:NamedIndividual ;
+    rdfs:label "Première tâche" ;
+    :__protege_display_name "00 | pg4031 | Première tâche" ;
+    :aReponse :pg4031_rep150,
+        :pg4031_rep211,
+        :pg4031_rep49,
+        :pg4031_rep627,
+        :pg4031_rep842 ;
+    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>C'est juste.<br><br>Vous avez repéré l'élément principal qui montre bien que l'énonciateur s'intéresse aux
+            conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans la salle de bains.<br></p>
+    </div>
+    """ ;
+    :commentaireSugg """<div id="divSugg5" onclick="SPE_clicDansBulle(event,'divSugg5')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Vous n'avez pas repéré l'élément principal.<br><br>C'est le mot <i><b>look</b></i> qui montre bien que
+            l'énonciateur s'intéresse aux conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans
+            la salle de bains.</p></div>
+""" ;
+    :description """<div id="STY_question" class="STY_question" style="  "><br>Le bloc mis en valeur correspond à un <a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')"><i>present perfect</i>.</a>
+        Ecoutez ce court dialogue en entier puis par blocs. <br>
+        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV8320', 'ecran81.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV92', 'mot8_13.swf', '270', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV5460', 'ecran82.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV91', 'mot8_22.swf', '330', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+        </table>
+        <br>Désignez le principal indice permettant de justifier la présence d'un <i><a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')">present
+            perfect</a></i>.
+    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
+    """ ;
+    :id "pg4031" ;
+    :index 0 ;
+    :titre "Première tâche" ;
+    rdfs:subClassOf :act957420 .
+
 :MosEtp369 a :SousPartie,
         owl:NamedIndividual ;
     rdfs:label "> Reconnaître les marques de l'accentuation" ;
@@ -12240,49 +12319,6 @@
     :titre "Quatrième tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
-:pg186 a :Activite,
-        :ExerciceQC_QCM,
-        owl:NamedIndividual ;
-    rdfs:label "Quatrième tâche" ;
-    :__protege_display_name "03 | pg186 | Quatrième tâche" ;
-    :aReponse :pg186_rep150,
-        :pg186_rep211,
-        :pg186_rep223,
-        :pg186_rep550,
-        :pg186_rep627,
-        :pg186_rep957 ;
-    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Bien.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de repérer l'événement
-            dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
-    """ ;
-    :description """<div id="STY_question" class="STY_question" style="  "><br>Ecoutez l'énoncé suivant. <br><b>
-        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV9069', 'ecran11.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV43', 'mot11_12.swf', '205', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-        </table>
-    </b><br>Désignez l'indice pertinent pour identifier la forme verbale et sélectionnez la forme verbale employée :
-    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
-    """ ;
-    :id "pg186" ;
-    :index 3 ;
-    :titre "Quatrième tâche" ;
-    rdfs:subClassOf :act957420 .
-
 :pg1894 a :Activite,
         :ExerciceQC_QCM,
         owl:NamedIndividual ;
@@ -12334,60 +12370,6 @@
     :titre "Première tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
-:pg4031 a :Activite,
-        :ExerciceQC_QCU,
-        owl:NamedIndividual ;
-    rdfs:label "Première tâche" ;
-    :__protege_display_name "00 | pg4031 | Première tâche" ;
-    :aReponse :pg4031_rep150,
-        :pg4031_rep211,
-        :pg4031_rep36,
-        :pg4031_rep49,
-        :pg4031_rep627,
-        :pg4031_rep842 ;
-    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>C'est juste.<br><br>Vous avez repéré l'élément principal qui montre bien que l'énonciateur s'intéresse aux
-            conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans la salle de bains.<br></p>
-    </div>
-    """ ;
-    :description """<div id="STY_question" class="STY_question" style="  "><br>Le bloc mis en valeur correspond à un <a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')"><i>present perfect</i>.</a>
-        Ecoutez ce court dialogue en entier puis par blocs. <br>
-        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV8320', 'ecran81.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV92', 'mot8_13.swf', '270', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV5460', 'ecran82.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV91', 'mot8_22.swf', '330', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-        </table>
-        <br>Désignez le principal indice permettant de justifier la présence d'un <i><a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')">present
-            perfect</a></i>.
-    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
-    """ ;
-    :id "pg4031" ;
-    :index 0 ;
-    :titre "Première tâche" ;
-    rdfs:subClassOf :act957420 .
-
 :pg9988 a :Activite,
         :ExerciceQC_QCU,
         owl:NamedIndividual ;
diff --git a/tetras_extraction/result/full/macao_full.ttl b/tetras_extraction/result/full/macao_full.ttl
index 05a23488fd67089ce8edd0105c41f2c348907ac8..d212b8cfaae653a7d958d11bc25cce2efcff4818 100644
--- a/tetras_extraction/result/full/macao_full.ttl
+++ b/tetras_extraction/result/full/macao_full.ttl
@@ -586,25 +586,6 @@
     :index 2 ;
     rdfs:subClassOf :pg186 .
 
-:pg186_rep627 a :MacaoContenu,
-        :MacaoObject,
-        :Reponse ;
-    :__protege_display_name "pg186_rep627 | F" ;
-    :commentaireSugg """<div id="divSugg1" onclick="SPE_clicDansBulle(event,'divSugg1')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Vous vous trompez.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de
-            repérer l'événement dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
-    """ ;
-    :correct false ;
-    :html "" ;
-    :id "rep627" ;
-    :index -1 ;
-    rdfs:subClassOf :pg186 .
-
 :pg186_rep957 a :MacaoContenu,
         :MacaoObject,
         :Reponse ;
@@ -1449,26 +1430,6 @@
     :index 2 ;
     rdfs:subClassOf :pg4031 .
 
-:pg4031_rep36 a :MacaoContenu,
-        :MacaoObject,
-        :Reponse ;
-    :__protege_display_name "pg4031_rep36 | F" ;
-    :commentaireSugg """<div id="divSugg5" onclick="SPE_clicDansBulle(event,'divSugg5')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Vous n'avez pas repéré l'élément principal.<br><br>C'est le mot <i><b>look</b></i> qui montre bien que
-            l'énonciateur s'intéresse aux conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans
-            la salle de bains.</p></div>
-""" ;
-    :correct false ;
-    :html "" ;
-    :id "rep36" ;
-    :index -1 ;
-    rdfs:subClassOf :pg4031 .
-
 :pg4031_rep49 a :MacaoContenu,
         :MacaoObject,
         :Reponse ;
@@ -13461,6 +13422,61 @@
     :titre "Se servir d'indices grammaticaux" ;
     rdfs:subClassOf :seq906956 .
 
+:pg186 a :Activite,
+        :Exercice,
+        :ExerciceQC,
+        :ExerciceQC_QCM,
+        :MacaoContenu,
+        :MacaoObject,
+        owl:NamedIndividual ;
+    rdfs:label "Quatrième tâche" ;
+    :__protege_display_name "03 | pg186 | Quatrième tâche" ;
+    :aReponse :pg186_rep150,
+        :pg186_rep211,
+        :pg186_rep223,
+        :pg186_rep550,
+        :pg186_rep957 ;
+    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Bien.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de repérer l'événement
+            dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
+    """ ;
+    :commentaireSugg """<div id="divSugg1" onclick="SPE_clicDansBulle(event,'divSugg1')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Vous vous trompez.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de
+            repérer l'événement dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
+    """ ;
+    :description """<div id="STY_question" class="STY_question" style="  "><br>Ecoutez l'énoncé suivant. <br><b>
+        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV9069', 'ecran11.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV43', 'mot11_12.swf', '205', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+        </table>
+    </b><br>Désignez l'indice pertinent pour identifier la forme verbale et sélectionnez la forme verbale employée :
+    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
+    """ ;
+    :id "pg186" ;
+    :index 3 ;
+    :titre "Quatrième tâche" ;
+    rdfs:subClassOf :act957420 .
+
 :pg3531 a :Activite,
         :Exercice,
         :ExerciceQC,
@@ -13518,6 +13534,73 @@
     :titre "Deuxième tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
+:pg4031 a :Activite,
+        :Exercice,
+        :ExerciceQC,
+        :ExerciceQC_QCU,
+        :MacaoContenu,
+        :MacaoObject,
+        owl:NamedIndividual ;
+    rdfs:label "Première tâche" ;
+    :__protege_display_name "00 | pg4031 | Première tâche" ;
+    :aReponse :pg4031_rep150,
+        :pg4031_rep211,
+        :pg4031_rep49,
+        :pg4031_rep627,
+        :pg4031_rep842 ;
+    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>C'est juste.<br><br>Vous avez repéré l'élément principal qui montre bien que l'énonciateur s'intéresse aux
+            conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans la salle de bains.<br></p>
+    </div>
+    """ ;
+    :commentaireSugg """<div id="divSugg5" onclick="SPE_clicDansBulle(event,'divSugg5')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Vous n'avez pas repéré l'élément principal.<br><br>C'est le mot <i><b>look</b></i> qui montre bien que
+            l'énonciateur s'intéresse aux conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans
+            la salle de bains.</p></div>
+""" ;
+    :description """<div id="STY_question" class="STY_question" style="  "><br>Le bloc mis en valeur correspond à un <a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')"><i>present perfect</i>.</a>
+        Ecoutez ce court dialogue en entier puis par blocs. <br>
+        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV8320', 'ecran81.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV92', 'mot8_13.swf', '270', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV5460', 'ecran82.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV91', 'mot8_22.swf', '330', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+        </table>
+        <br>Désignez le principal indice permettant de justifier la présence d'un <i><a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')">present
+            perfect</a></i>.
+    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
+    """ ;
+    :id "pg4031" ;
+    :index 0 ;
+    :titre "Première tâche" ;
+    rdfs:subClassOf :act957420 .
+
 :MosEtp558 a :MacaoContenu,
         :MacaoObject,
         :Module,
@@ -13621,53 +13704,6 @@
     :titre "Quatrième tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
-:pg186 a :Activite,
-        :Exercice,
-        :ExerciceQC,
-        :ExerciceQC_QCM,
-        :MacaoContenu,
-        :MacaoObject,
-        owl:NamedIndividual ;
-    rdfs:label "Quatrième tâche" ;
-    :__protege_display_name "03 | pg186 | Quatrième tâche" ;
-    :aReponse :pg186_rep150,
-        :pg186_rep211,
-        :pg186_rep223,
-        :pg186_rep550,
-        :pg186_rep627,
-        :pg186_rep957 ;
-    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Bien.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de repérer l'événement
-            dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
-    """ ;
-    :description """<div id="STY_question" class="STY_question" style="  "><br>Ecoutez l'énoncé suivant. <br><b>
-        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV9069', 'ecran11.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV43', 'mot11_12.swf', '205', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-        </table>
-    </b><br>Désignez l'indice pertinent pour identifier la forme verbale et sélectionnez la forme verbale employée :
-    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
-    """ ;
-    :id "pg186" ;
-    :index 3 ;
-    :titre "Quatrième tâche" ;
-    rdfs:subClassOf :act957420 .
-
 :pg1894 a :Activite,
         :Exercice,
         :ExerciceQC,
@@ -13723,64 +13759,6 @@
     :titre "Première tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
-:pg4031 a :Activite,
-        :Exercice,
-        :ExerciceQC,
-        :ExerciceQC_QCU,
-        :MacaoContenu,
-        :MacaoObject,
-        owl:NamedIndividual ;
-    rdfs:label "Première tâche" ;
-    :__protege_display_name "00 | pg4031 | Première tâche" ;
-    :aReponse :pg4031_rep150,
-        :pg4031_rep211,
-        :pg4031_rep36,
-        :pg4031_rep49,
-        :pg4031_rep627,
-        :pg4031_rep842 ;
-    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>C'est juste.<br><br>Vous avez repéré l'élément principal qui montre bien que l'énonciateur s'intéresse aux
-            conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans la salle de bains.<br></p>
-    </div>
-    """ ;
-    :description """<div id="STY_question" class="STY_question" style="  "><br>Le bloc mis en valeur correspond à un <a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')"><i>present perfect</i>.</a>
-        Ecoutez ce court dialogue en entier puis par blocs. <br>
-        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV8320', 'ecran81.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV92', 'mot8_13.swf', '270', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV5460', 'ecran82.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV91', 'mot8_22.swf', '330', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-        </table>
-        <br>Désignez le principal indice permettant de justifier la présence d'un <i><a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')">present
-            perfect</a></i>.
-    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
-    """ ;
-    :id "pg4031" ;
-    :index 0 ;
-    :titre "Première tâche" ;
-    rdfs:subClassOf :act957420 .
-
 :pg9988 a :Activite,
         :Exercice,
         :ExerciceQC,
diff --git a/tetras_extraction/result/macao_3/macao_content.ttl b/tetras_extraction/result/macao_3/macao_content.ttl
index 917ff677e264f87ed053b0ddd4fe9d916e76249c..3a6f838a441328b4086d24847a2e9264bce742d6 100644
--- a/tetras_extraction/result/macao_3/macao_content.ttl
+++ b/tetras_extraction/result/macao_3/macao_content.ttl
@@ -562,23 +562,6 @@
     :index 2 ;
     rdfs:subClassOf :pg186 .
 
-:pg186_rep627 a :Reponse ;
-    :__protege_display_name "pg186_rep627 | F" ;
-    :commentaireSugg """<div id="divSugg1" onclick="SPE_clicDansBulle(event,'divSugg1')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Vous vous trompez.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de
-            repérer l'événement dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
-    """ ;
-    :correct false ;
-    :html "" ;
-    :id "rep627" ;
-    :index -1 ;
-    rdfs:subClassOf :pg186 .
-
 :pg186_rep957 a :Reponse ;
     :__protege_display_name "pg186_rep957 | V" ;
     :correct true ;
@@ -2067,24 +2050,6 @@
     :index 2 ;
     rdfs:subClassOf :pg4031 .
 
-:pg4031_rep36 a :Reponse ;
-    :__protege_display_name "pg4031_rep36 | F" ;
-    :commentaireSugg """<div id="divSugg5" onclick="SPE_clicDansBulle(event,'divSugg5')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Vous n'avez pas repéré l'élément principal.<br><br>C'est le mot <i><b>look</b></i> qui montre bien que
-            l'énonciateur s'intéresse aux conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans
-            la salle de bains.</p></div>
-""" ;
-    :correct false ;
-    :html "" ;
-    :id "rep36" ;
-    :index -1 ;
-    rdfs:subClassOf :pg4031 .
-
 :pg4031_rep49 a :Reponse ;
     :__protege_display_name "pg4031_rep49 | V" ;
     :correct true ;
@@ -5993,6 +5958,57 @@
     :titre "Repérer des indices pertinents" ;
     rdfs:subClassOf :seq68058 .
 
+:pg186 a :Activite,
+        :ExerciceQC_QCM,
+        owl:NamedIndividual ;
+    rdfs:label "Quatrième tâche" ;
+    :__protege_display_name "03 | pg186 | Quatrième tâche" ;
+    :aReponse :pg186_rep150,
+        :pg186_rep211,
+        :pg186_rep223,
+        :pg186_rep550,
+        :pg186_rep957 ;
+    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Bien.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de repérer l'événement
+            dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
+    """ ;
+    :commentaireSugg """<div id="divSugg1" onclick="SPE_clicDansBulle(event,'divSugg1')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Vous vous trompez.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de
+            repérer l'événement dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
+    """ ;
+    :description """<div id="STY_question" class="STY_question" style="  "><br>Ecoutez l'énoncé suivant. <br><b>
+        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV9069', 'ecran11.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV43', 'mot11_12.swf', '205', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+        </table>
+    </b><br>Désignez l'indice pertinent pour identifier la forme verbale et sélectionnez la forme verbale employée :
+    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
+    """ ;
+    :id "pg186" ;
+    :index 3 ;
+    :titre "Quatrième tâche" ;
+    rdfs:subClassOf :act957420 .
+
 :pg3531 a :Activite,
         :ExerciceQC_QCM,
         owl:NamedIndividual ;
@@ -6046,6 +6062,69 @@
     :titre "Deuxième tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
+:pg4031 a :Activite,
+        :ExerciceQC_QCU,
+        owl:NamedIndividual ;
+    rdfs:label "Première tâche" ;
+    :__protege_display_name "00 | pg4031 | Première tâche" ;
+    :aReponse :pg4031_rep150,
+        :pg4031_rep211,
+        :pg4031_rep49,
+        :pg4031_rep627,
+        :pg4031_rep842 ;
+    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>C'est juste.<br><br>Vous avez repéré l'élément principal qui montre bien que l'énonciateur s'intéresse aux
+            conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans la salle de bains.<br></p>
+    </div>
+    """ ;
+    :commentaireSugg """<div id="divSugg5" onclick="SPE_clicDansBulle(event,'divSugg5')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Vous n'avez pas repéré l'élément principal.<br><br>C'est le mot <i><b>look</b></i> qui montre bien que
+            l'énonciateur s'intéresse aux conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans
+            la salle de bains.</p></div>
+""" ;
+    :description """<div id="STY_question" class="STY_question" style="  "><br>Le bloc mis en valeur correspond à un <a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')"><i>present perfect</i>.</a>
+        Ecoutez ce court dialogue en entier puis par blocs. <br>
+        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV8320', 'ecran81.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV92', 'mot8_13.swf', '270', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV5460', 'ecran82.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV91', 'mot8_22.swf', '330', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+        </table>
+        <br>Désignez le principal indice permettant de justifier la présence d'un <i><a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')">present
+            perfect</a></i>.
+    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
+    """ ;
+    :id "pg4031" ;
+    :index 0 ;
+    :titre "Première tâche" ;
+    rdfs:subClassOf :act957420 .
+
 :act704962 a :SousPartie,
         owl:NamedIndividual ;
     rdfs:label "Utiliser différents types d'indices" ;
@@ -6146,49 +6225,6 @@
     :titre "Quatrième tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
-:pg186 a :Activite,
-        :ExerciceQC_QCM,
-        owl:NamedIndividual ;
-    rdfs:label "Quatrième tâche" ;
-    :__protege_display_name "03 | pg186 | Quatrième tâche" ;
-    :aReponse :pg186_rep150,
-        :pg186_rep211,
-        :pg186_rep223,
-        :pg186_rep550,
-        :pg186_rep627,
-        :pg186_rep957 ;
-    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Bien.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de repérer l'événement
-            dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
-    """ ;
-    :description """<div id="STY_question" class="STY_question" style="  "><br>Ecoutez l'énoncé suivant. <br><b>
-        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV9069', 'ecran11.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV43', 'mot11_12.swf', '205', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-        </table>
-    </b><br>Désignez l'indice pertinent pour identifier la forme verbale et sélectionnez la forme verbale employée :
-    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
-    """ ;
-    :id "pg186" ;
-    :index 3 ;
-    :titre "Quatrième tâche" ;
-    rdfs:subClassOf :act957420 .
-
 :pg1894 a :Activite,
         :ExerciceQC_QCM,
         owl:NamedIndividual ;
@@ -6240,60 +6276,6 @@
     :titre "Première tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
-:pg4031 a :Activite,
-        :ExerciceQC_QCU,
-        owl:NamedIndividual ;
-    rdfs:label "Première tâche" ;
-    :__protege_display_name "00 | pg4031 | Première tâche" ;
-    :aReponse :pg4031_rep150,
-        :pg4031_rep211,
-        :pg4031_rep36,
-        :pg4031_rep49,
-        :pg4031_rep627,
-        :pg4031_rep842 ;
-    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>C'est juste.<br><br>Vous avez repéré l'élément principal qui montre bien que l'énonciateur s'intéresse aux
-            conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans la salle de bains.<br></p>
-    </div>
-    """ ;
-    :description """<div id="STY_question" class="STY_question" style="  "><br>Le bloc mis en valeur correspond à un <a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')"><i>present perfect</i>.</a>
-        Ecoutez ce court dialogue en entier puis par blocs. <br>
-        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV8320', 'ecran81.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV92', 'mot8_13.swf', '270', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV5460', 'ecran82.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV91', 'mot8_22.swf', '330', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-        </table>
-        <br>Désignez le principal indice permettant de justifier la présence d'un <i><a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')">present
-            perfect</a></i>.
-    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
-    """ ;
-    :id "pg4031" ;
-    :index 0 ;
-    :titre "Première tâche" ;
-    rdfs:subClassOf :act957420 .
-
 :pg9988 a :Activite,
         :ExerciceQC_QCU,
         owl:NamedIndividual ;
diff --git a/tetras_extraction/result/macao_3/macao_full.ttl b/tetras_extraction/result/macao_3/macao_full.ttl
index 324d43e25cb0833f161cb319e618e0c073ad4274..8c22c237004c80aa0e3750513dd4fc7e0ce99d44 100644
--- a/tetras_extraction/result/macao_3/macao_full.ttl
+++ b/tetras_extraction/result/macao_3/macao_full.ttl
@@ -410,25 +410,6 @@
     :index 2 ;
     rdfs:subClassOf :pg186 .
 
-:pg186_rep627 a :MacaoContenu,
-        :MacaoObject,
-        :Reponse ;
-    :__protege_display_name "pg186_rep627 | F" ;
-    :commentaireSugg """<div id="divSugg1" onclick="SPE_clicDansBulle(event,'divSugg1')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Vous vous trompez.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de
-            repérer l'événement dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
-    """ ;
-    :correct false ;
-    :html "" ;
-    :id "rep627" ;
-    :index -1 ;
-    rdfs:subClassOf :pg186 .
-
 :pg186_rep957 a :MacaoContenu,
         :MacaoObject,
         :Reponse ;
@@ -820,26 +801,6 @@
     :index 2 ;
     rdfs:subClassOf :pg4031 .
 
-:pg4031_rep36 a :MacaoContenu,
-        :MacaoObject,
-        :Reponse ;
-    :__protege_display_name "pg4031_rep36 | F" ;
-    :commentaireSugg """<div id="divSugg5" onclick="SPE_clicDansBulle(event,'divSugg5')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Vous n'avez pas repéré l'élément principal.<br><br>C'est le mot <i><b>look</b></i> qui montre bien que
-            l'énonciateur s'intéresse aux conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans
-            la salle de bains.</p></div>
-""" ;
-    :correct false ;
-    :html "" ;
-    :id "rep36" ;
-    :index -1 ;
-    rdfs:subClassOf :pg4031 .
-
 :pg4031_rep49 a :MacaoContenu,
         :MacaoObject,
         :Reponse ;
@@ -6621,6 +6582,61 @@
     :titre "Se servir d'indices grammaticaux" ;
     rdfs:subClassOf :seq906956 .
 
+:pg186 a :Activite,
+        :Exercice,
+        :ExerciceQC,
+        :ExerciceQC_QCM,
+        :MacaoContenu,
+        :MacaoObject,
+        owl:NamedIndividual ;
+    rdfs:label "Quatrième tâche" ;
+    :__protege_display_name "03 | pg186 | Quatrième tâche" ;
+    :aReponse :pg186_rep150,
+        :pg186_rep211,
+        :pg186_rep223,
+        :pg186_rep550,
+        :pg186_rep957 ;
+    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Bien.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de repérer l'événement
+            dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
+    """ ;
+    :commentaireSugg """<div id="divSugg1" onclick="SPE_clicDansBulle(event,'divSugg1')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Vous vous trompez.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de
+            repérer l'événement dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
+    """ ;
+    :description """<div id="STY_question" class="STY_question" style="  "><br>Ecoutez l'énoncé suivant. <br><b>
+        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV9069', 'ecran11.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV43', 'mot11_12.swf', '205', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+        </table>
+    </b><br>Désignez l'indice pertinent pour identifier la forme verbale et sélectionnez la forme verbale employée :
+    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
+    """ ;
+    :id "pg186" ;
+    :index 3 ;
+    :titre "Quatrième tâche" ;
+    rdfs:subClassOf :act957420 .
+
 :pg3531 a :Activite,
         :Exercice,
         :ExerciceQC,
@@ -6678,6 +6694,73 @@
     :titre "Deuxième tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
+:pg4031 a :Activite,
+        :Exercice,
+        :ExerciceQC,
+        :ExerciceQC_QCU,
+        :MacaoContenu,
+        :MacaoObject,
+        owl:NamedIndividual ;
+    rdfs:label "Première tâche" ;
+    :__protege_display_name "00 | pg4031 | Première tâche" ;
+    :aReponse :pg4031_rep150,
+        :pg4031_rep211,
+        :pg4031_rep49,
+        :pg4031_rep627,
+        :pg4031_rep842 ;
+    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>C'est juste.<br><br>Vous avez repéré l'élément principal qui montre bien que l'énonciateur s'intéresse aux
+            conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans la salle de bains.<br></p>
+    </div>
+    """ ;
+    :commentaireSugg """<div id="divSugg5" onclick="SPE_clicDansBulle(event,'divSugg5')"><p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p> </p>
+        <p>Vous n'avez pas repéré l'élément principal.<br><br>C'est le mot <i><b>look</b></i> qui montre bien que
+            l'énonciateur s'intéresse aux conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans
+            la salle de bains.</p></div>
+""" ;
+    :description """<div id="STY_question" class="STY_question" style="  "><br>Le bloc mis en valeur correspond à un <a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')"><i>present perfect</i>.</a>
+        Ecoutez ce court dialogue en entier puis par blocs. <br>
+        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV8320', 'ecran81.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV92', 'mot8_13.swf', '270', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+            <tr>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV5460', 'ecran82.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
+                </td>
+                <td style="BACKGROUND: #b5f0c7" valign="middle">
+                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV91', 'mot8_22.swf', '330', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
+                </td>
+            </tr>
+        </table>
+        <br>Désignez le principal indice permettant de justifier la présence d'un <i><a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')">present
+            perfect</a></i>.
+    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
+    """ ;
+    :id "pg4031" ;
+    :index 0 ;
+    :titre "Première tâche" ;
+    rdfs:subClassOf :act957420 .
+
 :act89909 a :MacaoContenu,
         :MacaoObject,
         :Module,
@@ -6759,53 +6842,6 @@
     :titre "Quatrième tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
-:pg186 a :Activite,
-        :Exercice,
-        :ExerciceQC,
-        :ExerciceQC_QCM,
-        :MacaoContenu,
-        :MacaoObject,
-        owl:NamedIndividual ;
-    rdfs:label "Quatrième tâche" ;
-    :__protege_display_name "03 | pg186 | Quatrième tâche" ;
-    :aReponse :pg186_rep150,
-        :pg186_rep211,
-        :pg186_rep223,
-        :pg186_rep550,
-        :pg186_rep627,
-        :pg186_rep957 ;
-    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>Bien.<br><br>L'indice pertinent est <i><b>last year</b></i>, il permet à l'énonciateur de repérer l'événement
-            dans le passé, d'où la forme verbale <i><b>he studied</b></i>.</p></div>
-    """ ;
-    :description """<div id="STY_question" class="STY_question" style="  "><br>Ecoutez l'énoncé suivant. <br><b>
-        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV9069', 'ecran11.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV43', 'mot11_12.swf', '205', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-        </table>
-    </b><br>Désignez l'indice pertinent pour identifier la forme verbale et sélectionnez la forme verbale employée :
-    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
-    """ ;
-    :id "pg186" ;
-    :index 3 ;
-    :titre "Quatrième tâche" ;
-    rdfs:subClassOf :act957420 .
-
 :pg1894 a :Activite,
         :Exercice,
         :ExerciceQC,
@@ -6861,64 +6897,6 @@
     :titre "Première tâche (2)" ;
     rdfs:subClassOf :act838137 .
 
-:pg4031 a :Activite,
-        :Exercice,
-        :ExerciceQC,
-        :ExerciceQC_QCU,
-        :MacaoContenu,
-        :MacaoObject,
-        owl:NamedIndividual ;
-    rdfs:label "Première tâche" ;
-    :__protege_display_name "00 | pg4031 | Première tâche" ;
-    :aReponse :pg4031_rep150,
-        :pg4031_rep211,
-        :pg4031_rep36,
-        :pg4031_rep49,
-        :pg4031_rep627,
-        :pg4031_rep842 ;
-    :commentaireSucces """<div id="divCmtSucces" onclick="SPE_clicDansBulle(event,'divCmtSucces')"><p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p> </p>
-        <p>C'est juste.<br><br>Vous avez repéré l'élément principal qui montre bien que l'énonciateur s'intéresse aux
-            conséquences de l'événement <b>HE + SPLASH</b> : il y a de l'eau partout dans la salle de bains.<br></p>
-    </div>
-    """ ;
-    :description """<div id="STY_question" class="STY_question" style="  "><br>Le bloc mis en valeur correspond à un <a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')"><i>present perfect</i>.</a>
-        Ecoutez ce court dialogue en entier puis par blocs. <br>
-        <table width="70%" bgcolor="#00c0c0" cellpadding="3" cellspacing="0" valign="top" border="0">
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" width="40%" valign="middle"><img align="center" border="0" src="../media/ecouteur_macao.png" id="MosImg32"></td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle"></td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV8320', 'ecran81.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV92', 'mot8_13.swf', '270', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-            <tr>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV5460', 'ecran82.swf', '30', '25', 'false', 'Flash', '', '', 'quality:high;wmode:transparent', '', ''));</script>
-                </td>
-                <td style="BACKGROUND: #b5f0c7" valign="middle">
-                    <script type="text/javascript">ajDocW(PF_clipAV('clipAV91', 'mot8_22.swf', '330', '19', 'false', 'Flash', '', '', 'Quality:high;wmode:transparent', '', ''));</script>
-                </td>
-            </tr>
-        </table>
-        <br>Désignez le principal indice permettant de justifier la présence d'un <i><a class="STY_lienComt" href="javascript:parent.SCO_ouvrirDoc('doc28886','htm')">present
-            perfect</a></i>.
-    </div><div id="divConsigne" onclick="SPE_clicDansBulle(event,'divConsigne')"></div>
-    """ ;
-    :id "pg4031" ;
-    :index 0 ;
-    :titre "Première tâche" ;
-    rdfs:subClassOf :act957420 .
-
 :pg9988 a :Activite,
         :Exercice,
         :ExerciceQC,
diff --git a/tetras_extraction/script/.vscode/launch.json b/tetras_extraction/script/.vscode/launch.json
index a98355be67884e272ff9b05314624bc82389c740..a42deee659da338dcde90666b2fbe03b9624030e 100644
--- a/tetras_extraction/script/.vscode/launch.json
+++ b/tetras_extraction/script/.vscode/launch.json
@@ -35,6 +35,14 @@
             "program": "src/main.py",
             "console": "integratedTerminal",
             "envFile": "${workspaceFolder}/.env"
+        },
+        {
+            "name": "Python: test",
+            "type": "debugpy",
+            "request": "launch",
+            "program": "src/test.py",
+            "console": "integratedTerminal",
+            "envFile": "${workspaceFolder}/.env"
         }
     ]
 }
\ No newline at end of file
diff --git a/tetras_extraction/script/.vscode/settings.json b/tetras_extraction/script/.vscode/settings.json
index c3434325b7625865a21b082eb6dac06611985a19..607407154f6fdafee02fb7432853db1aaf2bceda 100644
--- a/tetras_extraction/script/.vscode/settings.json
+++ b/tetras_extraction/script/.vscode/settings.json
@@ -9,5 +9,15 @@
     },
     "editor.formatOnSave": true,
     "python.analysis.autoImportCompletions": true,
-    "python.analysis.typeCheckingMode": "basic"
+    "python.analysis.typeCheckingMode": "basic",
+    "python.envFile": "${workspaceFolder}/.env",
+    "python.testing.unittestArgs": [
+        "-v",
+        "-s",
+        "./src",
+        "-p",
+        "test*.py"
+    ],
+    "python.testing.pytestEnabled": false,
+    "python.testing.unittestEnabled": true
 }
\ No newline at end of file
diff --git a/tetras_extraction/script/src/extract_page.py b/tetras_extraction/script/src/extract_page.py
index 1a3e90881d37d1f0a1ee93f66ace33a00939d10e..685fcacd585302bd5c3c049c127d3a0094987e0a 100644
--- a/tetras_extraction/script/src/extract_page.py
+++ b/tetras_extraction/script/src/extract_page.py
@@ -408,10 +408,17 @@ class RegexParser(JSParser):
                 re.VERBOSE,
             )
             for match in comments_regex.finditer(code):
-                choice = exo.get_or_create_choice(match.group("choice_id"))
-                # Save a Comment object with just the ID, other fields will be
-                # filled at the HTML parsing stage
-                choice.comment = Comment(match.group("comment_id"))
+                choice_id = match.group("choice_id")
+                comment_id = match.group("comment_id")
+                try:
+                    choice = exo.choices[choice_id]
+                    # Save a Comment object with just the ID, other fields will be
+                    # filled at the HTML parsing stage
+                    choice.comment = Comment(comment_id)
+                except KeyError:
+                    log.warning(
+                        f"{self.act_id}: '{comment_id}' requested choice ID '{choice_id}', which doesn't exist"
+                    )
             pass
 
     def _parse_score(self, code: str):
diff --git a/tetras_extraction/script/src/test.py b/tetras_extraction/script/src/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..68c1a8d776e8353f6eede9b80a7747abb33864cb
--- /dev/null
+++ b/tetras_extraction/script/src/test.py
@@ -0,0 +1,154 @@
+import unittest
+
+from rdflib import Graph
+
+import extract
+import transform
+from common import *
+
+
+class TestObjectCount(unittest.TestCase):
+    def __init__(self, methodName):  # pyright: ignore[reportMissingParameterType]
+        super().__init__()
+        # Run extraction
+        extract.main()
+        transform.main()
+        # Load graph
+        self.graph = Graph()
+        self.graph.bind("", NS)
+        self.graph.parse(RDF_FULL_FILE)
+
+    def runTest(self):
+        # Modules
+        self.assertCount(
+            """SELECT * WHERE {
+                ?subj a :Module .
+
+                ?subj :id ?id .
+                ?subj :index ?index .
+                ?subj :titre ?titre .
+                
+                MINUS { ?subj a :SousPartie }
+                }""",
+            (9, 6, 9 + 6),
+        )
+        # SousParties
+        self.assertCount(
+            """SELECT * WHERE {
+                ?subj a :SousPartie .
+
+                ?subj :id ?id .
+                ?subj :index ?index .
+                ?subj :titre ?titre .
+                }""",
+            (18, 14, 18 + 14),
+        )
+        # Activités
+        self.assertCount(
+            """SELECT * WHERE {
+                ?subj a :Activite .
+
+                ?subj :id ?id .
+                ?subj :index ?index .
+                ?subj :titre ?titre .
+                ?subj :description ?desc .
+                }""",
+            (132, 86, 132 + 86),
+        )
+
+        # Types d'activités:
+        # Cours
+        self.assertCount(
+            """SELECT * WHERE {
+                ?subj a :Cours .
+
+                ?subj :description ?desc .
+                }""",
+            (59, 26, 59 + 26),
+        )
+        # QCU
+        self.assertCount(
+            """SELECT DISTINCT ?subj ?desc WHERE {
+                ?subj a :ExerciceQC_QCU .
+
+                ?subj :aReponse ?rep .
+                }""",
+            (39, 25, 39 + 25),
+        )
+        # QCM
+        self.assertCount(
+            """SELECT DISTINCT ?subj ?desc WHERE {
+                ?subj a :ExerciceQC_QCM .
+
+                ?subj :aReponse ?rep .
+                }""",
+            (9, 6, 9 + 6),
+        )
+        # QM
+        self.assertCount(
+            """SELECT DISTINCT ?subj ?desc WHERE {
+                ?subj a :ExerciceQM .
+                }""",
+            (8, 3, 8 + 3),
+        )
+        # TAT
+        self.assertCount(
+            """SELECT DISTINCT ?subj ?desc WHERE {
+                ?subj a :ExerciceTAT .
+                }""",
+            (12, 25, 12 + 25),
+        )
+        # GD
+        self.assertCount(
+            """SELECT DISTINCT ?subj ?desc WHERE {
+                ?subj a :ExerciceGD .
+                }""",
+            (5, 1, 5 + 1),
+        )
+
+        # Autres entités
+        # Réponses
+        self.assertCount(
+            """SELECT * WHERE {
+                ?subj a :Reponse .
+
+                ?subj :id ?id .
+                ?subj :index ?index .
+                ?subj :correct ?correct .
+                ?subj :html ?html .
+                }""",
+            (180, 106, 180 + 106),
+        )
+
+    def assertCount(
+        self, query: str, expected_tuple: tuple[int | None, int | None, int | None]
+    ):
+        """Checks that the `query` produces the expected number of results.
+        The `expected_tuple` contains 3 values, for the macao_12 graph,
+        macao_3 graph, and both combined. A `None` value in the tuple ignores this check.
+        """
+        res = self.graph.query(query)
+        count = len(res)
+        # Check that variables bound to Literals are not empty or None
+        for binding in res.bindings:
+            for var, val in binding.items():
+                if isinstance(val, Literal):
+                    self.assertFalse(
+                        val.eq(Literal("")), f"Empty value: ?{var} = '{val}'"
+                    )
+                    self.assertFalse(
+                        val.eq(Literal("None")), f"None value: ?{var} = '{val}'"
+                    )
+
+        versions = ("macao_12", "macao_3", "full")
+        try:
+            expected = expected_tuple[versions.index(MACAO_VERSION)]
+        except ValueError:
+            self.fail(f"Unknown version '{Context.version}'")
+        if expected is not None:
+            self.assertEqual(count, expected)
+        # else skip test
+
+
+if __name__ == "__main__":
+    unittest.main()