Un élève décroche
+- 3 QCM de début d’heure sous la moyenne
- Cours lu en 2 minutes au lieu de 15
- Devoir maison non rendu
→ Premier rang, notion à réexpliquer, suivi plus régulier.
+diff --git a/.gitignore b/.gitignore index 4c49bd7..3323b34 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .env +.DS_Store diff --git a/design/.thumbnail b/design/.thumbnail new file mode 100644 index 0000000..75def0b Binary files /dev/null and b/design/.thumbnail differ diff --git a/design/Apercu accueil Blade.html b/design/Apercu accueil Blade.html new file mode 100644 index 0000000..bae94b1 --- /dev/null +++ b/design/Apercu accueil Blade.html @@ -0,0 +1,75 @@ + + +
+ + +Cours · TP sur machine · suivi des élèves
Des cours gratuits, un vrai Linux pour chaque élève et toute la classe sur un écran. Dans le navigateur, rien à installer.
Sans carte bancaire · élève ? rejoindre ma classe
Hébergé en France
Paris
RGPD
données minimisées
20 cursus
du lycée au master
443 seulement
aucun port à ouvrir
0 €
sans carte bancaire
Pour l’élève
Chaque élève a sa propre machine Debian. Il clique, la console s’ouvre. Aucun poste du lycée à configurer.
Correction
Le lab contrôle directement la machine. L’élève sait s’il a réussi, et reçoit un indice s’il bloque.
Pour l’enseignant
Vos élèves n’auront plus que le droit de tousser ou de respirer ! Les demandes arrivent dans l’ordre. Vous ouvrez la console de l’élève sans vous déplacer.
Les cours sont gratuits. Les TP sur VM : 29 € par mois pour une classe, ou 24 € par élève et par an pour un établissement.
Non. Un navigateur suffit, même sur un vieux PC ou un Chromebook. Tout passe par HTTPS, port 443.
Par code de classe, import CSV ou saisie rapide. Chaque élève reçoit une fiche de connexion, sans e-mail.
Oui. CM, TD avec cases à remplir, correction et QCM papier, en PDF.
Sur un cloud hébergé en France. Les données des élèves sont supprimées 90 jours après l’archivage de la classe.
Sans carte bancaire
Aucun cours ne correspond. Essayez un autre cursus ou un autre mot.
+Du lycée au master · rien à installer
+ ++ Debian ou l’IDE s’ouvre dans le navigateur en moins de 5 secondes. Les labs se corrigent tout seuls, et vous voyez qui avance, qui bloque, qui lève la main. +
+ + +Nora lève la main
+bloquée depuis 8 min
+Lycée NSI
+BTS SIO · SISR et SLAM
+BTS CIEL
+BUT · Licence pro
+Master · École d’ingé
++ Chaque élève a sa propre VM Debian, sur un cloud hébergé en France. Rien ne s'installe sur les postes du lycée. +
+Des VM déjà démarrées attendent en réserve. L'élève clique, la console s'ouvre, même sur un vieux PC ou un Chromebook.
+Chaque étape est vérifiée directement dans la VM. L'élève sait tout de suite s'il a réussi, avec un indice s'il bloque.
+Une tuile par élève : son étape, sa main levée, son blocage. Vous ouvrez sa console pour l'aider sans vous déplacer.
+Séance en direct
+Une tuile par élève : son étape, sa main levée, le temps passé sans avancer. Un clic ouvre sa console en lecture, un second vous donne la main.
+2nde NSI · Groupe B
+Premiers pas dans le shell · 24 élèves
+Léa M.
étape 5/5 ✓
Yanis B.
étape 3/5
Nora K.
main levée
Tom R.
étape 4/5
Inès D.
étape 2/5
Sami L.
bloqué 9 min
Chloé P.
étape 5/5 ✓
Adam F.
étape 3/5
Code ou QR de classe
Vous validez chaque demande.
Import CSV
Nom, prénom, groupe. Rien de plus.
Saisie rapide
Une ligne par élève.
Fiche de connexion
Identifiant et QR imprimés, sans e-mail pour les mineurs.
Moodle LTI 1.3
Les élèves arrivent depuis votre ENT.
443
Tout passe par HTTPS. Aucun port à ouvrir sur le réseau de l'établissement.
FR
Hébergé en France. Données d'élèves minimales, supprimées 90 jours après l'archivage.
0 install
Vieux PC, Chromebook, connexion lente : un navigateur suffit.
NAT
Les VM ne sortent pas sur Internet. Seuls les miroirs de paquets répondent.
Un espace pour chacun
+Vous devenez le roi du silence grâce à la fonction « Lever la main ».
+Vos élèves n’auront plus que le droit de tousser ou de respirer !
+Gratuit · à télécharger
+CM complet, TD prêt à imprimer avec ses cases à remplir, correction à part, QCM papier. Pour la classe, pour réviser chez soi ou pour un jour sans réseau.
+ +Gratuit, sans compte
+Chaque cours suit le découpage de l’Éducation nationale : un CM pour comprendre, un TD pour s’exercer sur papier, un TP sur une vraie VM, un QCM corrigé et expliqué.
+Première et Terminale · spécialité NSI · 16 cours
+Services informatiques aux organisations · option SISR · 18 cours
+Cybersécurité, informatique et réseaux, électronique · option IR · 12 cours
+Réseaux et télécommunications · parcours Cybersécurité et DevCloud · 13 cours
+Technicien supérieur systèmes et réseaux · niveau 5 · 11 cours
+Python, web, SQL, Bash, C · exercices dans l’IDE en ligne · 29 cours
+ Ouvrir l’IDE → +Vous devenez le roi du silence grâce à la fonction « Lever la main ».
+Vos élèves n’auront plus que le droit de tousser ou de respirer !
+Gratuit · à télécharger
+CM complet, TD prêt à imprimer avec ses cases à remplir, correction à part, QCM papier. Pour la classe, pour réviser chez soi ou pour un jour sans réseau.
+ +Pour les établissements
+Chaque établissement a son espace isolé sur notre cloud OpenStack hébergé en France. Chaque classe a son propre réseau, sans IP publique.
+Crée les classes, gère les enseignants et les quotas de l’établissement.
Réserve une séance, suit la classe en direct, prend la main sur une console.
Se connecte avec sa fiche, lance le lab, lève la main s’il bloque.
Anime des sessions pour adultes en titre professionnel.
Des séquences complètes, reliées aux référentiels : cours, TD, quiz et lab. Dupliquez une séquence, modifiez-la pour votre classe. Les quiz s’exportent en GIFT et Moodle XML.
+Dites-nous combien de classes et quelles formations. On vous répond avec une proposition.
+Vous devenez le roi du silence grâce à la fonction « Lever la main ».
+Vos élèves n’auront plus que le droit de tousser ou de respirer !
+Fonctionnalités
+Des cours aux conseils de classe, de l’IDE aux TD à imprimer, sans rien installer. Un navigateur suffit, pour l’élève comme pour le prof.
+Pourquoi un tel outil ?
+Avec des classes entières et une charge de travail déjà lourde, suivre chaque élève individuellement devient presque impossible. Un élève en difficulté décroche vite, souvent sans bruit, et le prof, pris par ses nombreuses classes, s’en rend compte trop tard.
+Paillasse surveille tout, sans être intrusif. Le QCM de début d’heure, celui qui suit la lecture du cours, les TP, les devoirs et exercices maison : chaque trace remonte au prof. Il voit rapidement qui accompagner plus régulièrement, qui faire passer au premier rang, à qui demander de réexpliquer une notion.
+C’est une supervision bienveillante et naturelle, qui ne remplace pas le regard du prof mais l’aide à savoir où concentrer ses efforts. Tout remonte dans le cockpit prof, d’où il pilote et supervise examens, devoirs maison, quiz et labs.
+Dans les labs, chaque étape a ses indices, qui se débloquent après un certain nombre de tentatives. Ils ne remplacent pas l’aide d’un prof (ni une recherche Google 😉), mais ils poussent l’élève à réfléchir un tout petit peu plus avant de vous appeler. Et souvent, ils vous évitent les questions triviales.
+Et dans l’autre sens, l’élève en excellence peut s’épanouir. Il aborde des notions plus avancées, avec une difficulté plus forte, sans prendre d’avance sur le programme : il explore des notions connexes qui développent sa culture générale.
+Tout cela dans un unique but : faciliter votre travail.
+→ Premier rang, notion à réexpliquer, suivi plus régulier.
+→ Défis plus durs sur des notions connexes, sans prendre d’avance sur le programme.
+→ L’élève cherche d’abord. Vous gardez votre temps pour les vraies questions.
+Cockpit prof
+Le cockpit prof fait remonter les informations importantes : qui décroche, qui a fini, qui lève la main, qui n’a pas rendu son devoir. De là, vous pilotez et supervisez tout le reste : examens, devoirs maison, quiz flash, labs et QCM.
+Cockpit · BTS SIO 1
mardi 29/09 · 10 h 12
À aider
3
élèves en difficulté
Mains levées
2
en attente
Examen
24/24
en cours, 0 sortie
DM
19/24
rendus avant vendredi
Toutes les ressources
+Tout ce qui a été ajouté à Paillasse, au même endroit. Chaque carte ouvre l’outil.
+Mode examen
+Pendant une épreuve, Paillasse enregistre chaque sortie de l’élève : changement d’onglet, fenêtre quittée, souris sortie du navigateur. Chaque événement est horodaté et apparaît en direct sur votre écran.
+Essayez : changez d’onglet ou sortez la souris de la page
+0 incident(s)
+Essayez aussi de copier ce texte : la copie est bloquée pendant l’épreuve.
+QCM et quiz
+L’élève valide, voit sa note, puis lit pourquoi la bonne réponse est la bonne. Vous voyez quelles questions font trébucher la classe.
+Question 2 · réussie par 38 % de la classe
+Quelle est l’adresse réseau de 10.0.3.200/22 ?
+Erreur fréquente : 10.0.3.0 (le masque n’est pas appliqué au 3ᵉ octet).
+Quiz de début d’heure
+Sélectionnez les outils à réviser parmi ceux proposés : ls, chmod, grep, ip, ssh, systemctl… Un diaporama s’affiche au tableau. Les élèves se connectent avec leur identifiant, sur téléphone ou sur PC, depuis leur navigateur. Vous voyez en direct qui est là et qui manque.
+Banque de sujets
+Classées par cursus, notion et difficulté. Modifiez-les, écrivez les vôtres, partagez-les avec vos collègues. Composez un sujet d’examen en quelques clics.
+CM, TD, TP
+Chaque cours suit le même parcours, calé sur votre référentiel. Dupliquez-le, changez ce que vous voulez, assignez-le en un clic.
+1 · CM
Une page complète
Illustrée, chronométrée. L’élève doit tout lire.
2 · QCM
A-t-il bien lu ?
Questions sur les notions du texte.
3 · TD
Optionnel
Exercices corrigés pour s’entraîner.
4 · TP
Pratiquer
VM prête en 5 s, étapes vérifiées.
5 · Examen
Quand le prof veut
Sujet tiré de la banque, surveillé en direct.
Élèves et classes
+Créez une classe, découpez-la en groupes, ajoutez les élèves comme vous préférez. L’établissement garde la main sur tout depuis l’espace administrateur, CPE compris.
Évolution des élèves
+Notes de QCM, étapes de TP réussies, temps passé, compétences du référentiel : tout se suit dans le temps, pour un élève ou pour la classe.
+ Ouvrir le suivi de classe ++6,5 points en 10 semaines. Décrochage repéré en S4, rattrapé après le TD assigné.
+Conseil de classe
+Notez une observation en deux clics pendant le cours. Au moment du conseil de classe, tout est rangé par élève et par période : notes, progression, assiduité en TP, remarques datées.
+Vieux PC et Chromebooks
Un navigateur récent suffit.
Réseau du lycée
Aucun port à ouvrir, ça passe le filtrage.
À la maison aussi
L’élève reprend son TP là où il l’a laissé.
Connexion lente
Le terminal est léger, il reste fluide.
Vous devenez le roi du silence grâce à la fonction « Lever la main ».
+Vos élèves n’auront plus que le droit de tousser ou de respirer !
+Gratuit · à télécharger
+CM complet, TD prêt à imprimer avec ses cases à remplir, correction à part, QCM papier. Pour la classe, pour réviser chez soi ou pour un jour sans réseau.
+ +Catalogue
+Chaque lab est une vraie VM Debian, ou plusieurs reliées en réseau. L’élève suit les consignes, la vérification valide chaque étape.
+Lycée NSI
+Se déplacer, créer des dossiers, lire des fichiers.
+ Lancer le lab +BTS SIO · SISR et SLAM
+Créer des comptes, régler chmod et chown, tester les accès.
+ Lancer le lab +BTS CIEL
+Configurer deux VM pour qu’elles se voient, puis diagnostiquer.
+ Lancer le lab +BUT · Licence pro
+Trois routeurs en conteneurs, une topologie à faire communiquer.
+ Lancer le lab +BTS SIO · SISR et SLAM
+Installer, publier une page, lire les journaux.
+ Lancer le lab +Master · École d’ingé
+Monter un contrôleur de domaine et joindre un client.
+ Lancer le lab +Pour les élèves
+Sur Paillasse, tu retrouves tes cours, tes QCM, l’IDE et le générateur de TD depuis chez toi, sur ton PC ou ton téléphone. Et si tu en veux encore, voici des ressources gratuites, sérieuses et en grande partie en français.
+ +Elles ne font pas partie de Paillasse. Certaines demandent de créer un compte : demande l’accord de tes parents si tu es mineur.
+Gratuit · à télécharger
+CM complet, TD prêt à imprimer avec ses cases à remplir, correction à part, QCM papier. Pour la classe, pour réviser chez soi ou pour un jour sans réseau.
+ +Le fondateur
+Parce qu’un BTS peut changer une vie. Il a changé la mienne.
+Salut ! Moi, c’est Adam Belkacemi.
+Après un bac S, je n’ai pas trouvé de filière qui me correspondait. J’ai très tôt intégré le marché du travail, et j’ai fait plein de boulots !
+L’informatique et le développement web, je les ai appris seul, en autodidacte. Au départ, c’était pour rendre service : mon frère avait besoin d’un site pour son cabinet d’infirmier, puis mon oncle pour son activité d’artisan. Le soir, après le boulot, j’apprenais, je testais, je cassais, je recommençais.
+J’ai pris goût à la programmation. Un nouveau monde s’est ouvert à moi !
+En 2019, j’intègre un BTS SN-IR, la seule formation qui voulait bien de moi… Ça a été le meilleur choix de toute ma vie !!!
+Pour la première fois, j’avais une vraie machine sous les mains, des profs qui me poussaient et un cadre pour progresser. Deux ans plus tard, j’en sors avec de bonnes notes et une lettre de recommandation de mon prof principal. Direction l’école d’ingénieur. Ça a été la plus belle expérience de toute ma vie ! 😊 Je le souhaite à tout le monde.
+Aujourd’hui, je suis data ingénieur et entrepreneur.
+
+
+ Juste après mon BTS, je tente le concours Mines-Télécom réservé aux alternants. Mes bonnes notes de BTS et la lettre de recommandation de mon prof principal font la différence : j’entre à Télécom Saint-Étienne, en école d’ingénieur.
+ + IMT + Concours Mines-Télécom, voie alternancealternance.imt.fr ↗ + +Il me reste une étape, et pas des moindres : il me faut une entreprise ! Je la trouve chez un industriel américain, à Grenoble et Échirolles, comme chef de projet digital.
+Pendant 3 ans, je pilote des projets à plusieurs centaines de milliers d’euros. Je découvre les outils de data engineering et d’IA, le suivi de production industrielle automatisé (SCADA, MES, IHM), la gestion de la qualité et la maintenance. Je permets aux équipes de terrain de suivre leur production en temps réel et de réagir plus vite quand une machine s’arrête.
+Autant vous dire que les machines qui tombent en panne au pire moment, je connais.
+À l’école, j’ai aussi créé des IA en partant de zéro, en Python. L’une reconnaît la voix et la transforme en texte. Une autre lit les caractères et reconnaît les formes (OCR).
+C’est là que j’ai compris qu’on apprend vraiment en faisant.
+À l’école d’ingé, j’ai aussi touché à tout ce qu’on y voit : les différents types de bases de données, SQL ou NoSQL, les principaux langages, les réseaux, l’électronique, la gestion de projet lean et agile, et même la compta.
+Bases de données
Langages
Et aussi
Trois mois à ’s-Hertogenbosch, que tout le monde là-bas appelle Den Bosch, comme développeur full stack, à construire une solution RH, le tout en anglais. Les premiers jours, on s’accroche. Et puis on se lance. J’en suis revenu avec un bien meilleur anglais et une expérience que je n’oublierai pas.
+
Chaque élève mérite une vraie machine pour apprendre, pas une salle informatique qui plante. Chaque prof mérite de passer son temps à enseigner, pas à réparer des postes.
+J’ai donc construit Paillasse : un outil clé en main, prêt en 5 secondes, pensé par quelqu’un qui a été assis au fond de la salle de TP.
+Une vraie VM Debian à soi, des TP qui se corrigent tout seuls, et le droit de se tromper sans rien casser.
+« Pas de cours à préparer, enfin… très peu :) »
+Moins de dépannage, plus de pédagogie. Vous voyez qui bloque et vous aidez ceux qui en ont le plus besoin.
+Tous les apprenants sur un seul écran : qui est connecté, qui avance, qui décroche.
+Vous devenez le roi du silence grâce à la fonction « Lever la main ».
+Vos élèves n’auront plus que le droit de tousser ou de respirer !
+Un choix, pas un hasard
+On a fait exprès de choisir des couleurs vives : jaune, vert menthe, rose, lavande, sur un fond blanc et des bordures noires épaisses. Le but est simple : que le regard de l’élève tombe tout de suite sur ce qui compte, la consigne, le terminal, la question, le bouton à cliquer.
+Ce n’est pas une intuition de designer. La recherche en psychologie cognitive montre depuis longtemps que la couleur et le contraste guident l’attention, et que ce qui attire l’attention est mieux retenu. Mais elle montre aussi l’inverse : trop de stimulations visuelles dispersent. Paillasse est construit sur ces deux résultats à la fois.
+Cette revue de la littérature explique que la couleur est un facteur clé pour capter l’attention, et que plus une information reçoit d’attention, plus elle a de chances d’être mémorisée. Les couleurs chaudes, comme le rouge et le jaune, attirent davantage le regard.
+ Dzulkifli & Mustafar, The Malaysian Journal of Medical Sciences, 2013 ↗ +C’est l’« effet von Restorff » : dans une série d’éléments semblables, celui qui se démarque par sa couleur, sa taille ou sa forme est mieux mémorisé. L’effet a été reproduit de nombreuses fois, on le retrouve chez l’enfant comme chez l’adulte âgé. C’est pour ça qu’une notion clé, chez nous, est toujours surlignée en couleur.
+ Étude électrophysiologique de l’effet von Restorff (PMC) ↗ +Le cabinet de référence en ergonomie web recommande de limiter le nombre de couleurs : cela renforce la hiérarchie visuelle et laisse moins de choses qui distraient. La couleur doit attirer l’œil vers ce que l’on veut mettre en avant, et toujours avec le même sens d’un écran à l’autre.
+ NN/g, « Using Color to Enhance Your Design », 2024 ↗ +Ceux qui ont besoin qu’on les regarde, ou qu’on ne rate rien, ont tous fait le même choix : une couleur vive, utilisée avec une règle précise.
+
Matt Groening a choisi ce jaune proposé par la coloriste Gyorgyi Peluce pour une raison simple : dans les années 80, les gens zappaient. Il l’a expliqué à la BBC en 2007 : quand un éclair jaune passe pendant que tu changes de chaîne, tu sais que tu regardes les Simpson. Presque 40 ans plus tard, tout le monde reconnaît encore cette famille au premier coup d’œil.
+ Groening à la BBC, cité par Joe.co.uk ↗ +
Le jaune et le rouge d’une chaîne de fast-food, le rouge d’une marque de soda, le bleu d’un réseau social : les grandes marques choisissent une ou deux couleurs vives et ne les quittent plus. Le but : être reconnues en une fraction de seconde, de loin, sur un écran ou au bord d’une route. Chez Paillasse, c’est pareil : le jaune veut toujours dire « regarde ici ».
+ +
La réglementation américaine de l’aviation (14 CFR 25.1322) impose le rouge pour les alertes qui demandent une action immédiate, et l’ambre ou le jaune pour les mises en garde. Elle limite leur usage ailleurs, car trop de rouge et de jaune usent leur pouvoir d’alerte : les pilotes finissent par ne plus y réagir. Notre règle « une couleur = une information » vient de là.
+ 14 CFR 25.1322 · eCFR ↗ +
Dans un service de soins, les moniteurs suivent aussi un code de couleurs normé (norme IEC 60601-1-8) : rouge pour une alarme de haute priorité, jaune pour une priorité moyenne. Une infirmière qui entre dans une chambre voit en un regard ce qui presse. Sur le tableau de bord du prof, c’est pareil : l’élève bloqué passe en rouge, la main levée en rose.
+ +
Les vêtements de haute visibilité (norme EN ISO 20471) sont jaune fluo, orange ou rouge fluo pour une raison : ces couleurs se détachent de presque tous les décors, de jour comme au crépuscule. On ne met pas du fluo partout sur un chantier : seulement sur ce qui doit absolument être vu.
+ +
Tous ces exemples disent la même chose que la recherche : une couleur vive capte l’attention, à condition d’être réservée à l’essentiel et de garder toujours le même sens. C’est exactement la règle de Paillasse : fond blanc, et du jaune, du vert, du rose seulement là où l’élève doit regarder.
+ +1
Fond blanc, toujours
Rien autour ne vient voler l’attention. L’écran reste calme.
2
Une couleur = une information
Vert : réussi. Rose : main levée. Rouge : bloqué ou examen. Jaune : à lire maintenant.
3
Lisible par tous
Texte noir sur couleur vive, contraste élevé, et jamais une information portée par la couleur seule.
Soyons honnêtes : aucune couleur n’empêche à elle seule un élève de regarder son téléphone. Mais un écran clair, où l’essentiel saute aux yeux, lui donne moins de raisons de décrocher. Le reste, c’est le travail du prof, et Paillasse est là pour lui libérer du temps.
+Un bug, une idée, un TP qui manque ? Écrivez-moi directement. Je lis tout et je réponds.
+Ou écrivez-moi directement :
+adam@belkacemi.me
+ +Tarifs HT
+Une licence Paillasse pour un élève coûte 24 € par an : QCM, TP sur VM, suivi et mode examen compris.
+Élèves, curieux, enseignants
+0 €
+pour toujours
+Une classe, sans passer par l’intendance
+29 €/ mois
+ou 290 € / an · jusqu’à 35 élèves
+Lycée, BTS, IUT, université, école
+24 €/ élève / an
+à partir de 60 élèves · 1 440 € / an
+Académies, régions, organismes de formation
+Devis
+à partir de 500 élèves ou stagiaires
+19 € HT par mois avec 100 h de VM incluses, puis 0,09 € HT l’heure. Quotas par jeton. Les classes restent toujours prioritaires sur la capacité.
+ Obtenir une clé +FAQ
+Intendance, données, pédagogie, technique. Une question manque ? adam@belkacemi.me
+Oui. Nous envoyons un devis, vous émettez un bon de commande, la facture arrive sur Chorus Pro. Paiement par mandat administratif à 30 jours.
Non. Un enseignant crée sa classe gratuitement, sans CB. En échange, on vous demande juste un coup de pouce : vos remarques, ou votre aide pour faire souscrire votre établissement.
Une licence suit l’année scolaire, de septembre à août. Les comptes archivés sont supprimés 90 jours après la fin d’année.
Ils repartent sur la licence de l’année suivante. Leur historique (notes, observations, progression) peut être conservé si l’établissement le demande.
Oui, un devis groupé est possible pour plusieurs établissements. Écrivez-nous pour en parler.
En France, chez Scaleway, sur des serveurs situés à Strasbourg. Rien ne sort de l’Union européenne.
Nous collectons le minimum : nom, prénom, classe, résultats. Pas de publicité, pas de revente, pas de traceurs tiers. Un contrat de sous-traitance est fourni à l’établissement.
Non. C’est l’enseignant qui crée la classe et distribue les identifiants. L’élève n’a pas besoin d’adresse e-mail.
Oui, depuis n’importe quel navigateur, sur PC ou téléphone. Cours, QCM, IDE et devoirs maison restent accessibles toute l’année.
Oui. Ils sont construits à partir des référentiels officiels (BO, arrêtés, fiches RNCP), du SNT au master. Chaque CM, TD et TP indique les compétences visées.
Oui. Tout se duplique et se modifie : CM, questions, TD, sujets d’examen. Vos versions restent dans votre bibliothèque.
L’élève passe en plein écran. Si sa souris sort de la fenêtre ou s’il change d’onglet, vous le voyez en direct, avec l’heure et la durée.
Oui. Chaque TD se télécharge en PDF avec ses étapes et ses cases à remplir. La correction s’imprime à part, pour vous.
L’élève lève la main depuis son écran, vous voyez la file d’attente. Fini les « Madame ! Monsieur ! » en boucle.
Non. Tout se passe dans le navigateur : terminal Debian, IDE, navigateur relié à la VM. Rien à installer sur les postes du lycée.
Le compteur est partagé par la classe : un élève peut consommer plus si d’autres consomment moins. Au-delà, les TP restent ouverts en lecture.
Paillasse passe par une connexion web chiffrée classique, comme n’importe quel site. En cas de souci, on vous aide à le régler avec votre administrateur réseau.
Non. Chaque VM est isolée chez nous. L’élève peut tout casser dedans, il la réinitialise en un clic.
Vous devenez le roi du silence grâce à la fonction « Lever la main ».
+Vos élèves n’auront plus que le droit de tousser ou de respirer !
+Multi-établissements
6 établissements · 28 classes · 608 élèves · année 2026-2027
Élèves actifs
608
+86 ce mois
Taux d’activité
91 %
élèves connectés / semaine
Labs réalisés
4 210
depuis la rentrée
Heures de VM
2 940 h
sur 9 120 h incluses
Élèves accompagnés
47
suite à une alerte
| Établissement | Classes | Élèves | Activité | Compétences validées | Statut |
|---|---|---|---|---|---|
Lycée Jean-Jaurès Montreuil | 6 | 118 | 94 % | 72 % | Actif |
Lycée Louis-Armand Paris 15e | 9 | 204 | 90 % | 68 % | Actif |
Lycée Saint-Exupéry Marseille | 4 | 86 | 88 % | 61 % | Actif |
IUT de Villetaneuse Villetaneuse | 7 | 160 | 92 % | 70 % | Actif |
Lycée Condorcet Saint-Priest | 2 | 40 | 71 % | 55 % | Démarrage |
Lycée Vauban Brest | 0 | 0 | — | — | Invité |
Piste : proposer une formation académique sur les services réseau.
Bilan de rentrée 2026
PDF · 12 pages · 01/10
Usage par établissement
CSV · 29/09
Compétences par filière
PDF · 6 pages · 29/09
Du lycée au master · rien à installer
+ ++ Debian ou l’IDE s’ouvre dans le navigateur en moins de 5 secondes. Les labs se corrigent tout seuls, et vous voyez qui avance, qui bloque, qui lève la main. +
+ + +Nora lève la main
+bloquée depuis 8 min
+Lycée NSI
+BTS SIO · SISR et SLAM
+BTS CIEL
+BUT · Licence pro
+Master · École d’ingé
++ Chaque élève a sa propre VM Debian, sur un cloud hébergé en France. Rien ne s'installe sur les postes du lycée. +
+Des VM déjà démarrées attendent en réserve. L'élève clique, la console s'ouvre, même sur un vieux PC ou un Chromebook.
+Chaque étape est vérifiée directement dans la VM. L'élève sait tout de suite s'il a réussi, avec un indice s'il bloque.
+Une tuile par élève : son étape, sa main levée, son blocage. Vous ouvrez sa console pour l'aider sans vous déplacer.
+Séance en direct
+Une tuile par élève : son étape, sa main levée, le temps passé sans avancer. Un clic ouvre sa console en lecture, un second vous donne la main.
+2nde NSI · Groupe B
+Premiers pas dans le shell · 24 élèves
+Léa M.
étape 5/5 ✓
Yanis B.
étape 3/5
Nora K.
main levée
Tom R.
étape 4/5
Inès D.
étape 2/5
Sami L.
bloqué 9 min
Chloé P.
étape 5/5 ✓
Adam F.
étape 3/5
Code ou QR de classe
Vous validez chaque demande.
Import CSV
Nom, prénom, groupe. Rien de plus.
Saisie rapide
Une ligne par élève.
Fiche de connexion
Identifiant et QR imprimés, sans e-mail pour les mineurs.
Moodle LTI 1.3
Les élèves arrivent depuis votre ENT.
443
Tout passe par HTTPS. Aucun port à ouvrir sur le réseau de l'établissement.
FR
Hébergé en France. Données d'élèves minimales, supprimées 90 jours après l'archivage.
0 install
Vieux PC, Chromebook, connexion lente : un navigateur suffit.
NAT
Les VM ne sortent pas sur Internet. Seuls les miroirs de paquets répondent.
Un espace pour chacun
+Vous devenez le roi du silence grâce à la fonction « Lever la main ».
+Vos élèves n’auront plus que le droit de tousser ou de respirer !
+Gratuit · à télécharger
+CM complet, TD prêt à imprimer avec ses cases à remplir, correction à part, QCM papier. Pour la classe, pour réviser chez soi ou pour un jour sans réseau.
+ +Centre d’aide
Des vidéos courtes et des guides pour prendre Paillasse en main.
Vidéos en cours de tournage : les vignettes sont des emplacements.
Écrivez à adam@belkacemi.me. Chaque question aide à améliorer l’outil.
Enseignants
+Gratuit · sans CB
+Ensuite, ajoutez vos élèves par code de classe, import CSV ou saisie rapide. Pour les mineurs, on ne demande que le nom, le prénom et le groupe.
+Espace enseignant · Banque
+1 240 questions classées par cursus et par notion. Modifiez-les, ajoutez les vôtres, composez vos sujets.
+Début d’heure
+Choisissez les outils à réviser. Paillasse tire les questions dans la banque. Un diaporama s’ouvre au tableau. Les élèves se connectent avec leur identifiant depuis leur téléphone ou leur PC, et vous voyez tout de suite qui manque.
+ Voir le diaporama →Voir la vue élève → +Outils à réviser
+Quelle est l’adresse réseau de 10.0.3.200/22 ?
+2 pts · utilisée 34 fois · réussite 38 %
+ +Combien d’hôtes utilisables dans un /27 ?
+1 pt · utilisée 51 fois · réussite 71 %
+ +Quelles commandes affichent les interfaces réseau sous Debian ?
+1 pt · utilisée 22 fois · réussite 64 %
+ +Un VLAN isole le trafic au niveau 2 du modèle OSI.
+1 pt · utilisée 40 fois · réussite 82 %
+ +Écrivez la commande qui donne les droits rwxr-x--- au fichier notes.txt.
+2 pts · utilisée 18 fois · réussite 47 %
+ +Quel port utilise par défaut le protocole SSH ?
+1 pt · utilisée 29 fois · réussite 88 %
+ +Complétez : la route par défaut s’écrit ___ via 192.168.1.1.
+3 pts · utilisée 9 fois · réussite 29 %
+ +Bibliothèque du prof
+Du SNT au master, en passant par l’école d’ingénieurs. Chaque fiche regroupe cours, quiz, TD, labs et examens. Un même chapitre sert plusieurs formations : OSPF compte pour la NSI, le BTS SIO, le BTS CIEL, le BUT R&T et les titres pro.
+Construit à partir des programmes officiels. Vérifié le 29 septembre 2026 :
Ma séquence : 0
+Espace enseignant · Suivi
+Bloc 2 · Administration des systèmes et des réseaux · 24 élèves
+| Élève | Adressage IPv4 | VLAN | Inter-VLAN | DHCP | DNS BIND | QCM | Temps VM |
|---|---|---|---|---|---|---|---|
| LLéa MartinTerminé | ++ | + | + | + | + | 18/20 | +12 h 40 | +
| YYanis Benali | ++ | + | + | + | + | 14/20 | +9 h 10 | +
| NNora KaciMain levée | ++ | + | + | + | + | 11/20 | +8 h 05 | +
| TTom Robert | ++ | + | + | + | + | 16/20 | +10 h 30 | +
| IInès Durand | ++ | + | + | + | + | 9/20 | +5 h 20 | +
| SSami LefèvreBloqué 9 min | ++ | + | + | + | + | 7/20 | +6 h 45 | +
| CChloé PetitEn avance | ++ | + | + | + | + | 19/20 | +13 h 15 | +
| AAdam Fontaine | ++ | + | + | + | + | 13/20 | +8 h 50 | +
8 élèves sur 24 affichés · triés par besoin d’aide
+Cockpit prof
16 élèves · mardi 29 septembre · 10:22
Présents
15/16
1 absent signalé
Moyenne QCM
13,4
+0,8 sur 4 semaines
À accompagner
3
+1 cette semaine
Mains levées
3
attente moy. 2 min
DM rendus
13/16
échéance vendredi
6 étapes · médiane : étape 3
Largeur = nombre d’élèves à chaque étape. 2 élèves ont terminé.
+| Tendance |
|---|
E6 blanc SISR · 1 h 30
00:00
DM 3 · Plan d’adressage
Rendu ven. 03/10
13/16
TP maison · Scripts Bash
Rendu lun. 06/10
6/16
QCM · Lecture CM VLAN
Rendu ce soir
15/16
Léa Martin Accompagner
3 QCM sous 8/20. Proposer le premier rang et réexpliquer les VLAN.
Lucas Moreau Accompagner
Cours lu en 2 min au lieu de 15. QCM de lecture à refaire.
Hugo Petit Relancer
DM 3 non rendu. Relance automatique jeudi 18 h.
Inès Kaci Stimuler
Tous les labs réussis. Défi connexe proposé : QoS et priorisation.
Classée par élève pour le conseil de classe.
Correction assistée
Paillasse pré-corrige selon votre barème. Vous validez, ajustez et commentez.
Question 2 · masque
J’emprunte 2 bits car 2² = 4 sous-réseaux. Le masque devient /26 soit 255.255.255.192.
Question 4 · plan d’adressage
| SR | Réseau | Broadcast |
|---|---|---|
| SR1 | .0 | .63 |
| SR2 | .64 | .127 |
| SR3 | .128 | .190 ✕ |
| SR4 | .192 | .255 |
Question 5 · terminal (rejoué)
eleve@srv:~$ sudo ip addr add 192.168.10.65/26 dev eth0 +eleve@srv:~$ ip a show eth0 + inet 192.168.10.65/26 scope global eth0
Masque choisi et justifié
Suggestion : /26 correct, justification 2² = 4
Plan d’adressage complet
Suggestion : SR3 : broadcast .190 au lieu de .191
Commande de configuration
Suggestion : ip addr add 192.168.10.65/26 dev eth0
Tests de connectivité
Suggestion : ping manquant entre SR1 et SR2
Rédaction et clarté
À évaluer par vous
Note
15/20
La pré-correction vérifie ce qui est vérifiable (calculs, commandes rejouées dans la VM, tests de code). Elle ne décide jamais seule : la note n’est publiée qu’après votre validation.
+Adressage IPv4 et sous-réseaux
+Lu : 0 %
+00:00/ 20:00 conseillées
+Lis le cours jusqu’au bout. Le QCM de lecture se débloque quand toutes les parties ont été lues et que 5 minutes se sont écoulées.
+Sur un réseau, chaque machine doit pouvoir être trouvée. Comme une lettre a besoin d’une adresse postale, un paquet a besoin d’une adresse IP de destination.
+La rue
= le réseau
Toutes les maisons de la rue partagent le même nom de rue.
Le numéro
= l’hôte
Chaque maison a son numéro, unique dans la rue.
Une adresse IPv4 contient les deux informations. Le masque indique où s’arrête la rue et où commence le numéro.
+Ton prof peut ajouter ici une vidéo YouTube pour illustrer le cours.
Espace prof · la vidéo s’affiche en mode sans cookie (youtube-nocookie.com).
+Une adresse IPv4 est un nombre de 32 bits. Pour la lire plus facilement, on la découpe en 4 octets de 8 bits, écrits en décimal et séparés par des points.
+192.168.10.77
+Chaque octet va de 0 (00000000) à 255 (11111111). Une adresse comme 192.168.10.300 est donc impossible.
+Le masque est lui aussi un nombre de 32 bits. Il commence par une suite de 1 (la partie réseau) suivie d’une suite de 0 (la partie hôte). La notation CIDR écrit simplement le nombre de 1 : /26.
/26 = 255.255.255.192
+Dans le dernier octet, les 2 premiers bits valent 1 : 128 + 64 = 192. D’où 255.255.255.192.
+Pour trouver le réseau d’une adresse, on fait un ET logique bit à bit entre l’adresse et le masque. Le résultat vaut 1 seulement si les deux bits valent 1.
+| A | B | A ET B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
Dernier octet seulement
+01001101 (77)
+ET 11000000 (192)
+= 01000000 (64)
+Les trois premiers octets du masque valent 255 : ils recopient l’adresse telle quelle. L’adresse réseau de 192.168.10.77/26 est donc 192.168.10.64.
+L’adresse de diffusion (broadcast) met tous les bits d’hôte à 1. Un paquet envoyé à cette adresse arrive à toutes les machines du réseau.
+Ici, les 6 bits d’hôte à 1 donnent 01111111 = 127 : la diffusion est 192.168.10.127.
+On retire 2 adresses : celle du réseau et celle de diffusion. Avec 6 bits : 2⁶ − 2 = 62 hôtes, de 192.168.10.65 à 192.168.10.126.
+Emprunter des bits d’hôte pour le réseau crée des sous-réseaux plus petits. Emprunter 2 bits à un /24 donne 2² = 4 sous-réseaux en /26.
+192.168.10.0/24 découpé en 4 × /26
+Astuce : la taille d’un bloc vaut 256 moins la valeur du dernier octet du masque. Pour 192 : 256 − 192 = 64.
+Certaines plages sont réservées aux réseaux internes (RFC 1918). Elles ne sont pas routées sur Internet.
+4 questions sur les notions du texte, pour vérifier que tu as bien lu.
+🔒 Encore un peu de lecture
+Parties lues : 0 / 8 · Temps : 0 / 5 min
+ +Des plateformes externes pour s’entraîner encore, à ton rythme. Elles ne font pas partie de Paillasse.
+ +Étape 3
TD corrigé
3 exercices pour s’entraîner.
+Étape 4
TP sur VM
Deux VM, un routeur, 45 min.
+Étape 5
Examen
Quand ton prof le programme.
+Gratuit, sans compte
+Chaque cours suit le découpage de l’Éducation nationale : un CM pour comprendre, un TD pour s’exercer sur papier, un TP sur une vraie VM, un QCM corrigé et expliqué.
+{{ $c['sous_titre'] }} · {{ collect($c['blocs'])->sum(fn ($b) => count($b['cours'])) }} cours
+Adressage IPv4 et sous-réseaux · cours complet
+8 parties illustrées : bits, masque, ET logique, diffusion, découpage, adresses privées. Chronométré, à lire en entier pour débloquer le QCM de lecture.
+5 questions · correction expliquée
+Exercice 1
+Pour 172.16.5.130/25, donnez l’adresse réseau, la diffusion et le nombre d’hôtes.
+Un /25 coupe le dernier octet en blocs de 128. 130 est dans le bloc 128–255. Réseau : 172.16.5.128. Diffusion : 172.16.5.255. Hôtes : 2⁷ − 2 = 126.
+Exercice 2
+Découpez 192.168.1.0/24 en 4 sous-réseaux de même taille.
+4 sous-réseaux = 2 bits empruntés, donc /26. Sous-réseaux : 192.168.1.0, .64, .128 et .192, avec 62 hôtes chacun.
+Exercice 3
+Le service comptabilité a 50 postes. Quel est le plus petit sous-réseau qui convient ?
+Il faut 2ʰ − 2 ≥ 50. Avec h = 6 : 64 − 2 = 62. On garde 6 bits d’hôte, soit un /26 (255.255.255.192). Un /27 ne donnerait que 30 hôtes.
+4 étapes vérifiées automatiquement · 45 min
+ Lancer le TP +eleve@vm1:~$ sudo ip addr add 192.168.10.10/26 dev ens3
+eleve@vm1:~$ ip -br addr
+ens3 UP 192.168.10.10/26
+eleve@vm1:~$ ping -c 1 192.168.10.11
+1 packets transmitted, 1 received
+✓ Étape 2 validée
+Le prof compose son sujet dans la banque de questions, le programme pour la classe, et suit l’épreuve en direct : sorties d’onglet, copier-coller bloqué, remise automatique.
+ +Espace enseignant · Devoirs
Donnez un TP, un QCM, un TD ou un exercice de code à faire à la maison. Programmez l’ouverture et la date limite, suivez les rendus, corrigez et notez.
TP Routage inter-VLAN
18 / 24 rendus · 2 en retard
QCM Adressage IPv4 · 2ᵉ essai
11 / 24 rendus
Défi Python : somme d’une liste
5 / 28 rendus
TD Découpage en sous-réseaux
24 / 24 rendus · 3 en retard
| Élève | État | Note |
|---|---|---|
| Léa Martin30 sept. · 17:42 | Rendu | 18/20 |
| Yanis Benali1 oct. · 22:10 | Rendu | 14/20 |
| Nora Kaci2 oct. · 09:05 | En retard | — |
| Sami Lefèvre— | Non rendu | — |
| Chloé Petit29 sept. · 20:31 | Rendu | 19/20 |
Espace élève · lea.m.sio1-a
+BTS SIO 1 · Groupe A · Bloc 2
+Mon espace élève
Mardi 29 septembre · 2 devoirs cette semaine · 1 examen dans 9 jours
Moyenne QCM
16,0
+1,2 sur 4 semaines
Labs réussis
11/14
dont 3 sans indice
Devoirs à rendre
2
le prochain vendredi
Série
6 j
d’entraînement d’affilée
Lun
Mar
Mer
Jeu
Ven
Sam
Dim
mardi 29/09
DM 3 · Plan d’adressage
Réseaux · M. Belkacemi · ven. 03/10 · 23 h 59
TP maison · Scripts Bash
Linux · Mme Roche · lun. 06/10 · 18 h
QCM · Lecture CM VLAN
Réseaux · hier
E6 blanc SISR
Administration systèmes et réseaux · jeu. 08/10 · 8 h
Contrôle · Adressage IPv4
Réseaux · 1 h · mar. 13/10 · 10 h
QCM flash · Commandes Linux
Début d’heure · 5 min · chaque lundi
Pendant un examen, reste sur la page : les changements d’onglet et de fenêtre sont signalés au prof.
+référentiel BTS SIO
Pour les établissements
+Chaque établissement a son espace isolé sur notre cloud OpenStack hébergé en France. Chaque classe a son propre réseau, sans IP publique.
+Crée les classes, gère les enseignants et les quotas de l’établissement.
Réserve une séance, suit la classe en direct, prend la main sur une console.
Se connecte avec sa fiche, lance le lab, lève la main s’il bloque.
Anime des sessions pour adultes en titre professionnel.
Des séquences complètes, reliées aux référentiels : cours, TD, quiz et lab. Dupliquez une séquence, modifiez-la pour votre classe. Les quiz s’exportent en GIFT et Moodle XML.
+Dites-nous combien de classes et quelles formations. On vous répond avec une proposition.
+Adressage et VLAN · E6 blanc SISR · Léa Martin
+Temps restant59:59
+Créez le VLAN 20 « compta » et placez-y l’interface eth2.
+root@sw1:~# ip link add link eth0 name eth0.20 type vlan id 20
+root@sw1:~#
+La copie est rendue automatiquement à la fin du temps.
+Exports
Vos notes, présences et appréciations, prêtes à charger dans votre logiciel de vie scolaire.
| Nom | Prénom | Classe | Devoir | Note | Sur | Coef. | Date |
|---|---|---|---|---|---|---|---|
| Martin | Léa | BTS SIO 1 A | DM 3 | 11 | 20 | 1 | 03/10/2026 |
| Nguyen | Sarah | BTS SIO 1 A | DM 3 | 16 | 20 | 1 | 03/10/2026 |
| Kaci | Inès | BTS SIO 1 A | DM 3 | 19 | 20 | 1 | 03/10/2026 |
| Petit | Hugo | BTS SIO 1 A | DM 3 | ABS | 20 | 1 | 03/10/2026 |
16 lignes · les devoirs non rendus sont marqués ABS · encodage UTF-8
Les menus exacts dépendent de votre logiciel et de ses réglages. Un tutoriel vidéo est disponible dans l’aide.
Facturation
M. Belkacemi · BTS SIO 1 A et B
Enseignant · mensuel
Actif29,00 € HT · 34,80 € TTC / mois
Prochain paiement le 29/10/2026 · 2 classes · 33/35 élèves
VM ce mois : 270 h sur 495 h incluses
•••• 4242
expire 08/28
Vous pouvez aussi passer au prélèvement SEPA ou au bon de commande de votre établissement.
Fiche élève
Accès journalisé · visible par l’équipe pédagogique et la vie scolaire
Moyenne QCM
7,5
−4,5 en 4 semaines
Labs réussis
5/14
3,1 indices par lab
DM rendus
3/3
moyenne 11/20
Temps de lecture
−62 %
vs moyenne de la classe
Installer et configurer un poste
Adressage IPv4
VLAN et commutation
Scripts Bash
Sécurité des accès
Difficulté21/09 · M. Belkacemi
Participe mais se décourage vite.
Progrès14/09 · Mme Roche
Très bon travail en binôme sur le câblage.
CPE27/09 · Mme Diallo
Entretien prévu le 02/10 avec la famille.
Fonctionnalités
+Des cours aux conseils de classe, de l’IDE aux TD à imprimer, sans rien installer. Un navigateur suffit, pour l’élève comme pour le prof.
+Pourquoi un tel outil ?
+Avec des classes entières et une charge de travail déjà lourde, suivre chaque élève individuellement devient presque impossible. Un élève en difficulté décroche vite, souvent sans bruit, et le prof, pris par ses nombreuses classes, s’en rend compte trop tard.
+Paillasse surveille tout, sans être intrusif. Le QCM de début d’heure, celui qui suit la lecture du cours, les TP, les devoirs et exercices maison : chaque trace remonte au prof. Il voit rapidement qui accompagner plus régulièrement, qui faire passer au premier rang, à qui demander de réexpliquer une notion.
+C’est une supervision bienveillante et naturelle, qui ne remplace pas le regard du prof mais l’aide à savoir où concentrer ses efforts. Tout remonte dans le cockpit prof, d’où il pilote et supervise examens, devoirs maison, quiz et labs.
+Dans les labs, chaque étape a ses indices, qui se débloquent après un certain nombre de tentatives. Ils ne remplacent pas l’aide d’un prof (ni une recherche Google 😉), mais ils poussent l’élève à réfléchir un tout petit peu plus avant de vous appeler. Et souvent, ils vous évitent les questions triviales.
+Et dans l’autre sens, l’élève en excellence peut s’épanouir. Il aborde des notions plus avancées, avec une difficulté plus forte, sans prendre d’avance sur le programme : il explore des notions connexes qui développent sa culture générale.
+Tout cela dans un unique but : faciliter votre travail.
+→ Premier rang, notion à réexpliquer, suivi plus régulier.
+→ Défis plus durs sur des notions connexes, sans prendre d’avance sur le programme.
+→ L’élève cherche d’abord. Vous gardez votre temps pour les vraies questions.
+Cockpit prof
+Le cockpit prof fait remonter les informations importantes : qui décroche, qui a fini, qui lève la main, qui n’a pas rendu son devoir. De là, vous pilotez et supervisez tout le reste : examens, devoirs maison, quiz flash, labs et QCM.
+Cockpit · BTS SIO 1
mardi 29/09 · 10 h 12
À aider
3
élèves en difficulté
Mains levées
2
en attente
Examen
24/24
en cours, 0 sortie
DM
19/24
rendus avant vendredi
Toutes les ressources
+Tout ce qui a été ajouté à Paillasse, au même endroit. Chaque carte ouvre l’outil.
+Mode examen
+Pendant une épreuve, Paillasse enregistre chaque sortie de l’élève : changement d’onglet, fenêtre quittée, souris sortie du navigateur. Chaque événement est horodaté et apparaît en direct sur votre écran.
+Essayez : changez d’onglet ou sortez la souris de la page
+0 incident(s)
+Essayez aussi de copier ce texte : la copie est bloquée pendant l’épreuve.
+QCM et quiz
+L’élève valide, voit sa note, puis lit pourquoi la bonne réponse est la bonne. Vous voyez quelles questions font trébucher la classe.
+Question 2 · réussie par 38 % de la classe
+Quelle est l’adresse réseau de 10.0.3.200/22 ?
+Erreur fréquente : 10.0.3.0 (le masque n’est pas appliqué au 3ᵉ octet).
+Quiz de début d’heure
+Sélectionnez les outils à réviser parmi ceux proposés : ls, chmod, grep, ip, ssh, systemctl… Un diaporama s’affiche au tableau. Les élèves se connectent avec leur identifiant, sur téléphone ou sur PC, depuis leur navigateur. Vous voyez en direct qui est là et qui manque.
+Banque de sujets
+Classées par cursus, notion et difficulté. Modifiez-les, écrivez les vôtres, partagez-les avec vos collègues. Composez un sujet d’examen en quelques clics.
+CM, TD, TP
+Chaque cours suit le même parcours, calé sur votre référentiel. Dupliquez-le, changez ce que vous voulez, assignez-le en un clic.
+1 · CM
Une page complète
Illustrée, chronométrée. L’élève doit tout lire.
2 · QCM
A-t-il bien lu ?
Questions sur les notions du texte.
3 · TD
Optionnel
Exercices corrigés pour s’entraîner.
4 · TP
Pratiquer
VM prête en 5 s, étapes vérifiées.
5 · Examen
Quand le prof veut
Sujet tiré de la banque, surveillé en direct.
Élèves et classes
+Créez une classe, découpez-la en groupes, ajoutez les élèves comme vous préférez. L’établissement garde la main sur tout depuis l’espace administrateur, CPE compris.
Évolution des élèves
+Notes de QCM, étapes de TP réussies, temps passé, compétences du référentiel : tout se suit dans le temps, pour un élève ou pour la classe.
+ Ouvrir le suivi de classe ++6,5 points en 10 semaines. Décrochage repéré en S4, rattrapé après le TD assigné.
+Conseil de classe
+Notez une observation en deux clics pendant le cours. Au moment du conseil de classe, tout est rangé par élève et par période : notes, progression, assiduité en TP, remarques datées.
+Vieux PC et Chromebooks
Un navigateur récent suffit.
Réseau du lycée
Aucun port à ouvrir, ça passe le filtrage.
À la maison aussi
L’élève reprend son TP là où il l’a laissé.
Connexion lente
Le terminal est léger, il reste fluide.
Générateur de TD
+Chaque clic tire un nouvel exercice au hasard. La correction montre le calcul, étape par étape. En mode examen : 10 questions, chronométrées, notées sur 20.
+Examen terminé
0 / 20
IDE en ligne
+Python, SQL, HTML/CSS/JavaScript et Linux. Le code s’exécute vraiment, les tests disent tout de suite si c’est juste. Ton code est gardé sur cet appareil.
+Clique sur ▶ Exécuter pour lancer ton code.+ +
pwd.ls -la.projets et entre dedans.notes.txt.echo.Catalogue
+Chaque lab est une vraie VM Debian, ou plusieurs reliées en réseau. L’élève suit les consignes, la vérification valide chaque étape.
+Lycée NSI
+Se déplacer, créer des dossiers, lire des fichiers.
+ Lancer le lab +BTS SIO · SISR et SLAM
+Créer des comptes, régler chmod et chown, tester les accès.
+ Lancer le lab +BTS CIEL
+Configurer deux VM pour qu’elles se voient, puis diagnostiquer.
+ Lancer le lab +BUT · Licence pro
+Trois routeurs en conteneurs, une topologie à faire communiquer.
+ Lancer le lab +BTS SIO · SISR et SLAM
+Installer, publier une page, lire les journaux.
+ Lancer le lab +Master · École d’ingé
+Monter un contrôleur de domaine et joindre un client.
+ Lancer le lab +http://192.168.10.10/
+Informations légales
+Dernière mise à jour : 29 septembre 2026
+Éditeur : Paillasse, édité par Adam Belkacemi, [à compléter] (forme juridique, capital, SIRET, adresse du siège).
+Directeur de la publication : Adam Belkacemi. Contact : adam@belkacemi.me.
+Hébergeur : Scaleway SAS, 8 rue de la Ville-l’Évêque, 75008 Paris. Les serveurs sont situés en France, à Strasbourg.
Paillasse met à disposition des cours, des labs Linux et réseau sur machines virtuelles, des QCM et des outils de suivi pour l’enseignement.
+Les enseignants créent un compte avec leur e-mail professionnel. Les élèves se connectent avec l’identifiant et le code remis par leur enseignant. Chacun est responsable de la confidentialité de ses accès.
+Pendant la phase de démonstration, l’accès est gratuit et sans carte bancaire. Paillasse peut faire évoluer les fonctionnalités et les limites d’usage, en prévenant les utilisateurs.
+Les VM servent uniquement à l’apprentissage. Sont interdits : le minage, les attaques vers des tiers, le contournement des quotas ou du mode examen. Le trafic sortant des VM est bloqué par défaut et l’activité est journalisée.
+Pendant une épreuve, les changements d’onglet, sorties de fenêtre et sorties de souris sont enregistrés et transmis à l’enseignant. L’élève en est informé avant de commencer.
+Les conditions de réutilisation des contenus pédagogiques seront précisées ultérieurement. Les travaux des élèves leur appartiennent.
+Paillasse fait ses meilleurs efforts pour assurer la disponibilité du service, sans garantie d’absence d’interruption. [à compléter]
+Les présentes conditions sont soumises au droit français.
Quand un établissement utilise Paillasse avec ses élèves, l’établissement est responsable du traitement et Paillasse agit comme sous-traitant. Pour les comptes enseignants créés directement, Paillasse est responsable du traitement.
+Fournir le service d’enseignement demandé par l’établissement (mission d’intérêt public de l’établissement) ou par l’enseignant (exécution du contrat).
+Les données d’une classe sont supprimées automatiquement 90 jours après son archivage de fin d’année.
+Toutes les données sont hébergées en France, chez Scaleway. Elles ne quittent pas l’Union européenne. Aucune donnée n’est vendue ni utilisée à des fins publicitaires.
+Accès, rectification, effacement, limitation, opposition et portabilité : écrivez à adam@belkacemi.me ou à votre établissement. Vous pouvez aussi adresser une réclamation à la CNIL (cnil.fr).
+Délégué à la protection des données : [à compléter]
Pour chaque établissement, un accord de sous-traitance précise :
+Pour les élèves
+Sur Paillasse, tu retrouves tes cours, tes QCM, l’IDE et le générateur de TD depuis chez toi, sur ton PC ou ton téléphone. Et si tu en veux encore, voici des ressources gratuites, sérieuses et en grande partie en français.
+ +Elles ne font pas partie de Paillasse. Certaines demandent de créer un compte : demande l’accord de tes parents si tu es mineur.
+Messagerie
Élève · BTS SIO 1 A · lab VLAN en cours
Bonjour Monsieur, je ne comprends pas l’étape 4 du lab VLAN, la commande ne marche pas.
10:12
J’ai déjà utilisé les 2 indices 😅
10:14
Bonjour Yanis. Regarde bien le nom de l’interface avec ip a : ce n’est pas eth0 sur cette VM.
10:16
Votre offre Enseignant est active. Le reçu et la facture sont envoyés par e-mail.
+Un coup de pouce en plus ? Parlez de Paillasse à votre établissement, ou écrivez vos remarques à adam@belkacemi.me.
+Les cours restent gratuits pour toujours. Vous payez les VM, le suivi et les outils prof.
Le numéro de carte est saisi dans un champ sécurisé fourni par Stripe. Paillasse ne le voit ni ne le stocke.
En validant, vous autorisez Paillasse à prélever le montant indiqué via Stripe. Vous pouvez demander un remboursement à votre banque sous 8 semaines.
Votre classe est ouverte dès la réception du bon de commande.
Le fondateur
+Parce qu’un BTS peut changer une vie. Il a changé la mienne.
+Salut ! Moi, c’est Adam Belkacemi.
+Après un bac S, je n’ai pas trouvé de filière qui me correspondait. J’ai très tôt intégré le marché du travail, et j’ai fait plein de boulots !
+L’informatique et le développement web, je les ai appris seul, en autodidacte. Au départ, c’était pour rendre service : mon frère avait besoin d’un site pour son cabinet d’infirmier, puis mon oncle pour son activité d’artisan. Le soir, après le boulot, j’apprenais, je testais, je cassais, je recommençais.
+J’ai pris goût à la programmation. Un nouveau monde s’est ouvert à moi !
+En 2019, j’intègre un BTS SN-IR, la seule formation qui voulait bien de moi… Ça a été le meilleur choix de toute ma vie !!!
+Pour la première fois, j’avais une vraie machine sous les mains, des profs qui me poussaient et un cadre pour progresser. Deux ans plus tard, j’en sors avec de bonnes notes et une lettre de recommandation de mon prof principal. Direction l’école d’ingénieur. Ça a été la plus belle expérience de toute ma vie ! 😊 Je le souhaite à tout le monde.
+Aujourd’hui, je suis data ingénieur et entrepreneur.
+
+
+ Juste après mon BTS, je tente le concours Mines-Télécom réservé aux alternants. Mes bonnes notes de BTS et la lettre de recommandation de mon prof principal font la différence : j’entre à Télécom Saint-Étienne, en école d’ingénieur.
+ + IMT + Concours Mines-Télécom, voie alternancealternance.imt.fr ↗ + +Il me reste une étape, et pas des moindres : il me faut une entreprise ! Je la trouve chez un industriel américain, à Grenoble et Échirolles, comme chef de projet digital.
+Pendant 3 ans, je pilote des projets à plusieurs centaines de milliers d’euros. Je découvre les outils de data engineering et d’IA, le suivi de production industrielle automatisé (SCADA, MES, IHM), la gestion de la qualité et la maintenance. Je permets aux équipes de terrain de suivre leur production en temps réel et de réagir plus vite quand une machine s’arrête.
+Autant vous dire que les machines qui tombent en panne au pire moment, je connais.
+À l’école, j’ai aussi créé des IA en partant de zéro, en Python. L’une reconnaît la voix et la transforme en texte. Une autre lit les caractères et reconnaît les formes (OCR).
+C’est là que j’ai compris qu’on apprend vraiment en faisant.
+À l’école d’ingé, j’ai aussi touché à tout ce qu’on y voit : les différents types de bases de données, SQL ou NoSQL, les principaux langages, les réseaux, l’électronique, la gestion de projet lean et agile, et même la compta.
+Bases de données
Langages
Et aussi
Trois mois à ’s-Hertogenbosch, que tout le monde là-bas appelle Den Bosch, comme développeur full stack, à construire une solution RH, le tout en anglais. Les premiers jours, on s’accroche. Et puis on se lance. J’en suis revenu avec un bien meilleur anglais et une expérience que je n’oublierai pas.
+ }})
Chaque élève mérite une vraie machine pour apprendre, pas une salle informatique qui plante. Chaque prof mérite de passer son temps à enseigner, pas à réparer des postes.
+J’ai donc construit Paillasse : un outil clé en main, prêt en 5 secondes, pensé par quelqu’un qui a été assis au fond de la salle de TP.
+Une vraie VM Debian à soi, des TP qui se corrigent tout seuls, et le droit de se tromper sans rien casser.
+« Pas de cours à préparer, enfin… très peu :) »
+Moins de dépannage, plus de pédagogie. Vous voyez qui bloque et vous aidez ceux qui en ont le plus besoin.
+Tous les apprenants sur un seul écran : qui est connecté, qui avance, qui décroche.
+Vous devenez le roi du silence grâce à la fonction « Lever la main ».
+Vos élèves n’auront plus que le droit de tousser ou de respirer !
+Un choix, pas un hasard
+On a fait exprès de choisir des couleurs vives : jaune, vert menthe, rose, lavande, sur un fond blanc et des bordures noires épaisses. Le but est simple : que le regard de l’élève tombe tout de suite sur ce qui compte, la consigne, le terminal, la question, le bouton à cliquer.
+Ce n’est pas une intuition de designer. La recherche en psychologie cognitive montre depuis longtemps que la couleur et le contraste guident l’attention, et que ce qui attire l’attention est mieux retenu. Mais elle montre aussi l’inverse : trop de stimulations visuelles dispersent. Paillasse est construit sur ces deux résultats à la fois.
+Cette revue de la littérature explique que la couleur est un facteur clé pour capter l’attention, et que plus une information reçoit d’attention, plus elle a de chances d’être mémorisée. Les couleurs chaudes, comme le rouge et le jaune, attirent davantage le regard.
+ Dzulkifli & Mustafar, The Malaysian Journal of Medical Sciences, 2013 ↗ +C’est l’« effet von Restorff » : dans une série d’éléments semblables, celui qui se démarque par sa couleur, sa taille ou sa forme est mieux mémorisé. L’effet a été reproduit de nombreuses fois, on le retrouve chez l’enfant comme chez l’adulte âgé. C’est pour ça qu’une notion clé, chez nous, est toujours surlignée en couleur.
+ Étude électrophysiologique de l’effet von Restorff (PMC) ↗ +Le cabinet de référence en ergonomie web recommande de limiter le nombre de couleurs : cela renforce la hiérarchie visuelle et laisse moins de choses qui distraient. La couleur doit attirer l’œil vers ce que l’on veut mettre en avant, et toujours avec le même sens d’un écran à l’autre.
+ NN/g, « Using Color to Enhance Your Design », 2024 ↗ +Ceux qui ont besoin qu’on les regarde, ou qu’on ne rate rien, ont tous fait le même choix : une couleur vive, utilisée avec une règle précise.
+ }})
Matt Groening a choisi ce jaune proposé par la coloriste Gyorgyi Peluce pour une raison simple : dans les années 80, les gens zappaient. Il l’a expliqué à la BBC en 2007 : quand un éclair jaune passe pendant que tu changes de chaîne, tu sais que tu regardes les Simpson. Presque 40 ans plus tard, tout le monde reconnaît encore cette famille au premier coup d’œil.
+ Groening à la BBC, cité par Joe.co.uk ↗ + }})
Le jaune et le rouge d’une chaîne de fast-food, le rouge d’une marque de soda, le bleu d’un réseau social : les grandes marques choisissent une ou deux couleurs vives et ne les quittent plus. Le but : être reconnues en une fraction de seconde, de loin, sur un écran ou au bord d’une route. Chez Paillasse, c’est pareil : le jaune veut toujours dire « regarde ici ».
+ + }})
La réglementation américaine de l’aviation (14 CFR 25.1322) impose le rouge pour les alertes qui demandent une action immédiate, et l’ambre ou le jaune pour les mises en garde. Elle limite leur usage ailleurs, car trop de rouge et de jaune usent leur pouvoir d’alerte : les pilotes finissent par ne plus y réagir. Notre règle « une couleur = une information » vient de là.
+ 14 CFR 25.1322 · eCFR ↗ + }})
Dans un service de soins, les moniteurs suivent aussi un code de couleurs normé (norme IEC 60601-1-8) : rouge pour une alarme de haute priorité, jaune pour une priorité moyenne. Une infirmière qui entre dans une chambre voit en un regard ce qui presse. Sur le tableau de bord du prof, c’est pareil : l’élève bloqué passe en rouge, la main levée en rose.
+ + }})
Les vêtements de haute visibilité (norme EN ISO 20471) sont jaune fluo, orange ou rouge fluo pour une raison : ces couleurs se détachent de presque tous les décors, de jour comme au crépuscule. On ne met pas du fluo partout sur un chantier : seulement sur ce qui doit absolument être vu.
+ + }})
Tous ces exemples disent la même chose que la recherche : une couleur vive capte l’attention, à condition d’être réservée à l’essentiel et de garder toujours le même sens. C’est exactement la règle de Paillasse : fond blanc, et du jaune, du vert, du rose seulement là où l’élève doit regarder.
+ +1
Fond blanc, toujours
Rien autour ne vient voler l’attention. L’écran reste calme.
2
Une couleur = une information
Vert : réussi. Rose : main levée. Rouge : bloqué ou examen. Jaune : à lire maintenant.
3
Lisible par tous
Texte noir sur couleur vive, contraste élevé, et jamais une information portée par la couleur seule.
Soyons honnêtes : aucune couleur n’empêche à elle seule un élève de regarder son téléphone. Mais un écran clair, où l’essentiel saute aux yeux, lui donne moins de raisons de décrocher. Le reste, c’est le travail du prof, et Paillasse est là pour lui libérer du temps.
+Un bug, une idée, un TP qui manque ? Écrivez-moi directement. Je lis tout et je réponds.
+Ou écrivez-moi directement :
+adam@belkacemi.me
+ +Vue élève · téléphone ou PC
+Tu es connectée, Léa !
+Regarde l’écran. La question arrive…
+ +Question 3 / 5 · la question est affichée au tableau
+Réponse envoyée ✓
+Attends la correction au tableau.
+BTS SIO 1 · Groupe A · ls, chmod, grep, ip, ping
+0 / 24 connectés
+ +Sur ton téléphone ou ton PC, va sur
+paillasse.fr/quiz
+et entre le code
+K7Q4
+Connecte-toi avec ton identifiant Paillasse.
+Présences
0 / 24
En attente des connexions…
+ +Question 1 / 5
+20 s
+0 / 0 ont répondu
+ + +Quiz terminé !
+0 %
+de bonnes réponses pour la classe
+ +Absents au quiz
+Résultats enregistrés dans le suivi de la classe.
+ Retour à la banque +Sujet · étape par étape
Composez un sujet en 5 étapes, à partir de la banque ou de vos questions.
Tarifs HT
+Une licence Paillasse pour un élève coûte 24 € par an : QCM, TP sur VM, suivi et mode examen compris.
+Élèves, curieux, enseignants
+0 €
+pour toujours
+Une classe, sans passer par l’intendance
+29 €/ mois
+ou 290 € / an · jusqu’à 35 élèves
+Lycée, BTS, IUT, université, école
+24 €/ élève / an
+à partir de 60 élèves · 1 440 € / an
+Académies, régions, organismes de formation
+Devis
+à partir de 500 élèves ou stagiaires
+19 € HT par mois avec 100 h de VM incluses, puis 0,09 € HT l’heure. Quotas par jeton. Les classes restent toujours prioritaires sur la capacité.
+ Obtenir une clé +FAQ
+Intendance, données, pédagogie, technique. Une question manque ? adam@belkacemi.me
+Oui. Nous envoyons un devis, vous émettez un bon de commande, la facture arrive sur Chorus Pro. Paiement par mandat administratif à 30 jours.
Non. Un enseignant crée sa classe gratuitement, sans CB. En échange, on vous demande juste un coup de pouce : vos remarques, ou votre aide pour faire souscrire votre établissement.
Une licence suit l’année scolaire, de septembre à août. Les comptes archivés sont supprimés 90 jours après la fin d’année.
Ils repartent sur la licence de l’année suivante. Leur historique (notes, observations, progression) peut être conservé si l’établissement le demande.
Oui, un devis groupé est possible pour plusieurs établissements. Écrivez-nous pour en parler.
En France, chez Scaleway, sur des serveurs situés à Strasbourg. Rien ne sort de l’Union européenne.
Nous collectons le minimum : nom, prénom, classe, résultats. Pas de publicité, pas de revente, pas de traceurs tiers. Un contrat de sous-traitance est fourni à l’établissement.
Non. C’est l’enseignant qui crée la classe et distribue les identifiants. L’élève n’a pas besoin d’adresse e-mail.
Oui, depuis n’importe quel navigateur, sur PC ou téléphone. Cours, QCM, IDE et devoirs maison restent accessibles toute l’année.
Oui. Ils sont construits à partir des référentiels officiels (BO, arrêtés, fiches RNCP), du SNT au master. Chaque CM, TD et TP indique les compétences visées.
Oui. Tout se duplique et se modifie : CM, questions, TD, sujets d’examen. Vos versions restent dans votre bibliothèque.
L’élève passe en plein écran. Si sa souris sort de la fenêtre ou s’il change d’onglet, vous le voyez en direct, avec l’heure et la durée.
Oui. Chaque TD se télécharge en PDF avec ses étapes et ses cases à remplir. La correction s’imprime à part, pour vous.
L’élève lève la main depuis son écran, vous voyez la file d’attente. Fini les « Madame ! Monsieur ! » en boucle.
Non. Tout se passe dans le navigateur : terminal Debian, IDE, navigateur relié à la VM. Rien à installer sur les postes du lycée.
Le compteur est partagé par la classe : un élève peut consommer plus si d’autres consomment moins. Au-delà, les TP restent ouverts en lecture.
Paillasse passe par une connexion web chiffrée classique, comme n’importe quel site. En cas de souci, on vous aide à le régler avec votre administrateur réseau.
Non. Chaque VM est isolée chez nous. L’élève peut tout casser dedans, il la réinitialise en un clic.
TD prêt à imprimer
+Étapes numérotées, cases à remplir, auto-évaluation. La correction s’imprime à part, pour le prof.
+BTS SIO · BTS CIEL · BUT R&T 1re année
Durée : 1 h · Calculatrice interdite
Nom :
Classe :
Date :
Rappel : un masque /n laisse 32 − n bits pour les hôtes. Nombre d’hôtes utilisables = 2(32 − n) − 2.
+L’établissement dispose du réseau 192.168.10.0/24. Complète les cases.
Il faut 4 sous-réseaux de même taille. Combien de bits emprunter ? Coche puis justifie.
Justification :
Avec ton masque, complète le tableau.
| Adresse réseau | |
|---|---|
| Masque (décimal) | |
| Nombre d’adresses par sous-réseau | |
| Hôtes utilisables |
Remplis le plan d’adressage des 4 sous-réseaux.
| Sous-réseau | Adresse réseau | Plage d’hôtes | Broadcast |
|---|---|---|---|
| SR1 · Administration | |||
| SR2 · Élèves | |||
| SR3 · Serveurs | |||
| SR4 · Wi-Fi invités |
Connecte-toi au lab « Adressage IPv4 » et configure le poste du SR2. Recopie la commande utilisée.
Coche ce que tu sais faire.
L’établissement dispose du réseau 192.168.10.0/24. Complète les cases.
Il faut 4 sous-réseaux de même taille. Combien de bits emprunter ? Coche puis justifie.
Justification :
2² = 4 sous-réseaux. Le masque passe de /24 à /26.
Avec ton masque, complète le tableau.
| Adresse réseau | 192.168.10.0 |
|---|---|
| Masque (décimal) | 255.255.255.192 |
| Nombre d’adresses par sous-réseau | 64 |
| Hôtes utilisables | 62 |
Remplis le plan d’adressage des 4 sous-réseaux.
| Sous-réseau | Adresse réseau | Plage d’hôtes | Broadcast |
|---|---|---|---|
| SR1 · Administration | 192.168.10.0 | 192.168.10.1 – .62 | 192.168.10.63 |
| SR2 · Élèves | 192.168.10.64 | 192.168.10.65 – .126 | 192.168.10.127 |
| SR3 · Serveurs | 192.168.10.128 | 192.168.10.129 – .190 | 192.168.10.191 |
| SR4 · Wi-Fi invités | 192.168.10.192 | 192.168.10.193 – .254 | 192.168.10.255 |
Connecte-toi au lab « Adressage IPv4 » et configure le poste du SR2. Recopie la commande utilisée.
sudo ip addr add 192.168.10.65/26 dev eth0
Coche ce que tu sais faire.
Vous devenez le roi du silence grâce à la fonction « Lever la main ».
+Vos élèves n’auront plus que le droit de tousser ou de respirer !
+Vie scolaire et intendance
6 classes · 118 élèves · semaine du 28 septembre
Alertes ouvertes
5
2 priorité haute
Présence moyenne
92 %
sur les séances en ligne
DM rendus
75 %
toutes classes
Examens surveillés
4
cette semaine · 7 sorties
Observations
38
prêtes pour les conseils
Licences
118/120
renouvellement 31/08/2027
Coût annuel
2 832 €
HT · 24 € / élève
Heures de VM
612 h
sur 1 770 h incluses ce mois
Factures
3
1 en attente Chorus Pro
Classes actives
6
6 enseignants
remontées par les profs et par Paillasse
| Priorité | Élève | Signal | Prof référent | Action |
|---|---|---|---|---|
| Haute | Lucas Moreau BTS SIO 1 A | Décrochage dans 3 matières QCM < 8 en réseaux, maths et CEJM | M. Belkacemi | |
| Haute | Léa Martin BTS SIO 1 A | Baisse continue sur 4 semaines 12 → 7,5 de moyenne QCM | M. Belkacemi | |
| Moyenne | Enzo Blanc Terminale NSI | 5 DM non rendus Depuis la rentrée | Mme Roche | |
| Moyenne | Camille Dubois BTS SIO 1 A | 3 sorties pendant un examen E6 blanc · 12 s au total | M. Belkacemi | |
| Moyenne | Mathis Colin BTS CIEL 2 | Absences répétées 4 séances de TP manquées | M. Arnaud | |
| Positif | Inès Kaci BTS SIO 1 A | Excellence dans toutes les matières Proposée pour le tutorat | M. Belkacemi |
| Classe | Enseignant | Élèves | Moy. QCM | Alertes | DM rendus | Présence |
|---|---|---|---|---|---|---|
| BTS SIO 1 · A | M. Belkacemi | 16 | 13,4 | 3 | 81 % | 94 % |
| BTS SIO 1 · B | M. Belkacemi | 17 | 12,8 | 2 | 76 % | 91 % |
| BTS SIO 2 · SISR | Mme Roche | 14 | 13,9 | 1 | 88 % | 96 % |
| BTS CIEL 2 | M. Arnaud | 15 | 11,6 | 4 | 64 % | 85 % |
| Terminale NSI | Mme Roche | 24 | 12,1 | 3 | 70 % | 93 % |
| Seconde SNT 4 | M. Faure | 32 | 11,8 | 2 | 73 % | 95 % |
BTS SIO 1 · A
lun. 07/12 · observations saisies
BTS CIEL 2
mar. 08/12 · observations saisies
Terminale NSI
jeu. 10/12 · observations saisies
Seconde SNT 4
ven. 11/12 · observations saisies
lun. 28/09 · 09:14 · BTS SIO 1 A · E6 blanc
Hugo Petit · changement d’onglet · 3 s
lun. 28/09 · 09:21 · BTS SIO 1 A · E6 blanc
Lucas Moreau · souris hors fenêtre · 6 s
lun. 28/09 · 09:40 · BTS SIO 1 A · E6 blanc
Camille Dubois · fenêtre réduite · 2 s
mar. 29/09 · 14:00 · Terminale NSI · Contrôle SQL
24/24 connectés · aucune sortie
Il reste 2 licences. Au-delà, chaque élève ajouté est facturé 24 € HT au prorata.
| Pièce | Date | Montant HT | Statut |
|---|---|---|---|
| Devis D-2026-041 | 02/09/2026 | 2 880,00 € | Accepté |
| Bon de commande BC-1187 | 05/09/2026 | 2 880,00 € | Reçu |
| Facture F-2026-093 | 10/09/2026 | 2 832,00 € | Déposée sur Chorus Pro |
Le compteur est partagé par classe. Aucun dépassement prévu d’ici la fin de l’année au rythme actuel.
+'+k+'
'+v+'
'+d+'
'+kicker+'
'+sub+'
' + t + '
'; }, + h1: function (t) { return '' + t + '
'; }, + cta: function (t, href, note) { return '' + note + '
' : '') + '' + it.k + '
' : '') + '' + it.d + '
' : '') + (it.a ? '' + S.link(it.a[0], it.a[1]) + '
' : '') + '' + s[0] + '
' + (s[1] ? '' + s[1] + '
' : '') + 'Multi-établissements
Pour les profs
+6 établissements · 28 classes · 608 élèves · année 2026-2027
Élèves actifs
608
+86 ce mois
Taux d’activité
91 %
élèves connectés / semaine
Labs réalisés
4 210
depuis la rentrée
Heures de VM
2 940 h
sur 9 120 h incluses
Élèves accompagnés
47
suite à une alerte
| Établissement | Classes | Élèves | Activité | Compétences validées | Statut |
|---|---|---|---|---|---|
Lycée Jean-Jaurès Montreuil | 6 | 118 | 94 % | 72 % | Actif |
Lycée Louis-Armand Paris 15e | 9 | 204 | 90 % | 68 % | Actif |
Lycée Saint-Exupéry Marseille | 4 | 86 | 88 % | 61 % | Actif |
IUT de Villetaneuse Villetaneuse | 7 | 160 | 92 % | 70 % | Actif |
Lycée Condorcet Saint-Priest | 2 | 40 | 71 % | 55 % | Démarrage |
Lycée Vauban Brest | 0 | 0 | — | — | Invité |
Piste : proposer une formation académique sur les services réseau.
Bilan de rentrée 2026
PDF · 12 pages · 01/10
Usage par établissement
CSV · 29/09
Compétences par filière
PDF · 6 pages · 29/09
Centre d’aide
Des vidéos courtes et des guides pour prendre Syllabus en main.
Vidéos en cours de tournage : les vignettes sont des emplacements.
Écrivez à adam@belkacemi.me. Chaque question aide à améliorer l’outil.
Espace enseignant · Banque
+Pour les profs
+1 240 questions classées par cursus et par notion. Modifiez-les, ajoutez les vôtres, composez vos sujets.
+Début d’heure
+Choisissez les outils à réviser. Syllabus tire les questions dans la banque. Un diaporama s’ouvre au tableau. Les élèves se connectent avec leur identifiant depuis leur téléphone ou leur PC, et vous voyez tout de suite qui manque.
+ Voir le diaporama →Voir la vue élève → +Outils à réviser
+Quelle est l’adresse réseau de 10.0.3.200/22 ?
+2 pts · utilisée 34 fois · réussite 38 %
+ +Combien d’hôtes utilisables dans un /27 ?
+1 pt · utilisée 51 fois · réussite 71 %
+ +Quelles commandes affichent les interfaces réseau sous Debian ?
+1 pt · utilisée 22 fois · réussite 64 %
+ +Un VLAN isole le trafic au niveau 2 du modèle OSI.
+1 pt · utilisée 40 fois · réussite 82 %
+ +Écrivez la commande qui donne les droits rwxr-x--- au fichier notes.txt.
+2 pts · utilisée 18 fois · réussite 47 %
+ +Quel port utilise par défaut le protocole SSH ?
+1 pt · utilisée 29 fois · réussite 88 %
+ +Complétez : la route par défaut s’écrit ___ via 192.168.1.1.
+3 pts · utilisée 9 fois · réussite 29 %
+ +Bibliothèque du prof
+Pour les profs
+Du SNT au master, en passant par l’école d’ingénieurs. Chaque fiche regroupe cours, quiz, TD, labs et examens. Un même chapitre sert plusieurs formations : OSPF compte pour la NSI, le BTS SIO, le BTS CIEL, le BUT R&T et les titres pro.
+Construit à partir des programmes officiels. Vérifié le 29 septembre 2026
Ma séquence : 0
+Gratuit · à télécharger
+CM complet, TD prêt à imprimer avec ses cases à remplir, correction à part, QCM papier. Pour la classe, pour réviser chez soi ou pour un jour sans réseau.
+ +Cockpit prof
Pour les profs
+16 élèves · mardi 29 septembre · 10:22
Présents
15/16
1 absent signalé
Moyenne QCM
13,4
+0,8 sur 4 semaines
À accompagner
3
+1 cette semaine
Mains levées
3
attente moy. 2 min
DM rendus
13/16
échéance vendredi
6 étapes · médiane : étape 3
Largeur = nombre d’élèves à chaque étape. 2 élèves ont terminé.
+| Tendance |
|---|
E6 blanc SISR · 1 h 30
00:00
DM 3 · Plan d’adressage
Rendu ven. 03/10
13/16
TP maison · Scripts Bash
Rendu lun. 06/10
6/16
QCM · Lecture CM VLAN
Rendu ce soir
15/16
Léa M. Accompagner
3 QCM sous 8/20. Proposer le premier rang et réexpliquer les VLAN.
Lucas M. Accompagner
Cours lu en 2 min au lieu de 15. QCM de lecture à refaire.
Hugo P. Relancer
DM 3 non rendu. Relance automatique jeudi 18 h.
Inès K. Stimuler
Tous les labs réussis. Défi connexe proposé : QoS et priorisation.
Classée par élève pour le conseil de classe.
Scolarité
Pour les profs
+Assiduité, résultats et alertes par classe. Cliquez sur une classe pour voir ses étudiants.
Étudiants
113
6 classes
Assiduité moyenne
89 %
séances planifiées
Compétences acquises
64 %
référentiels BTS / BUT
Alertes ouvertes
15
dont 4 nouvelles
| Classe | Effectif | Assiduité | Moyenne | Compétences | Alertes | |
|---|---|---|---|---|---|---|
| BTS SIO 1 A | 16 | 93 % | 12,4 | 68 % | 1 ouverte | Voir la classe → |
| BTS SIO 1 B | 15 | 88 % | 11,1 | 61 % | 3 ouvertes | Voir la classe → |
| BTS SIO 2 A | 18 | 95 % | 13,2 | 79 % | Aucune | Voir la classe → |
| BTS SIO 2 B | 14 | 84 % | 10,6 | 57 % | 4 ouvertes | Voir la classe → |
| BTS CIEL 1 | 22 | 90 % | 11,8 | 63 % | 2 ouvertes | Voir la classe → |
| BUT R&T 1 | 28 | 86 % | 11,3 | 59 % | 5 ouvertes | Voir la classe → |
| Étudiant | Présent | Absent | Justifié | Taux |
|---|---|---|---|---|
| Petit Hugo | 18 | 6 | 1 | 72 % |
| Leroy Tom | 21 | 3 | 3 | 88 % |
| Diallo Adam | 23 | 1 | 1 | 96 % |
Absence = séance planifiée sans connexion ni présence pointée. Une connexion hors séance ne compte pas comme présence.
| Donnée | Enseignant | Prof principal | CPE | Direction | Intendance |
|---|---|---|---|---|---|
| Notes de ses classes | Lire, écrire | Lire | Lire | Lire | — |
| Assiduité | Pointer | Lire | Lire, justifier | Lire | — |
| Observations | Écrire | Lire, écrire | Lire, écrire | Lire | — |
| Fiche élève complète | Ses élèves | Sa classe | Tous | Tous | — |
| Exports | Ses classes | Sa classe | Tous | Tous | — |
| Licences et factures | — | — | — | Lire | Lire, gérer |
Chaque consultation de fiche et chaque export sont journalisés. Le journal est consultable par la direction et le DPO.
Correction assistée
Pour les profs
+Syllabus pré-corrige selon votre barème. Vous validez, ajustez et commentez.
Question 2 · masque
J’emprunte 2 bits car 2² = 4 sous-réseaux. Le masque devient /26 soit 255.255.255.192.
Question 4 · plan d’adressage
| SR | Réseau | Broadcast |
|---|---|---|
| SR1 | .0 | .63 |
| SR2 | .64 | .127 |
| SR3 | .128 | .190 ✕ |
| SR4 | .192 | .255 |
Question 5 · terminal (rejoué
eleve@srv:~$ sudo ip addr add 192.168.10.65/26 dev eth0 +eleve@srv:~$ ip a show eth0 + inet 192.168.10.65/26 scope global eth0
Masque choisi et justifié
Suggestion : /26 correct, justification 2² = 4
Plan d’adressage complet
Suggestion : SR3 : broadcast .190 au lieu de .191
Commande de configuration
Suggestion : ip addr add 192.168.10.65/26 dev eth0
Tests de connectivité
Suggestion : ping manquant entre SR1 et SR2
Rédaction et clarté
À évaluer par vous
Note
15/20
La pré-correction vérifie ce qui est vérifiable (calculs, commandes rejouées dans la VM, tests de code). Elle ne décide jamais seule : la note n’est publiée qu’après votre validation.
+Adressage IPv4 et sous-réseaux
+Lu : 0 %
+00:00/ 20:00 conseillées
+Pour les élèves
+Lis le cours jusqu’au bout. Le QCM de lecture se débloque quand toutes les parties ont été lues et que 5 minutes se sont écoulées.
+Sur un réseau, chaque machine doit pouvoir être trouvée. Comme une lettre a besoin d’une adresse postale, un paquet a besoin d’une adresse IP de destination.
+La rue
= le réseau
Toutes les maisons de la rue partagent le même nom de rue.
Le numéro
= l’hôte
Chaque maison a son numéro, unique dans la rue.
Une adresse IPv4 contient les deux informations. Le masque indique où s’arrête la rue et où commence le numéro.
+Ton prof peut ajouter ici une vidéo YouTube pour illustrer le cours.
Espace prof · la vidéo s’affiche en mode sans cookie (youtube-nocookie.com).
+Une adresse IPv4 est un nombre de 32 bits. Pour la lire plus facilement, on la découpe en 4 octets de 8 bits, écrits en décimal et séparés par des points.
+192.168.10.77
+Chaque octet va de 0 (00000000) à 255 (11111111). Une adresse comme 192.168.10.300 est donc impossible.
+Le masque est lui aussi un nombre de 32 bits. Il commence par une suite de 1 (la partie réseau) suivie d’une suite de 0 (la partie hôte). La notation CIDR écrit simplement le nombre de 1 : /26.
/26 = 255.255.255.192
+Dans le dernier octet, les 2 premiers bits valent 1 : 128 + 64 = 192. D’où 255.255.255.192.
+Pour trouver le réseau d’une adresse, on fait un ET logique bit à bit entre l’adresse et le masque. Le résultat vaut 1 seulement si les deux bits valent 1.
+| A | B | A ET B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
Dernier octet seulement
+01001101 (77
+ET 11000000 (192
+= 01000000 (64
+Les trois premiers octets du masque valent 255 : ils recopient l’adresse telle quelle. L’adresse réseau de 192.168.10.77/26 est donc 192.168.10.64.
+L’adresse de diffusion (broadcast) met tous les bits d’hôte à 1. Un paquet envoyé à cette adresse arrive à toutes les machines du réseau.
+Ici, les 6 bits d’hôte à 1 donnent 01111111 = 127 : la diffusion est 192.168.10.127.
+On retire 2 adresses : celle du réseau et celle de diffusion. Avec 6 bits : 2⁶ − 2 = 62 hôtes, de 192.168.10.65 à 192.168.10.126.
+Emprunter des bits d’hôte pour le réseau crée des sous-réseaux plus petits. Emprunter 2 bits à un /24 donne 2² = 4 sous-réseaux en /26.
+192.168.10.0/24 découpé en 4 × /26
+Astuce : la taille d’un bloc vaut 256 moins la valeur du dernier octet du masque. Pour 192 : 256 − 192 = 64.
+Certaines plages sont réservées aux réseaux internes (RFC 1918). Elles ne sont pas routées sur Internet.
+4 questions sur les notions du texte, pour vérifier que tu as bien lu.
+🔒 Encore un peu de lecture
+Parties lues : 0 / 8 · Temps : 0 / 5 min
+ +Des plateformes externes pour s’entraîner encore, à ton rythme. Elles ne font pas partie de Syllabus.
+ +Étape 3
TD corrigé
3 exercices pour s’entraîner.
+Étape 4
TP sur VM
Deux VM, un routeur, 45 min.
+Étape 5
Examen
Quand ton prof le programme.
+Pour les élèves
+Adressage IPv4 et sous-réseaux · cours complet
+8 parties illustrées : bits, masque, ET logique, diffusion, découpage, adresses privées. Chronométré, à lire en entier pour débloquer le QCM de lecture.
+5 questions · correction expliquée
+Exercice 1
+Pour 172.16.5.130/25, donnez l’adresse réseau, la diffusion et le nombre d’hôtes.
+Un /25 coupe le dernier octet en blocs de 128. 130 est dans le bloc 128–255. Réseau : 172.16.5.128. Diffusion : 172.16.5.255. Hôtes : 2⁷ − 2 = 126.
+Exercice 2
+Découpez 192.168.1.0/24 en 4 sous-réseaux de même taille.
+4 sous-réseaux = 2 bits empruntés, donc /26. Sous-réseaux : 192.168.1.0, .64, .128 et .192, avec 62 hôtes chacun.
+Exercice 3
+Le service comptabilité a 50 postes. Quel est le plus petit sous-réseau qui convient ?
+Il faut 2ʰ − 2 ≥ 50. Avec h = 6 : 64 − 2 = 62. On garde 6 bits d’hôte, soit un /26 (255.255.255.192). Un /27 ne donnerait que 30 hôtes.
+4 étapes vérifiées automatiquement · 45 min
+ Lancer le TP +eleve@vm1:~$ sudo ip addr add 192.168.10.10/26 dev ens3
+eleve@vm1:~$ ip -br addr
+ens3 UP 192.168.10.10/26
+eleve@vm1:~$ ping -c 1 192.168.10.11
+1 packets transmitted, 1 received
+✓ Étape 2 validée
+Le prof compose son sujet dans la banque de questions, le programme pour la classe, et suit l’épreuve en direct : sorties d’onglet, copier-coller bloqué, remise automatique.
+ +Gratuit, sans compte
Chaque cours suit le découpage de l’Éducation nationale : un CM pour comprendre, un TD pour s’exercer sur papier, un TP sur une vraie VM, un QCM corrigé et expliqué.
99 cours · 45 TD · 59 TP sur VM · 98 QCM corrigés
Première et Terminale · spécialité NSI · 16 cours
+Services informatiques aux organisations · option SISR · 18 cours
+Cybersécurité, informatique et réseaux, électronique · option IR · 12 cours
+Réseaux et télécommunications · parcours Cybersécurité et DevCloud · 13 cours
+Technicien supérieur systèmes et réseaux · niveau 5 · 11 cours
+Python, web, SQL, Bash, C · exercices dans l’IDE en ligne · 29 cours
+ Ouvrir l’IDE → +Les élèves signalent un blocage avec la fonction « Lever la main », sans interrompre la classe.« Lever la main ».
+Chaque demande arrive dans votre tableau de bord, dans l’ordre. !
+Gratuit · à télécharger
+CM complet, TD prêt à imprimer avec ses cases à remplir, correction à part, QCM papier. Pour la classe, pour réviser chez soi ou pour un jour sans réseau.
+ +Espace enseignant · Devoirs
Pour les profs
+Donnez un TP, un QCM, un TD ou un exercice de code à faire à la maison. Programmez l’ouverture et la date limite, suivez les rendus, corrigez et notez.
TP Routage inter-VLAN
18 / 24 rendus · 2 en retard
QCM Adressage IPv4 · 2ᵉ essai
11 / 24 rendus
Défi Python : somme d’une liste
5 / 28 rendus
TD Découpage en sous-réseaux
24 / 24 rendus · 3 en retard
| Élève | État | Note |
|---|---|---|
| Léa M.30 sept. · 17:42 | Rendu | 18/20 |
| Yanis B.1 oct. · 22:10 | Rendu | 14/20 |
| Nora Kaci2 oct. · 09:05 | En retard | — |
| Sami L.— | Non rendu | — |
| Chloé P.29 sept. · 20:31 | Rendu | 19/20 |
Les élèves signalent un blocage avec la fonction « Lever la main », sans interrompre la classe.« Lever la main ».
+Chaque demande arrive dans votre tableau de bord, dans l’ordre. !
+Espace élève · lea.m.sio1-a
+Pour les élèves
+BTS SIO 1 · Groupe A · Bloc 2
+Mon espace élève
Pour les élèves
+Mardi 29 septembre · 2 devoirs cette semaine · 1 examen dans 9 jours
Moyenne QCM
16,0
+1,2 sur 4 semaines
Labs réussis
11/14
dont 3 sans indice
Devoirs à rendre
2
le prochain vendredi
Série
6 j
d’entraînement d’affilée
Lun
Mar
Mer
Jeu
Ven
Sam
Dim
mardi 29/09
DM 3 · Plan d’adressage
Réseaux · M. Belkacemi · ven. 03/10 · 23 h 59
TP maison · Scripts Bash
Linux · Mme Roche · lun. 06/10 · 18 h
QCM · Lecture CM VLAN
Réseaux · hier
E6 blanc SISR
Administration systèmes et réseaux · jeu. 08/10 · 8 h
Contrôle · Adressage IPv4
Réseaux · 1 h · mar. 13/10 · 10 h
QCM flash · Commandes Linux
Début d’heure · 5 min · chaque lundi
Pendant un examen, reste sur la page : les changements d’onglet et de fenêtre sont signalés au prof.
+référentiel BTS SIO
Gestion administrative
Pour les profs
+Abonnement, licences, documents comptables et contrats. Accès réservé à l’intendance et à la direction.
Formule Établissement
20 classes
renouvelable chaque année
Période
01/09 → 31/08
renouvellement le 01/07/2027
Licences
118 / 120
2 disponibles
Heures de VM
2 940 h
sur 9 120 h incluses
| Titulaire | Classe / rôle | Début | Fin | Statut | |
|---|---|---|---|---|---|
| Martin Léa | BTS SIO 1 A | 01/09/2026 | 30/06/2027 | Active | |
| Kaci Inès | BTS SIO 1 A | 01/09/2026 | 30/06/2027 | Active | |
| Petit Hugo | BTS SIO 2 B | 01/09/2025 | 15/10/2026 | Fin programmée | |
| Roche Anne | Enseignante | 01/09/2026 | — | Active | |
| Leroy Tom | BTS SIO 1 B | 01/09/2026 | 29/09/2026 | Retirée |
Import CSV : colonnes nom;prenom;email;classe;date_fin. Une licence se libère automatiquement à la date de fin ; les données de l’étudiant sont supprimées 12 mois après, sauf export demandé.
| Document | N° engagement | HT | TTC | Chorus Pro | |
|---|---|---|---|---|---|
| Facture F-2026-0412 | EJ 2026-0187 | 2 400,00 € | 2 880,00 € | Déposée | |
| Bon de commande BC-2026-031 | EJ 2026-0187 | 2 400,00 € | 2 880,00 € | Validé | |
| Devis D-2026-118 | — | 2 400,00 € | 2 880,00 € | Accepté | |
| Facture F-2025-0298 | EJ 2025-0142 | 1 800,00 € | 2 160,00 € | Payée |
Fournisseur : Syllabus SAS · SIRET 000 000 000 00000 · TVA FR00000000000 · IBAN FR76 0000 0000 0000 0000 0000 000
Conditions générales de vente
v3 · 01/09/2026 · Acceptées le 03/09/2026
Contrat de service établissement
Formule Établissement · Signé le 03/09/2026
Accord de sous-traitance RGPD (art. 28
DPA v2 · Signé le 03/09/2026
Fiche fournisseur
SIRET, RIB, contacts · À jour
Modèle de bon de commande
Format administration · Modèle
Pour les établissements
Chaque établissement a son espace isolé sur notre cloud hébergé en France, à Paris. Chaque classe a son propre réseau, sans IP publique.
Réponse sous 48 h · bon de commande et Chorus Pro
Administrateur
Crée les classes, gère les enseignants et les quotas.
Enseignant
Réserve une séance, suit la classe en direct, prend la main sur une console.
Élève
Se connecte avec sa fiche, lance le lab, lève la main s’il bloque.
Formateur
Anime des sessions en titre professionnel.
Ajout et retrait d’élèves, bons de commande, factures déposées sur Chorus Pro, conventions.
Hébergement en France, RGPD, prérequis réseau, authentification unique.
Des séquences reliées aux référentiels : cours, TD, quiz et lab. Les quiz s’exportent en GIFT et Moodle XML.
Dites-nous combien de classes et quelles formations. On vous répond avec une proposition.
Adressage et VLAN · E6 blanc SISR · Léa M.
+Temps restant59:59
+Créez le VLAN 20 « compta » et placez-y l’interface eth2.
+root@sw1:~# ip link add link eth0 name eth0.20 type vlan id 20
+root@sw1:~#
+La copie est rendue automatiquement à la fin du temps.
+Exports
Pour les profs
+Vos notes, présences et appréciations, prêtes à charger dans votre logiciel de vie scolaire.
| Nom | Prénom | Classe | Devoir | Note | Sur | Coef. | Date |
|---|---|---|---|---|---|---|---|
| Martin | Léa | BTS SIO 1 A | DM 3 | 11 | 20 | 1 | 03/10/2026 |
| Nguyen | Sarah | BTS SIO 1 A | DM 3 | 16 | 20 | 1 | 03/10/2026 |
| Kaci | Inès | BTS SIO 1 A | DM 3 | 19 | 20 | 1 | 03/10/2026 |
| Petit | Hugo | BTS SIO 1 A | DM 3 | ABS | 20 | 1 | 03/10/2026 |
16 lignes · les devoirs non rendus sont marqués ABS · encodage UTF-8
Les menus exacts dépendent de votre logiciel et de ses réglages. Un tutoriel vidéo est disponible dans l’aide.
Facturation
Pour les profs
+M. Belkacemi · BTS SIO 1 A et B
Enseignant · mensuel
Actif29,00 € HT · 34,80 € TTC / mois
Prochain paiement le 29/10/2026 · 2 classes · 33/35 élèves
VM ce mois : 270 h sur 495 h incluses
•••• 4242
expire 08/28
Vous pouvez aussi passer au prélèvement SEPA ou au bon de commande de votre établissement.
Fiche élève
Pour les profs
+Accès journalisé · visible par l’équipe pédagogique et la vie scolaire
Moyenne QCM
7,5
−4,5 en 4 semaines
Labs réussis
5/14
3,1 indices par lab
DM rendus
3/3
moyenne 11/20
Temps de lecture
−62 %
vs moyenne de la classe
Installer et configurer un poste
Adressage IPv4
VLAN et commutation
Scripts Bash
Sécurité des accès
Difficulté21/09 · M. Belkacemi
Participe mais se décourage vite.
Progrès14/09 · Mme Roche
Très bon travail en binôme sur le câblage.
CPE27/09 · Mme Diallo
Entretien prévu le 02/10 avec la famille.
Fonctionnalités
Cours, TP sur machine Linux, éditeur de code, évaluations et suivi des élèves, dans un seul site. Choisissez un outil pour voir à quoi il sert, puis essayez sa démo.
Sans carte bancaire
Pourquoi un tel outil ?
+Avec des classes entières et une charge de travail déjà lourde, suivre chaque élève individuellement devient presque impossible. Un élève en difficulté décroche vite, souvent sans bruit, et le prof, pris par ses nombreuses classes, s’en rend compte trop tard.
+Syllabus surveille tout, sans être intrusif. Le QCM de début d’heure, celui qui suit la lecture du cours, les TP, les devoirs et exercices maison : chaque trace remonte au prof. Il voit rapidement qui accompagner plus régulièrement, qui faire passer au premier rang, à qui demander de réexpliquer une notion.
+C’est une supervision bienveillante et naturelle, qui ne remplace pas le regard du prof mais l’aide à savoir où concentrer ses efforts. Tout remonte dans le cockpit prof, d’où il pilote et supervise examens, devoirs maison, quiz et labs.
+Dans les labs, chaque étape a ses indices, qui se débloquent après un certain nombre de tentatives. Ils ne remplacent pas l’aide d’un prof (ni une recherche Google 😉), mais ils poussent l’élève à réfléchir un tout petit peu plus avant de vous appeler. Et souvent, ils vous évitent les questions triviales.
+Et dans l’autre sens, l’élève en excellence peut s’épanouir. Il aborde des notions plus avancées, avec une difficulté plus forte, sans prendre d’avance sur le programme : il explore des notions connexes qui développent sa culture générale.
+Tout cela dans un unique but : faciliter votre travail.
+→ Premier rang, notion à réexpliquer, suivi plus régulier.
+→ Défis plus durs sur des notions connexes, sans prendre d’avance sur le programme.
+→ L’élève cherche d’abord. Vous gardez votre temps pour les vraies questions.
+Suivre la classe, l’établissement et le territoire.
Cours, TP sur machine et code dans le navigateur.
Ressources prêtes à projeter, imprimer ou adapter.
Quiz, examens, devoirs et correction.
Le suivi individuel et les échanges.
−40 dB
Vous devenez le roi du silence grâce à la fonction « Lever la main ».
Vos élèves n’auront plus que le droit de tousser ou de respirer !
CM complet, TD prêt à imprimer avec ses cases à remplir, correction à part, QCM papier.
Générateur de TD
+Pour les profs
+Chaque clic tire un nouvel exercice au hasard. La correction montre le calcul, étape par étape. En mode examen : 10 questions, chronométrées, notées sur 20.
+Examen terminé
0 / 20
IDE en ligne
+Pour les élèves
+Python, SQL, HTML/CSS/JavaScript et Linux. Le code s’exécute vraiment, les tests disent tout de suite si c’est juste. Ton code est gardé sur cet appareil.
+Clique sur ▶ Exécuter pour lancer ton code.+ +
Enseignants
+Gratuit · sans CB
+Ensuite, ajoutez vos élèves par code de classe, import CSV ou saisie rapide. Pour les mineurs, on ne demande que le nom, le prénom et le groupe.
+Documentation technique
Pour les profs
+Ce qu’il faut savoir pour raccorder Syllabus au système d’information de l’établissement.
Protocoles pris en charge : SAML 2.0 (Shibboleth, ADFS, fédération Renater), OpenID Connect (Entra ID, Google Workspace, Keycloak), CAS (ENT). EduConnect pour les élèves du secondaire via l’ENT de l’académie.
| Paramètre | Valeur |
|---|---|
| Entity ID | https://auth.syllabus.fr/saml/metadata |
| ACS URL | https://auth.syllabus.fr/saml/acs |
| Attributs requis | mail, givenName, sn, eduPersonAffiliation |
| Redirect URI OIDC | https://auth.syllabus.fr/oidc/callback |
Import CSV
Classes et étudiants, depuis l’export de votre logiciel de scolarité
Juste à temps (JIT
Compte créé à la première connexion SSO, rattaché selon l’affiliation
SCIM 2.0
Synchronisation automatique depuis Entra ID ou Keycloak
LDAP / Active Directory
Synchronisation planifiée des groupes en lecture seule
Suppression
Compte désactivé à la fin de licence, données effacées après 12 mois
API REST en JSON, documentée au format OpenAPI 3.1. Authentification par jeton porteur, une clé par établissement avec des droits limités (lecture des notes, gestion des comptes). Limite : 600 requêtes par minute. Webhooks signés (HMAC-SHA256) pour les événements devoir rendu, examen terminé, alerte ouverte.
curl -H "Authorization: Bearer $PAILLASSE_TOKEN" \ + https://api.syllabus.fr/v1/classes/bts-sio-1a/notes?format=csv
| À autoriser | Protocole | Usage |
|---|---|---|
| syllabus.fr, *.syllabus.fr | HTTPS 443 | site, cours, API |
| vm.syllabus.fr | WSS 443 (WebSocket | terminal et IDE |
| auth.syllabus.fr | HTTPS 443 | connexion SSO |
Aucun port autre que 443, aucun logiciel à installer. Le proxy doit laisser passer les connexions WebSocket (en-tête Upgrade) et ne pas couper les sessions inactives avant 10 minutes. Navigateurs : Firefox, Chrome, Edge et Safari des deux dernières versions majeures. Débit : environ 50 kbit/s par terminal, 300 kbit/s par IDE.
| Sujet | Engagement |
|---|---|
| Hébergement | Scaleway, datacenters de Paris, France |
| RGPD | Accord de sous-traitance art. 28, registre des traitements fourni |
| Conservation | Traces d’activité 12 mois, notes jusqu’à fin de scolarité + 1 an |
| Sauvegardes | Quotidiennes, chiffrées, conservées 30 jours, second site en France |
| Disponibilité | 99,5 % par mois en période scolaire, maintenance hors cours |
| Chiffrement | TLS 1.2+ en transit, AES-256 au repos |
| DPO | dpo@syllabus.fr |
pwd.ls -la.projets et entre dedans.notes.txt.echo.http://192.168.10.10/
+Catalogue
+Pour les élèves
+Chaque lab est une vraie VM Debian, ou plusieurs reliées en réseau. L’élève suit les consignes, la vérification valide chaque étape.
+Lycée NSI
+Se déplacer, créer des dossiers, lire des fichiers.
+ Lancer le lab +BTS SIO · SISR et SLAM
+Créer des comptes, régler chmod et chown, tester les accès.
+ Lancer le lab +BTS CIEL
+Configurer deux VM pour qu’elles se voient, puis diagnostiquer.
+ Lancer le lab +BUT · Licence pro
+Trois routeurs en conteneurs, une topologie à faire communiquer.
+ Lancer le lab +BTS SIO · SISR et SLAM
+Installer, publier une page, lire les journaux.
+ Lancer le lab +Master · École d’ingé
+Monter un contrôleur de domaine et joindre un client.
+ Lancer le lab +Informations légales
+Dernière mise à jour : 29 septembre 2026
+Éditeur Syllabus, édité par Adam Belkacemi, [à compléter] (forme juridique, capital, SIRET, adresse du siège).
+Directeur de la publication Adam Belkacemi. Contact adam@belkacemi.me.
+Hébergeur Scaleway SAS, 8 rue de la Ville-l’Évêque, 75008 Paris. Les serveurs sont situés en France, à Paris.
Syllabus met à disposition des cours, des labs Linux et réseau sur machines virtuelles, des QCM et des outils de suivi pour l’enseignement.
+Les enseignants créent un compte avec leur e-mail professionnel. Les élèves se connectent avec l’identifiant et le code remis par leur enseignant. Chacun est responsable de la confidentialité de ses accès.
+L’accès enseignant est gratuit et sans carte bancaire. Syllabus peut faire évoluer les fonctionnalités et les limites d’usage, en prévenant les utilisateurs.
+Les VM servent uniquement à l’apprentissage. Sont interdits : le minage, les attaques vers des tiers, le contournement des quotas ou du mode examen. Le trafic sortant des VM est bloqué par défaut et l’activité est journalisée.
+Pendant une épreuve, les changements d’onglet, sorties de fenêtre et sorties de souris sont enregistrés et transmis à l’enseignant. L’élève en est informé avant de commencer.
+Les conditions de réutilisation des contenus pédagogiques seront précisées ultérieurement. Les travaux des élèves leur appartiennent.
+Syllabus fait ses meilleurs efforts pour assurer la disponibilité du service, sans garantie d’absence d’interruption. [à compléter]
+Les présentes conditions sont soumises au droit français.
Quand un établissement utilise Syllabus avec ses élèves, l’établissement est responsable du traitement et Syllabus agit comme sous-traitant. Pour les comptes enseignants créés directement, Syllabus est responsable du traitement.
+Fournir le service d’enseignement demandé par l’établissement (mission d’intérêt public de l’établissement) ou par l’enseignant (exécution du contrat).
+Les données d’une classe sont supprimées automatiquement 90 jours après son archivage de fin d’année.
+Toutes les données sont hébergées en France, chez Scaleway. Elles ne quittent pas l’Union européenne. Aucune donnée n’est vendue ni utilisée à des fins publicitaires.
+Accès, rectification, effacement, limitation, opposition et portabilité : écrivez à adam@belkacemi.me ou à votre établissement. Vous pouvez aussi adresser une réclamation à la CNIL (cnil.fr).
+Délégué à la protection des données [à compléter]
Pour chaque établissement, un accord de sous-traitance précise
+Pour les élèves
+Pour les élèves
+Sur Syllabus, tu retrouves tes cours, tes QCM, l’IDE et le générateur de TD depuis chez toi, sur ton PC ou ton téléphone. Et si tu en veux encore, voici des ressources gratuites, sérieuses et en grande partie en français.
+ +Elles ne font pas partie de Syllabus. Certaines demandent de créer un compte : demande l’accord de tes parents si tu es mineur.
+Gratuit · à télécharger
+CM complet, TD prêt à imprimer avec ses cases à remplir, correction à part, QCM papier. Pour la classe, pour réviser chez soi ou pour un jour sans réseau.
+ +Messagerie
Pour les profs
+Élève · BTS SIO 1 A · lab VLAN en cours
Bonjour Monsieur, je ne comprends pas l’étape 4 du lab VLAN, la commande ne marche pas.
10:12
J’ai déjà utilisé les 2 indices 😅
10:14
Bonjour Yanis. Regarde bien le nom de l’interface avec ip a : ce n’est pas eth0 sur cette VM.
10:16
Pour les profs
+Votre offre Enseignant est active. Le reçu et la facture sont envoyés par e-mail.
+Un coup de pouce en plus ? Parlez de Syllabus à votre établissement, ou écrivez vos remarques à adam@belkacemi.me.
+Pour les profs
+Les cours restent gratuits pour toujours. Vous payez les VM, le suivi et les outils prof.
Le numéro de carte est saisi dans un champ sécurisé fourni par Stripe. Syllabus ne le voit ni ne le stocke.
En validant, vous autorisez Syllabus à prélever le montant indiqué via Stripe. Vous pouvez demander un remboursement à votre banque sous 8 semaines.
Votre classe est ouverte dès la réception du bon de commande.
Vue élève · téléphone ou PC
+Pour les élèves
+Tu es connectée, Léa !
+Regarde l’écran. La question arrive…
+ +Question 3 / 5 · la question est affichée au tableau
+Réponse envoyée ✓
+Attends la correction au tableau.
+BTS SIO 1 · Groupe A · ls, chmod, grep, ip, ping
+0 / 24 connectés
+ +Sur ton téléphone ou ton PC, va sur
+syllabus.fr/quiz
+et entre le code
+K7Q4
+Connecte-toi avec ton identifiant Syllabus.
+Présences
0 / 24
En attente des connexions…
+ +Question 1 / 5
+20 s
+Pour les profs
+0 / 0 ont répondu
+ + +Quiz terminé !
+0 %
+de bonnes réponses pour la classe
+ +Absents au quiz
+Résultats enregistrés dans le suivi de la classe.
+ Retour à la banque +Espace enseignant · Suivi
+Pour les profs
+Bloc 2 · Administration des systèmes et des réseaux · 24 élèves
+| Élève | Adressage IPv4 | VLAN | Inter-VLAN | DHCP | DNS BIND | QCM | Temps VM |
|---|---|---|---|---|---|---|---|
| LLéa M.Terminé | ++ | + | + | + | + | 18/20 | +12 h 40 | +
| YYanis B. | ++ | + | + | + | + | 14/20 | +9 h 10 | +
| NNora KaciMain levée | ++ | + | + | + | + | 11/20 | +8 h 05 | +
| TTom R. | ++ | + | + | + | + | 16/20 | +10 h 30 | +
| IInès D. | ++ | + | + | + | + | 9/20 | +5 h 20 | +
| SSami L.Bloqué 9 min | ++ | + | + | + | + | 7/20 | +6 h 45 | +
| CChloé P.En avance | ++ | + | + | + | + | 19/20 | +13 h 15 | +
| AAdam F. | ++ | + | + | + | + | 13/20 | +8 h 50 | +
8 élèves sur 24 affichés · triés par besoin d’aide
+Les élèves signalent un blocage avec la fonction « Lever la main », sans interrompre la classe.« Lever la main ».
+Chaque demande arrive dans votre tableau de bord, dans l’ordre. !
+Sujet · étape par étape
Pour les profs
+Composez un sujet en 5 étapes, à partir de la banque ou de vos questions.
Tarifs HT
Une licence Syllabus pour un élève coûte 24 € par an : QCM, TP sur VM, suivi et mode examen compris.
Élèves, curieux, enseignants
0 €
pour toujours
Une classe, sans passer par l’intendance
29 € / mois
ou 290 € / an · jusqu’à 35 élèves
Le plus choisi
Lycée, BTS, IUT, université, école
24 € / élève / an
à partir de 60 élèves · 1 440 € / an
Académies, régions, organismes de formation
Sur devis
à partir de 500 élèves ou stagiaires
API et MCP pour développeurs : 19 € HT par mois avec 100 h de VM incluses, puis 0,09 € HT l’heure. Les classes restent prioritaires sur la capacité.
Intendance, données, pédagogie, technique. Une question manque ? adam@belkacemi.me
+Oui. Nous envoyons un devis, vous émettez un bon de commande, la facture arrive sur Chorus Pro. Paiement par mandat administratif à 30 jours.
Non. Un enseignant crée sa classe gratuitement, sans CB. En échange, on vous demande juste un coup de pouce : vos remarques, ou votre aide pour faire souscrire votre établissement.
Une licence suit l’année scolaire, de septembre à août. Les comptes archivés sont supprimés 90 jours après la fin d’année.
Ils repartent sur la licence de l’année suivante. Leur historique (notes, observations, progression) peut être conservé si l’établissement le demande.
Oui, un devis groupé est possible pour plusieurs établissements. Écrivez-nous pour en parler.
En France, chez Scaleway, sur des serveurs situés à Paris. Rien ne sort de l’Union européenne.
Nous collectons le minimum : nom, prénom, classe, résultats. Pas de publicité, pas de revente, pas de traceurs tiers. Un contrat de sous-traitance est fourni à l’établissement.
Non. C’est l’enseignant qui crée la classe et distribue les identifiants. L’élève n’a pas besoin d’adresse e-mail.
Oui, depuis n’importe quel navigateur, sur PC ou téléphone. Cours, QCM, IDE et devoirs maison restent accessibles toute l’année.
Oui. Ils sont construits à partir des référentiels officiels (BO, arrêtés, fiches RNCP), du SNT au master. Chaque CM, TD et TP indique les compétences visées.
Oui. Tout se duplique et se modifie : CM, questions, TD, sujets d’examen. Vos versions restent dans votre bibliothèque.
L’élève passe en plein écran. Si sa souris sort de la fenêtre ou s’il change d’onglet, vous le voyez en direct, avec l’heure et la durée.
Oui. Chaque TD se télécharge en PDF avec ses étapes et ses cases à remplir. La correction s’imprime à part, pour vous.
L’élève lève la main depuis son écran, vous voyez la file d’attente. Fini les « Madame ! Monsieur ! » en boucle.
Non. Tout se passe dans le navigateur : terminal Debian, IDE, navigateur relié à la VM. Rien à installer sur les postes du lycée.
Le compteur est partagé par la classe : un élève peut consommer plus si d’autres consomment moins. Au-delà, les TP restent ouverts en lecture.
Syllabus passe par une connexion web chiffrée classique, comme n’importe quel site. En cas de souci, on vous aide à le régler avec votre administrateur réseau.
Non. Chaque VM est isolée chez nous. L’élève peut tout casser dedans, il la réinitialise en un clic.
TD prêt à imprimer
+Pour les profs
+Étapes numérotées, cases à remplir, auto-évaluation. La correction s’imprime à part, pour le prof.
+BTS SIO · BTS CIEL · BUT R&T 1re année
Durée : 1 h · Calculatrice interdite
Nom :
Classe :
Date :
Rappel : un masque /n laisse 32 − n bits pour les hôtes. Nombre d’hôtes utilisables = 2(32 − n − 2.
+L’établissement dispose du réseau 192.168.10.0/24. Complète les cases.
Il faut 4 sous-réseaux de même taille. Combien de bits emprunter ? Coche puis justifie.
Justification
Avec ton masque, complète le tableau.
| Adresse réseau | |
|---|---|
| Masque (décimal | |
| Nombre d’adresses par sous-réseau | |
| Hôtes utilisables |
Remplis le plan d’adressage des 4 sous-réseaux.
| Sous-réseau | Adresse réseau | Plage d’hôtes | Broadcast |
|---|---|---|---|
| SR1 · Administration | |||
| SR2 · Élèves | |||
| SR3 · Serveurs | |||
| SR4 · Wi-Fi invités |
Connecte-toi au lab « Adressage IPv4 » et configure le poste du SR2. Recopie la commande utilisée.
Coche ce que tu sais faire.
L’établissement dispose du réseau 192.168.10.0/24. Complète les cases.
Il faut 4 sous-réseaux de même taille. Combien de bits emprunter ? Coche puis justifie.
Justification
2² = 4 sous-réseaux. Le masque passe de /24 à /26.
Avec ton masque, complète le tableau.
| Adresse réseau | 192.168.10.0 |
|---|---|
| Masque (décimal | 255.255.255.192 |
| Nombre d’adresses par sous-réseau | 64 |
| Hôtes utilisables | 62 |
Remplis le plan d’adressage des 4 sous-réseaux.
| Sous-réseau | Adresse réseau | Plage d’hôtes | Broadcast |
|---|---|---|---|
| SR1 · Administration | 192.168.10.0 | 192.168.10.1 – .62 | 192.168.10.63 |
| SR2 · Élèves | 192.168.10.64 | 192.168.10.65 – .126 | 192.168.10.127 |
| SR3 · Serveurs | 192.168.10.128 | 192.168.10.129 – .190 | 192.168.10.191 |
| SR4 · Wi-Fi invités | 192.168.10.192 | 192.168.10.193 – .254 | 192.168.10.255 |
Connecte-toi au lab « Adressage IPv4 » et configure le poste du SR2. Recopie la commande utilisée.
sudo ip addr add 192.168.10.65/26 dev eth0
Coche ce que tu sais faire.
Les élèves signalent un blocage avec la fonction « Lever la main », sans interrompre la classe.« Lever la main ».
+Chaque demande arrive dans votre tableau de bord, dans l’ordre. !
+Vie scolaire et intendance
Pour les profs
+6 classes · 118 élèves · semaine du 28 septembre
Alertes ouvertes
5
2 priorité haute
Présence moyenne
92 %
sur les séances en ligne
DM rendus
75 %
toutes classes
Examens surveillés
4
cette semaine · 7 sorties
Observations
38
prêtes pour les conseils
Licences
118/120
renouvellement 31/08/2027
Coût annuel
2 832 €
HT · 24 € / élève
Heures de VM
612 h
sur 1 770 h incluses ce mois
Factures
3
1 en attente Chorus Pro
Classes actives
6
6 enseignants
remontées par les profs et par Syllabus
| Priorité | Élève | Signal | Prof référent | Action |
|---|---|---|---|---|
| Haute | Lucas M. BTS SIO 1 A | Décrochage dans 3 matières QCM < 8 en réseaux, maths et CEJM | M. Belkacemi | |
| Haute | Léa M. BTS SIO 1 A | Baisse continue sur 4 semaines 12 → 7,5 de moyenne QCM | M. Belkacemi | |
| Moyenne | Enzo B. Terminale NSI | 5 DM non rendus Depuis la rentrée | Mme Roche | |
| Moyenne | Camille D. BTS SIO 1 A | 3 sorties pendant un examen E6 blanc · 12 s au total | M. Belkacemi | |
| Moyenne | Mathis C. BTS CIEL 2 | Absences répétées 4 séances de TP manquées | M. Arnaud | |
| Positif | Inès K. BTS SIO 1 A | Excellence dans toutes les matières Proposée pour le tutorat | M. Belkacemi |
| Classe | Enseignant | Élèves | Moy. QCM | Alertes | DM rendus | Présence |
|---|---|---|---|---|---|---|
| BTS SIO 1 · A | M. Belkacemi | 16 | 13,4 | 3 | 81 % | 94 % |
| BTS SIO 1 · B | M. Belkacemi | 17 | 12,8 | 2 | 76 % | 91 % |
| BTS SIO 2 · SISR | Mme Roche | 14 | 13,9 | 1 | 88 % | 96 % |
| BTS CIEL 2 | M. Arnaud | 15 | 11,6 | 4 | 64 % | 85 % |
| Terminale NSI | Mme Roche | 24 | 12,1 | 3 | 70 % | 93 % |
| Seconde SNT 4 | M. Faure | 32 | 11,8 | 2 | 73 % | 95 % |
BTS SIO 1 · A
lun. 07/12 · observations saisies
BTS CIEL 2
mar. 08/12 · observations saisies
Terminale NSI
jeu. 10/12 · observations saisies
Seconde SNT 4
ven. 11/12 · observations saisies
lun. 28/09 · 09:14 · BTS SIO 1 A · E6 blanc
Hugo P. · changement d’onglet · 3 s
lun. 28/09 · 09:21 · BTS SIO 1 A · E6 blanc
Lucas M. · souris hors fenêtre · 6 s
lun. 28/09 · 09:40 · BTS SIO 1 A · E6 blanc
Camille D. · fenêtre réduite · 2 s
mar. 29/09 · 14:00 · Terminale NSI · Contrôle SQL
24/24 connectés · aucune sortie
Il reste 2 licences. Au-delà, chaque élève ajouté est facturé 24 € HT au prorata.
| Pièce | Date | Montant HT | Statut |
|---|---|---|---|
| Devis D-2026-041 | 02/09/2026 | 2 880,00 € | Accepté |
| Bon de commande BC-1187 | 05/09/2026 | 2 880,00 € | Reçu |
| Facture F-2026-093 | 10/09/2026 | 2 832,00 € | Déposée sur Chorus Pro |
Le compteur est partagé par classe. Aucun dépassement prévu d’ici la fin de l’année au rythme actuel.
+Visio de classe
+Tous les élèves arrivent en sourdine. Ils lèvent la main, vous donnez la parole, un à la fois.
+Les vues sont reliées : levez la main côté élève (Léa M.), puis donnez-lui la parole côté prof.
+Premier arrivé en haut.
eleve@debian:~$ indique l’utilisateur, la machine, le dossier courant (~ = dossier personnel) et le type de compte ($ utilisateur, # administrateur).' },
+ { t: 'L’arborescence Linux (FHS)', d: '15 min', html: 'Tout part de la racine /. Il n’y a pas de lettres de lecteur.', table: [['Dossier', 'Contenu'], ['/home', 'dossiers personnels des utilisateurs'], ['/etc', 'fichiers de configuration'], ['/var/log', 'journaux du système'], ['/bin, /usr/bin', 'commandes'], ['/tmp', 'fichiers temporaires, vidés au redémarrage'], ['/root', 'dossier personnel de l’administrateur']] },
+ { t: 'Chemins absolus et relatifs', d: '10 min', html: 'Un chemin absolu commence par / et part de la racine : /home/eleve/notes.txt. Un chemin relatif part du dossier courant : projets/web. . désigne le dossier courant, .. le dossier parent.', exemple: 'eleve@debian:~$ pwd\n/home/eleve\neleve@debian:~$ cd projets/web\neleve@debian:~/projets/web$ cd ../..\neleve@debian:~$' },
+ { t: 'Lister et se déplacer', d: '10 min', html: 'pwd affiche le dossier courant. ls liste ; ls -l détaille (droits, taille, date) ; ls -a montre les fichiers cachés (qui commencent par un point) ; ls -lh affiche les tailles lisibles. cd change de dossier.' },
+ { t: 'Créer, copier, déplacer, supprimer', d: '15 min', html: 'mkdir -p a/b/c crée une arborescence, touch f un fichier vide, cp src dest copie (-r pour un dossier), mv déplace ou renomme, rm supprime (-r pour un dossier).', attention: 'Il n’y a pas de corbeille. rm -rf supprime sans confirmation. Relisez toujours la commande avant Entrée, surtout avec sudo.' },
+ { t: 'Aide et productivité', d: '10 min', html: 'man commande ouvre le manuel (/ pour chercher, q pour quitter). Tab complète les noms, ↑ rappelle l’historique, Ctrl+R recherche dans l’historique, Ctrl+C interrompt une commande, history liste les commandes passées.' }],
+ synthese: ['/ est la racine, ~ le dossier personnel', 'Chemin absolu = commence par /', 'pwd, ls, cd pour se repérer ; mkdir, cp, mv, rm pour agir', 'Pas de corbeille : relire avant rm'],
+ qcm: [
+ ['Où se trouvent les fichiers de configuration du système ?', ['/home', '/etc', '/var', '/bin'], 1, '/etc regroupe la configuration.'],
+ ['Lequel est un chemin absolu ?', ['projets/web', '../notes', '/var/log/syslog', '~notes'], 2, 'Il commence par /.'],
+ ['Que fait mkdir -p a/b/c ?', ['Erreur si a n’existe pas', 'Crée toute l’arborescence', 'Crée un fichier', 'Supprime a/b/c'], 1, '-p crée les dossiers parents manquants.'],
+ ['Que signifie # à la fin de l’invite ?', ['Commentaire', 'Compte administrateur', 'Erreur', 'Dossier racine'], 1, '# indique root.'],
+ ['Quelle commande copie le dossier site et son contenu ?', ['cp site copie', 'cp -r site copie', 'mv site copie', 'mkdir site copie'], 1, '-r = récursif.'],
+ ['Quel raccourci recherche dans l’historique ?', ['Ctrl+C', 'Ctrl+R', 'Ctrl+Z', 'Tab'], 1, 'Ctrl+R lance la recherche inversée.'],
+ ['Où sont les journaux du système ?', ['/var/log', '/etc/log', '/tmp', '/home/log'], 0, '/var/log contient syslog, auth.log…'],
+ ['Depuis /home/eleve/projets, que désigne ../.. ?', ['/home', '/home/eleve', '/', '/projets'], 0, 'On remonte deux fois.']],
+ td: [
+ { n: 'Échauffement', c: 'Depuis /home/eleve, donner le chemin absolu puis relatif du fichier /home/eleve/projets/web/index.html.', r: 'Absolu : /home/eleve/projets/web/index.html · relatif : projets/web/index.html' },
+ { n: 'Application', c: 'Créer en une commande : tp/{reseau,systeme,web}.', r: 'mkdir -p tp/reseau tp/systeme tp/web (ou mkdir -p tp/{reseau,systeme,web})' },
+ { n: 'Application', c: 'Copier /etc/hosts dans tp/reseau sous le nom hosts.bak, puis vérifier.', r: 'cp /etc/hosts tp/reseau/hosts.bak && ls -l tp/reseau' },
+ { n: 'Approfondissement', c: 'Trouver tous les fichiers .conf de /etc de plus de 10 Ko.', r: 'find /etc -name "*.conf" -size +10k 2>/dev/null' }],
+ tp: { type: 'Lab VM', url: 'apercu-lab-essai.html', desc: 'Un vrai terminal Debian, étapes vérifiées automatiquement dans la VM.', etapes: ['Se repérer : pwd, ls -la', 'Créer l’arborescence du projet', 'Copier et renommer des fichiers', 'Retrouver un fichier avec find', 'Nettoyer sans rien casser'] },
+ plusLoin: [['Le jeu OverTheWire Bandit (niveaux 0 à 10)', 'https://overthewire.org/wargames/bandit/'], ['Linux Journey', 'https://linuxjourney.com/']] },
+
+{ id: 'droits', match: /droits|chmod|chown|permissions|utilisateurs et groupes/i,
+ titre: 'Droits, utilisateurs et groupes sous Linux', duree: '5 h (CM 1 h 30 · TD 1 h 30 · TP 2 h)', niveau: 'BTS SIO SISR · BTS CIEL IR · BUT R&T · TSSR',
+ prerequis: ['Le terminal Linux', 'Binaire : poids des bits'],
+ competences: ['BTS SIO · Bloc 3 · Sécuriser les équipements et les usages', 'BTS CIEL · C08 · Sécuriser un système', 'BUT R&T · Compétence « Administrer »'],
+ intro: 'Sur un serveur partagé, chaque fichier appartient à quelqu’un et chacun n’a que les droits dont il a besoin : c’est le principe du moindre privilège. Une erreur de droits, c’est soit un service qui ne démarre pas, soit une fuite de données.',
+ cm: [
+ { t: 'Utilisateurs et groupes', d: '15 min', html: 'Chaque utilisateur a un identifiant (UID) et un groupe principal (GID), déclarés dans /etc/passwd et /etc/group. Les mots de passe hachés sont dans /etc/shadow, lisible par root seulement. id affiche vos identifiants.', exemple: 'root@srv:~# adduser alice\nroot@srv:~# addgroup profs\nroot@srv:~# usermod -aG profs alice\nroot@srv:~# id alice\nuid=1001(alice) gid=1001(alice) groupes=1001(alice),1002(profs)' },
+ { t: 'Lire les droits', d: '15 min', html: 'ls -l affiche 10 caractères : le type puis trois triplets pour le propriétaire (u), le groupe (g) et les autres (o).', table: [['Droit', 'Sur un fichier', 'Sur un dossier'], ['r (4)', 'lire le contenu', 'lister les noms'], ['w (2)', 'modifier', 'créer, renommer, supprimer dedans'], ['x (1)', 'exécuter', 'traverser (cd)']], exemple: '-rwxr-x--- 1 alice profs 812 sept. 29 10:14 sauvegarde.sh\n│└┬┘└┬┘└┬┘\n│ u g o' },
+ { t: 'chmod : octal et symbolique', d: '20 min', html: 'En octal, on additionne r = 4, w = 2, x = 1 pour chaque triplet : rwx = 7, r-x = 5, r-- = 4. En symbolique, on ajoute (+), retire (−) ou fixe (=) un droit pour u, g, o ou a.', exemple: 'chmod 750 sauvegarde.sh # rwxr-x---\nchmod u+x,g-w rapport.txt\nchmod -R o= /srv/partage # retire tout aux autres, récursivement' },
+ { t: 'chown et umask', d: '15 min', html: 'chown alice:profs fichier change propriétaire et groupe (réservé à root). umask fixe les droits retirés à la création : avec umask 022, un fichier est créé en 644 et un dossier en 755 ; avec 027, en 640 et 750.' },
+ { t: 'Droits spéciaux', d: '15 min', html: 'SUID (4000) : le programme s’exécute avec les droits de son propriétaire (ex. passwd). SGID (2000) sur un dossier : les fichiers créés héritent du groupe du dossier, idéal pour un partage. Sticky bit (1000) sur un dossier : seul le propriétaire d’un fichier peut le supprimer (ex. /tmp).', attention: 'Un script SUID root mal écrit est une porte d’entrée classique pour une élévation de privilèges. En audit, on les recherche avec find / -perm -4000.' },
+ { t: 'Au-delà : les ACL', d: '10 min', html: 'Les ACL permettent de donner des droits à un utilisateur précis sans changer le groupe : setfacl -m u:bob:rw rapport.txt, et getfacl pour les lire.' }],
+ synthese: ['u g o × r w x, avec r = 4, w = 2, x = 1', 'x sur un dossier = pouvoir y entrer', 'SGID sur un dossier partagé, sticky bit sur /tmp', 'Moindre privilège : ne donner que le nécessaire'],
+ qcm: [
+ ['rwxr-x--- en octal ?', ['750', '755', '740', '770'], 0, '7, 5, 0.'],
+ ['Quel fichier contient les hachages des mots de passe ?', ['/etc/passwd', '/etc/shadow', '/etc/group', '/etc/login'], 1, 'shadow, lisible par root uniquement.'],
+ ['Que fait chmod g+w rapport.txt ?', ['Donne l’écriture aux autres', 'Donne l’écriture au groupe', 'Retire l’écriture', 'Change le groupe'], 1, 'g = groupe, + = ajouter.'],
+ ['Avec umask 027, un nouveau dossier a les droits :', ['755', '750', '770', '700'], 1, '777 − 027 = 750.'],
+ ['Quel droit permet à un utilisateur de faire cd dans un dossier ?', ['r', 'w', 'x', 's'], 2, 'x sur un dossier = traverser.'],
+ ['Le sticky bit sur /tmp sert à :', ['Accélérer', 'Empêcher de supprimer les fichiers des autres', 'Chiffrer', 'Hériter du groupe'], 1, 'Chacun ne supprime que ses fichiers.'],
+ ['Comment ajouter alice au groupe profs sans retirer ses autres groupes ?', ['usermod -G profs alice', 'usermod -aG profs alice', 'chown profs alice', 'addgroup alice'], 1, '-a = append.'],
+ ['Quelle commande trouve les fichiers SUID ?', ['find / -perm -4000', 'ls -suid', 'chmod -find', 'grep suid /'], 0, '-perm -4000 cherche le bit SUID.']],
+ td: [
+ { n: 'Échauffement', c: 'Traduire en octal : rw-r--r--, rwx------, rwxrwxr-x, r--------.', r: '644 · 700 · 775 · 400' },
+ { n: 'Échauffement', c: 'Traduire en symbolique : 640, 755, 600.', r: 'rw-r----- · rwxr-xr-x · rw-------' },
+ { n: 'Application', c: 'Créer un dossier /srv/projet partagé par le groupe devs : les membres lisent et écrivent, les fichiers créés restent dans le groupe devs, les autres n’ont aucun accès.', r: 'mkdir /srv/projet\nchown root:devs /srv/projet\nchmod 2770 /srv/projet' },
+ { n: 'Application', c: 'Le script sauvegarde.sh refuse de se lancer (« Permission non accordée »). Diagnostiquer et corriger.', r: 'ls -l sauvegarde.sh → pas de x. chmod u+x sauvegarde.sh' },
+ { n: 'Approfondissement', c: 'Expliquer pourquoi un fichier en 777 dans un dossier en 700 appartenant à alice reste inaccessible à bob.', r: 'bob ne peut pas traverser le dossier (pas de x pour les autres) : il n’atteint jamais le fichier.' }],
+ tp: { type: 'Lab VM', url: 'apercu-labs.html', desc: 'Créer des comptes, un dossier partagé en SGID et tester les accès avec su.', etapes: ['Créer alice, bob et le groupe devs', 'Préparer /srv/projet en 2770', 'Tester l’écriture en tant qu’alice puis bob', 'Poser une ACL pour un stagiaire', 'Audit : lister les fichiers SUID'] },
+ plusLoin: [['ANSSI · Recommandations de sécurité relatives à un système GNU/Linux', 'https://cyber.gouv.fr/publications/recommandations-de-securite-relatives-un-systeme-gnulinux']] }
+]);
diff --git a/design/js/contenus-2.js b/design/js/contenus-2.js
new file mode 100644
index 0000000..4f3b2cb
--- /dev/null
+++ b/design/js/contenus-2.js
@@ -0,0 +1,90 @@
+// Cours complets · lot 2 : tubes, réseaux (OSI), SQL
+window.CONTENUS_PRO = (window.CONTENUS_PRO || []).concat([
+{ id: 'tubes', match: /redirection|tubes|grep|filtres|sed|awk/i,
+ titre: 'Redirections, tubes et filtres de texte', duree: '4 h (CM 1 h · TD 1 h 30 · TP 1 h 30)', niveau: 'BTS SIO · BTS CIEL · BUT R&T · TSSR',
+ prerequis: ['Le terminal Linux'],
+ competences: ['BTS SIO · Bloc 1 · Exploiter des journaux', 'BUT R&T · Compétence « Administrer » · automatiser'],
+ intro: 'Un administrateur passe beaucoup de temps à lire des journaux de plusieurs milliers de lignes. Plutôt que de les lire à l’œil, on enchaîne de petites commandes spécialisées. C’est la philosophie Unix : chaque outil fait une chose, et bien.',
+ cm: [
+ { t: 'Les trois flux standard', d: '10 min', html: 'Chaque processus dispose de trois flux : stdin (0) l’entrée, stdout (1) la sortie normale, stderr (2) les erreurs. Les séparer permet de garder les résultats propres et d’isoler les erreurs.' },
+ { t: 'Rediriger', d: '15 min', html: 'On envoie un flux vers un fichier ou on lit un fichier comme entrée.', table: [['Opérateur', 'Effet'], ['>', 'stdout vers un fichier (écrase)'], ['>>', 'stdout ajouté à la fin'], ['2>', 'stderr vers un fichier'], ['&> ou > f 2>&1', 'les deux flux dans le même fichier'], ['<', 'le fichier devient stdin'], ['> /dev/null', 'jeter la sortie']], exemple: 'find / -name "*.conf" > resultats.txt 2> /dev/null' },
+ { t: 'Le tube', d: '10 min', html: 'Le tube | branche la sortie d’une commande sur l’entrée de la suivante, sans fichier intermédiaire. On construit une chaîne de traitement de gauche à droite.', exemple: 'cat /var/log/auth.log | grep "Failed password" | wc -l' },
+ { t: 'La boîte à outils', d: '20 min', html: '', table: [['Commande', 'Rôle', 'Exemple'], ['grep', 'garder les lignes qui correspondent', 'grep -i erreur syslog'], ['cut', 'extraire des colonnes', 'cut -d: -f1,7 /etc/passwd'], ['sort', 'trier', 'sort -n, sort -rn'], ['uniq -c', 'compter les lignes identiques consécutives', 'sort | uniq -c'], ['wc -l', 'compter les lignes', ''], ['head / tail', 'début / fin', 'tail -f pour suivre en direct'], ['awk', 'traiter par colonnes', "awk '{print $1}'"], ['sed', 'remplacer', "sed 's/http/https/g'"]], attention: 'uniq ne regroupe que les lignes consécutives : il faut presque toujours trier avant avec sort.' },
+ { t: 'Un cas réel : repérer une attaque SSH', d: '15 min', html: 'Objectif : trouver les adresses IP qui ont le plus échoué à se connecter.', exemple: "grep 'Failed password' /var/log/auth.log \\\n | awk '{print $(NF-3)}' \\\n | sort | uniq -c | sort -rn | head -5\n\n 412 203.0.113.42\n 87 198.51.100.7\n 12 192.0.2.19" }],
+ synthese: ['> écrase, >> ajoute, 2> capture les erreurs', '| enchaîne les traitements', 'sort | uniq -c | sort -rn : le classement le plus utile de l’administrateur', 'tail -f pour suivre un journal en direct'],
+ qcm: [
+ ['Où va l’erreur de ls /inexistant > sortie.txt ?', ['Dans sortie.txt', 'À l’écran', 'Nulle part', 'Dans /dev/null'], 1, '> ne redirige que stdout ; stderr s’affiche.'],
+ ['Comment jeter à la fois la sortie et les erreurs ?', ['> /dev/null', '2> /dev/null', '&> /dev/null', '| null'], 2, '&> redirige les deux flux.'],
+ ['Que fait cut -d: -f1 /etc/passwd ?', ['Supprime la ligne 1', 'Affiche la 1re colonne séparée par :', 'Compte les lignes', 'Trie'], 1, '-d = séparateur, -f = champ.'],
+ ['Pourquoi trier avant uniq -c ?', ['Pour aller plus vite', 'uniq ne regroupe que les lignes consécutives', 'Ce n’est pas utile', 'Pour supprimer les doublons'], 1, 'Sans tri, les doublons dispersés ne sont pas regroupés.'],
+ ['Quelle commande suit un journal en temps réel ?', ['head -f', 'tail -f', 'cat -f', 'less -r'], 1, 'tail -f affiche les nouvelles lignes au fil de l’eau.'],
+ ['Que fait sed "s/a/b/g" f.txt ?', ['Supprime a', 'Remplace tous les a par b à l’affichage', 'Modifie le fichier sur disque', 'Compte les a'], 1, 'Sans -i, sed ne modifie pas le fichier.']],
+ td: [
+ { n: 'Échauffement', c: 'Enregistrer la liste de /etc dans liste.txt, puis y ajouter celle de /var.', r: 'ls /etc > liste.txt && ls /var >> liste.txt' },
+ { n: 'Application', c: 'Afficher les comptes qui utilisent /bin/bash, avec seulement leur nom.', r: 'grep "/bin/bash$" /etc/passwd | cut -d: -f1' },
+ { n: 'Application', c: 'Dans acces.log (format Apache), classer les 10 pages les plus demandées.', r: "awk '{print $7}' acces.log | sort | uniq -c | sort -rn | head -10" },
+ { n: 'Approfondissement', c: 'Compter les erreurs 404 par heure dans acces.log.', r: "awk '$9 == 404 {print substr($4, 14, 2)}' acces.log | sort | uniq -c" }],
+ tp: { type: 'IDE Bash', url: 'apercu-ide.html?ex=bash-tp', desc: 'Scripts Bash sur de vrais journaux, vérifiés par des tests.', etapes: ['Compter les connexions échouées', 'Classer les IP suspectes', 'Écrire un rapport dans un fichier', 'Bonus : alerte si plus de 100 échecs'] },
+ plusLoin: [['Le jeu OverTheWire Bandit (niveaux 10 à 20)', 'https://overthewire.org/wargames/bandit/'], ['Défis « Linux Shell » sur HackerRank', 'https://www.hackerrank.com/domains/shell']] },
+
+{ id: 'osi', match: /OSI|TCP\/IP|modèle en couches|encapsulation|Internet : IP/i,
+ titre: 'Modèles OSI et TCP/IP, encapsulation', duree: '4 h (CM 1 h 30 · TD 1 h · TP 1 h 30)', niveau: 'SNT · BTS SIO · BTS CIEL · BUT R&T S1',
+ prerequis: ['Binaire et hexadécimal'],
+ competences: ['BTS SIO · Bloc 1 · Exploiter les éléments d’un réseau', 'BTS CIEL · C03 · Analyser un réseau', 'BUT R&T · Compétence « Connecter »'],
+ intro: 'Quand un réseau tombe en panne, l’administrateur raisonne couche par couche : le câble est-il branché ? le switch voit-il la carte ? l’adresse IP est-elle bonne ? le service écoute-t-il ? Le modèle en couches est d’abord une méthode de diagnostic.',
+ cm: [
+ { t: 'Pourquoi un modèle en couches', d: '10 min', html: 'Communiquer suppose de régler beaucoup de problèmes : transmettre des bits, les adresser, les acheminer, les remettre en ordre, les présenter à l’application. Chaque couche règle un problème et offre un service à la couche du dessus, sans connaître le détail des autres.' },
+ { t: 'Les 7 couches OSI', d: '20 min', html: '', table: [['N°', 'Couche', 'Rôle', 'Unité', 'Exemples'], ['7', 'Application', 'service rendu à l’utilisateur', 'données', 'HTTP, DNS, SSH, SMTP'], ['6', 'Présentation', 'format, chiffrement', 'données', 'TLS, UTF-8'], ['5', 'Session', 'dialogue', 'données', 'RPC'], ['4', 'Transport', 'bout en bout, ports', 'segment', 'TCP, UDP'], ['3', 'Réseau', 'adressage logique, routage', 'paquet', 'IP, ICMP'], ['2', 'Liaison', 'accès au support, MAC', 'trame', 'Ethernet, Wi-Fi'], ['1', 'Physique', 'signal', 'bit', 'RJ45, fibre, radio']] },
+ { t: 'Le modèle TCP/IP', d: '10 min', html: 'Le modèle réellement implémenté compte 4 couches : Accès réseau (OSI 1-2), Internet (3), Transport (4), Application (5-7).' },
+ { t: 'L’encapsulation', d: '20 min', html: 'À l’émission, chaque couche ajoute son en-tête aux données reçues de la couche supérieure. À la réception, chaque couche lit et retire le sien.', exemple: '[ HTTP : GET /index.html ]\n[ TCP : port src 51234 → dst 443 ][ HTTP … ]\n[ IP : 192.168.10.65 → 93.184.216.34 ][ TCP … ][ HTTP … ]\n[ Eth : MAC src → MAC passerelle ][ IP … ][ TCP … ][ HTTP … ][ FCS ]' },
+ { t: 'Les équipements par couche', d: '10 min', html: 'Hub : couche 1, répète le signal. Switch : couche 2, commute selon les adresses MAC. Routeur : couche 3, achemine selon les adresses IP. Pare-feu : couches 3-4, filtre IP et ports (voire 7 pour un pare-feu applicatif).' },
+ { t: 'Diagnostiquer couche par couche', d: '15 min', html: 'On part du bas : ip link (lien actif ?), ip addr (adresse ?), ping la passerelle (couche 3), ss -tlnp (le service écoute-t-il ?), curl (l’application répond-elle ?).', attention: 'Un ping qui échoue ne prouve pas que la machine est éteinte : ICMP est souvent filtré par les pare-feux.' }],
+ synthese: ['OSI 7 couches, TCP/IP 4 couches', 'bit → trame → paquet → segment → données', 'MAC couche 2, IP couche 3, port couche 4', 'On diagnostique toujours de bas en haut'],
+ qcm: [
+ ['À quelle couche travaille un switch classique ?', ['1', '2', '3', '4'], 1, 'Il commute selon les adresses MAC.'],
+ ['Quelle est l’unité de la couche Transport ?', ['Trame', 'Paquet', 'Segment', 'Bit'], 2, 'TCP et UDP manipulent des segments (datagrammes pour UDP).'],
+ ['Le port 443 est une information de couche :', ['2', '3', '4', '7'], 2, 'Les ports sont gérés par la couche Transport.'],
+ ['Quel protocole n’est PAS de couche application ?', ['DNS', 'SSH', 'ICMP', 'SMTP'], 2, 'ICMP accompagne IP, couche 3.'],
+ ['Dans une trame Ethernet, l’adresse MAC de destination est celle :', ['du serveur web distant', 'de la passerelle ou du voisin direct', 'du DNS', 'du switch'], 1, 'La MAC change à chaque saut, l’IP de destination reste la même.'],
+ ['Combien de couches compte le modèle TCP/IP ?', ['3', '4', '5', '7'], 1, 'Accès réseau, Internet, Transport, Application.'],
+ ['Un poste a une IP mais n’accède pas à Internet. Première vérification ?', ['Réinstaller', 'ping la passerelle', 'Changer le câble', 'Vider le cache DNS'], 1, 'On teste la couche 3 vers la passerelle avant d’aller plus haut.']],
+ td: [
+ { n: 'Échauffement', c: 'Classer par couche OSI : HTTP, IP, switch, TCP, câble RJ45, routeur, TLS, Wi-Fi.', r: '7 · 3 · 2 · 4 · 1 · 3 · 6 · 1-2' },
+ { n: 'Application', c: 'Dessiner l’encapsulation d’une requête DNS du poste 192.168.1.20 vers 1.1.1.1.', r: 'DNS (requête) → UDP (port src aléatoire → 53) → IP (192.168.1.20 → 1.1.1.1) → Ethernet (MAC poste → MAC box)' },
+ { n: 'Application', c: 'Un utilisateur ne peut pas ouvrir intranet.lycee.fr. Proposer une démarche de diagnostic en 5 commandes, de bas en haut.', r: 'ip link · ip addr · ping passerelle · nslookup intranet.lycee.fr · curl -I https://intranet.lycee.fr' },
+ { n: 'Approfondissement', c: 'Expliquer pourquoi l’adresse MAC de destination change à chaque routeur traversé alors que l’adresse IP de destination reste la même.', r: 'La couche 2 ne sert qu’à atteindre le voisin direct ; chaque routeur ré-encapsule dans une nouvelle trame. La couche 3 porte l’adresse finale.' }],
+ tp: { type: 'Lab VM', url: 'apercu-labs.html', desc: 'Capturer du trafic avec tcpdump et reconnaître chaque en-tête.', etapes: ['Lancer tcpdump sur eth0', 'Faire un curl vers un site', 'Identifier Ethernet, IP, TCP, HTTP', 'Comparer avec une requête DNS en UDP'] },
+ plusLoin: [['Cisco Networking Academy · cours gratuits', 'https://www.netacad.com/'], ['RFC 1122 (Requirements for Internet Hosts)', 'https://www.rfc-editor.org/rfc/rfc1122']] },
+
+{ id: 'sql', match: /SQL|SELECT|requête|bases de données relationnelles|jointure/i,
+ titre: 'SQL : interroger une base de données relationnelle', duree: '6 h (CM 2 h · TD 2 h · TP 2 h)', niveau: 'NSI Terminale · BTS SIO SLAM · BUT Informatique · MIAGE',
+ prerequis: ['Notion de tableau de données'],
+ competences: ['NSI Tle · Bases de données : langage SQL', 'BTS SIO SLAM · Bloc 2 · Concevoir et exploiter une base de données', 'BUT Info · Compétence « Gérer des données »'],
+ intro: 'Presque toutes les applications stockent leurs données dans une base relationnelle : un ENT, un site marchand, Syllabus elle-même. SQL est le langage standard pour les interroger. Il se lit presque comme une phrase.',
+ cm: [
+ { t: 'Le modèle relationnel', d: '20 min', html: 'Une base est un ensemble de tables (relations). Chaque ligne est un enregistrement, chaque colonne un attribut typé. La clé primaire identifie une ligne de façon unique ; une clé étrangère référence la clé primaire d’une autre table.', table: [['eleves', 'id (PK)', 'nom', 'prenom', 'classe_id (FK)'], ['', '1', 'Martin', 'Léa', '3'], ['', '2', 'Kaci', 'Inès', '3']] },
+ { t: 'Sélectionner : SELECT … FROM', d: '15 min', html: 'On choisit les colonnes, puis la table. * sélectionne toutes les colonnes, DISTINCT supprime les doublons, AS renomme.', exemple: 'SELECT nom, prenom FROM eleves;\nSELECT DISTINCT ville FROM eleves;\nSELECT nom AS "Nom de famille" FROM eleves;' },
+ { t: 'Filtrer et trier', d: '20 min', html: 'WHERE filtre avec =, <>, <, >, BETWEEN, IN, LIKE (% = n’importe quelle suite), IS NULL, combinés par AND, OR, NOT. ORDER BY trie (ASC, DESC), LIMIT restreint.', exemple: "SELECT nom, moyenne FROM eleves\nWHERE classe_id = 3 AND moyenne >= 10\nORDER BY moyenne DESC\nLIMIT 5;" },
+ { t: 'Agréger : COUNT, AVG, GROUP BY', d: '20 min', html: 'Les fonctions d’agrégat calculent sur un ensemble de lignes : COUNT, SUM, AVG, MIN, MAX. GROUP BY forme des groupes, HAVING filtre les groupes (WHERE filtre les lignes avant).', exemple: 'SELECT classe_id, COUNT(*) AS effectif, AVG(moyenne) AS moy\nFROM eleves\nGROUP BY classe_id\nHAVING COUNT(*) > 20;', attention: 'Toute colonne du SELECT qui n’est pas agrégée doit figurer dans le GROUP BY.' },
+ { t: 'Joindre des tables', d: '25 min', html: 'La jointure relie deux tables par leurs clés. INNER JOIN garde les lignes qui ont une correspondance des deux côtés ; LEFT JOIN garde toutes les lignes de gauche, avec NULL s’il n’y a pas de correspondance.', exemple: 'SELECT e.nom, c.libelle\nFROM eleves e\nJOIN classes c ON e.classe_id = c.id;\n\n-- Classes sans aucun élève :\nSELECT c.libelle FROM classes c\nLEFT JOIN eleves e ON e.classe_id = c.id\nWHERE e.id IS NULL;' },
+ { t: 'Modifier les données', d: '15 min', html: 'INSERT INTO ajoute, UPDATE … SET … WHERE modifie, DELETE FROM … WHERE supprime.', attention: 'Un UPDATE ou un DELETE sans WHERE touche toutes les lignes. On teste toujours d’abord le WHERE avec un SELECT.' },
+ { t: 'Sécurité : l’injection SQL', d: '10 min', html: 'Construire une requête en collant du texte saisi par l’utilisateur permet de détourner la requête (\' OR 1=1 --). On utilise toujours des requêtes préparées avec paramètres.' }],
+ synthese: ['SELECT colonnes FROM table WHERE condition ORDER BY tri', 'WHERE filtre les lignes, HAVING filtre les groupes', 'JOIN … ON relie clé étrangère et clé primaire', 'Jamais de DELETE ni d’UPDATE sans WHERE', 'Requêtes préparées contre l’injection'],
+ qcm: [
+ ['Quelle clause filtre les groupes après un GROUP BY ?', ['WHERE', 'HAVING', 'ORDER BY', 'LIMIT'], 1, 'HAVING s’applique aux groupes.'],
+ ['Que renvoie SELECT COUNT(*) FROM eleves WHERE moyenne IS NULL ?', ['Les élèves sans moyenne', 'Le nombre d’élèves sans moyenne', 'Une erreur', '0 toujours'], 1, 'COUNT compte les lignes retenues.'],
+ ['Quelle jointure garde les classes sans élève ?', ['INNER JOIN', 'LEFT JOIN depuis classes', 'CROSS JOIN', 'Aucune'], 1, 'LEFT JOIN conserve toutes les lignes de la table de gauche.'],
+ ['LIKE "Ma%" correspond à :', ['Ma exactement', 'tout texte commençant par Ma', 'tout texte finissant par Ma', 'tout texte contenant %'], 1, '% remplace n’importe quelle suite de caractères.'],
+ ['Que se passe-t-il avec DELETE FROM eleves; ?', ['Rien', 'Toutes les lignes sont supprimées', 'La table est supprimée', 'Erreur de syntaxe'], 1, 'Sans WHERE, toutes les lignes partent. La table reste.'],
+ ['Quel est le rôle d’une clé étrangère ?', ['Chiffrer', 'Référencer une ligne d’une autre table', 'Accélérer les tris', 'Rendre une colonne unique'], 1, 'Elle garantit l’intégrité référentielle.'],
+ ['Comment se protéger de l’injection SQL ?', ['Masquer les erreurs', 'Requêtes préparées', 'Mettre des guillemets', 'Utiliser HTTPS'], 1, 'Les paramètres ne sont jamais interprétés comme du SQL.'],
+ ['Classer les élèves du meilleur au moins bon :', ['ORDER BY moyenne', 'ORDER BY moyenne DESC', 'SORT BY moyenne', 'GROUP BY moyenne'], 1, 'DESC = décroissant.']],
+ td: [
+ { n: 'Échauffement', c: 'Afficher nom et prénom des élèves de la classe 3, triés par nom.', r: 'SELECT nom, prenom FROM eleves WHERE classe_id = 3 ORDER BY nom;' },
+ { n: 'Application', c: 'Afficher l’effectif et la moyenne de chaque classe, avec son libellé.', r: 'SELECT c.libelle, COUNT(e.id), AVG(e.moyenne)\nFROM classes c LEFT JOIN eleves e ON e.classe_id = c.id\nGROUP BY c.libelle;' },
+ { n: 'Application', c: 'Lister les élèves qui n’ont rendu aucun devoir (tables eleves, rendus).', r: 'SELECT e.nom FROM eleves e\nLEFT JOIN rendus r ON r.eleve_id = e.id\nWHERE r.id IS NULL;' },
+ { n: 'Approfondissement', c: 'Afficher les classes dont la moyenne est supérieure à la moyenne générale.', r: 'SELECT classe_id, AVG(moyenne) FROM eleves GROUP BY classe_id\nHAVING AVG(moyenne) > (SELECT AVG(moyenne) FROM eleves);' },
+ { n: 'Approfondissement', c: 'Réécrire en requête préparée (PHP PDO) : "SELECT * FROM users WHERE login = \'" . $login . "\'"', r: '$st = $pdo->prepare("SELECT * FROM users WHERE login = ?");\n$st->execute([$login]);' }],
+ tp: { type: 'IDE SQL', url: 'apercu-ide.html?ex=sql-select', desc: 'Une base SQLite dans le navigateur, requêtes vérifiées automatiquement.', etapes: ['Explorer les tables', '8 requêtes SELECT progressives', '3 jointures', '2 requêtes d’agrégat', 'Défi : le palmarès par classe'] },
+ plusLoin: [['SQLBolt · exercices interactifs', 'https://sqlbolt.com/'], ['Défis SQL sur HackerRank', 'https://www.hackerrank.com/domains/sql'], ['DataCamp · Introduction to SQL', 'https://www.datacamp.com/courses/introduction-to-sql']] }
+]);
diff --git a/design/js/contenus-3.js b/design/js/contenus-3.js
new file mode 100644
index 0000000..6bbd620
--- /dev/null
+++ b/design/js/contenus-3.js
@@ -0,0 +1,92 @@
+// Cours complets · lot 3 : Python, Web, cryptographie
+window.CONTENUS_PRO = (window.CONTENUS_PRO || []).concat([
+{ id: 'python', match: /Python|programmation|boucle|variable|algorithm/i,
+ titre: 'Python : variables, conditions, boucles et fonctions', duree: '6 h (CM 2 h · TD 2 h · TP 2 h)', niveau: 'SNT · NSI Première · BTS SIO SLAM · BUT S1',
+ prerequis: ['Aucun'],
+ competences: ['NSI 1re · Langages et programmation', 'BTS SIO SLAM · Bloc 2 · Développer une solution applicative', 'BUT Info · Compétence « Réaliser »'],
+ intro: 'Python est le langage d’enseignement du lycée à l’université, mais aussi celui des administrateurs, des data engineers et de l’IA. Sa syntaxe courte permet de se concentrer sur l’essentiel : décomposer un problème en instructions.',
+ cm: [
+ { t: 'Variables et types', d: '20 min', html: 'Une variable associe un nom à une valeur. Le type est déduit de la valeur.', table: [['Type', 'Exemple', 'Usage'], ['int', '17', 'entiers'], ['float', '3.5', 'nombres à virgule'], ['str', '"Léa"', 'texte'], ['bool', 'True', 'vrai / faux'], ['list', '[12, 15, 9]', 'suite modifiable'], ['dict', '{"nom": "Léa"}', 'associations clé → valeur']], exemple: 'age = 17\nnom = "Léa"\nprint(f"{nom} a {age} ans") # Léa a 17 ans\nprint(type(age)) # input() lit une saisie, toujours sous forme de texte : on la convertit avec int() ou float().', attention: 'input() renvoie une chaîne : "3" + "4" donne "34", pas 7.' },
+ { t: 'Conditions', d: '20 min', html: 'Le bloc exécuté dépend d’une condition. Python délimite les blocs par l’indentation (4 espaces).', exemple: 'note = float(input("Note : "))\nif note >= 16:\n print("Très bien")\nelif note >= 10:\n print("Admis")\nelse:\n print("À retravailler")' },
+ { t: 'Boucle for', d: '20 min', html: 'for parcourt une séquence. range(n) produit 0, 1, …, n − 1 ; range(a, b, pas) va de a à b − 1.', exemple: 'notes = [12, 15, 9, 18]\ntotal = 0\nfor n in notes:\n total += n\nprint(total / len(notes)) # 13.5' },
+ { t: 'Boucle while', d: '15 min', html: 'while répète tant que la condition est vraie. On l’utilise quand on ne connaît pas le nombre de tours à l’avance.', exemple: 'essais = 0\nmdp = ""\nwhile mdp != "paillasse" and essais < 3:\n mdp = input("Mot de passe : ")\n essais += 1', attention: 'Si la condition ne devient jamais fausse, la boucle est infinie. Ctrl+C l’interrompt.' },
+ { t: 'Fonctions', d: '20 min', html: 'Une fonction regroupe des instructions réutilisables. Elle reçoit des paramètres et renvoie un résultat avec return. On la documente avec une docstring et on la teste avec assert.', exemple: 'def moyenne(valeurs):\n """Renvoie la moyenne d\'une liste non vide."""\n return sum(valeurs) / len(valeurs)\n\nassert moyenne([10, 20]) == 15' },
+ { t: 'Listes et dictionnaires', d: '10 min', html: 'Une liste s’indexe à partir de 0 : notes[0], notes[-1] (dernier), notes.append(14). Un dictionnaire associe des clés à des valeurs : eleve["nom"].' }],
+ synthese: ['L’indentation délimite les blocs', 'input() renvoie du texte : convertir avec int() ou float()', 'for quand on connaît la séquence, while sinon', 'Une fonction = paramètres + return + tests'],
+ qcm: [
+ ['Que vaut 7 // 2 ?', ['3.5', '3', '4', '1'], 1, '// est la division entière.'],
+ ['Que vaut 7 % 2 ?', ['1', '3', '3.5', '0'], 0, '% donne le reste.'],
+ ['Combien de tours fait for i in range(2, 10, 3) ?', ['2', '3', '4', '8'], 1, 'i prend 2, 5, 8.'],
+ ['Que renvoie input() ?', ['Un int', 'Un str', 'Un float', 'Un bool'], 1, 'Toujours une chaîne.'],
+ ['Que vaut notes[-1] pour notes = [12, 15, 9] ?', ['12', '15', '9', 'Erreur'], 2, '-1 désigne le dernier élément.'],
+ ['Que fait return dans une fonction ?', ['Affiche une valeur', 'Renvoie une valeur et sort de la fonction', 'Recommence la fonction', 'Rien'], 1, 'return termine la fonction avec un résultat.'],
+ ['Quelle boucle convient pour « redemander tant que la saisie est invalide » ?', ['for', 'while', 'range', 'if'], 1, 'On ne connaît pas le nombre de tours.'],
+ ['Que produit "3" + "4" ?', ['7', '"34"', 'Erreur', '"7"'], 1, 'Concaténation de chaînes.']],
+ td: [
+ { n: 'Échauffement', c: 'Écrire un programme qui demande l’année de naissance et affiche l’âge en 2026.', r: 'annee = int(input("Année : "))\nprint(2026 - annee)' },
+ { n: 'Application', c: 'Écrire est_pair(n) qui renvoie True si n est pair, puis afficher les nombres pairs de 1 à 30.', r: 'def est_pair(n):\n return n % 2 == 0\n\nfor i in range(1, 31):\n if est_pair(i):\n print(i)' },
+ { n: 'Application', c: 'Écrire mention(note) qui renvoie « TB », « B », « AB », « Passable » ou « Insuffisant ».', r: 'def mention(n):\n if n >= 16: return "TB"\n if n >= 14: return "B"\n if n >= 12: return "AB"\n if n >= 10: return "Passable"\n return "Insuffisant"' },
+ { n: 'Approfondissement', c: 'Écrire maximum(liste) sans utiliser max(), avec ses tests.', r: 'def maximum(l):\n m = l[0]\n for x in l:\n if x > m:\n m = x\n return m\n\nassert maximum([3, 9, 2]) == 9' },
+ { n: 'Approfondissement', c: 'Compter le nombre d’occurrences de chaque mot d’une phrase avec un dictionnaire.', r: 'compte = {}\nfor mot in phrase.split():\n compte[mot] = compte.get(mot, 0) + 1' }],
+ tp: { type: 'IDE Python', url: 'apercu-ide.html?ex=py-pair', desc: 'Exercices corrigés par des tests automatiques, directement dans le navigateur.', etapes: ['Parité et multiples', 'Somme et moyenne d’une liste', 'Compter les voyelles', 'Jeu du nombre mystère', 'Défi : FizzBuzz'] },
+ plusLoin: [['France-IOI · parcours Python', 'https://www.france-ioi.org/'], ['HackerRank · Python', 'https://www.hackerrank.com/domains/python'], ['DataCamp · Introduction to Python', 'https://www.datacamp.com/courses/intro-to-python-for-data-science']] },
+
+{ id: 'web', match: /HTML|CSS|Le Web|HTTP|serveur web|Apache/i,
+ titre: 'Le Web : HTTP, HTML, CSS et serveur web', duree: '5 h (CM 1 h 30 · TD 1 h 30 · TP 2 h)', niveau: 'SNT · NSI Première · BTS SIO · BTS CIEL',
+ prerequis: ['Modèles OSI et TCP/IP (conseillé)'],
+ competences: ['SNT · Le Web', 'NSI 1re · Interactions entre l’homme et la machine sur le Web', 'BTS SIO · Bloc 1 · Mettre à disposition un service'],
+ intro: 'Chaque fois que vous ouvrez une page, votre navigateur échange des messages HTTP avec un serveur, puis affiche du HTML mis en forme par du CSS. Comprendre cet échange, c’est pouvoir créer un site, mais aussi le dépanner et le sécuriser.',
+ cm: [
+ { t: 'URL et architecture client-serveur', d: '15 min', html: 'Le client (navigateur) envoie une requête, le serveur (Apache, Nginx) répond. L’URL précise tout : https://www.lycee.fr:443/cours/index.html?id=3 = protocole, nom d’hôte, port, chemin, paramètres.' },
+ { t: 'Le protocole HTTP', d: '20 min', html: 'HTTP est un protocole texte. La requête contient une méthode, un chemin et des en-têtes ; la réponse contient un code d’état, des en-têtes et un corps.', exemple: 'GET /index.html HTTP/1.1\nHost: www.lycee.fr\n\nHTTP/1.1 200 OK\nContent-Type: text/html; charset=utf-8\n\n…', table: [['Code', 'Sens'], ['200', 'OK'], ['301 / 302', 'redirection'], ['403', 'accès interdit'], ['404', 'ressource introuvable'], ['500', 'erreur du serveur']] },
+ { t: 'HTML : la structure', d: '20 min', html: 'HTML décrit le sens du contenu avec des balises : titres <h1> à <h6>, paragraphes, listes, liens, images, formulaires. Une page bien structurée est lisible par les moteurs de recherche et les lecteurs d’écran.', exemple: '\n\nHébergé sur Debian.
\n\n' }, + { t: 'CSS : la présentation', d: '20 min', html: 'Une règle CSS associe un sélecteur à des déclarations. Sélecteurs : balise (p), classe (.carte), identifiant (#menu). La mise en page moderne repose sur display: flex et display: grid.', exemple: '.carte {\n border: 2px solid #000;\n padding: 16px;\n}\n.grille { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }' },
+ { t: 'Formulaires : GET et POST', d: '10 min', html: 'Un formulaire envoie des données au serveur. GET les place dans l’URL (recherche, filtres). POST les place dans le corps de la requête (connexion, envoi de fichier).', attention: 'Un mot de passe ne doit jamais passer en GET : il finirait dans l’historique et les journaux du serveur.' },
+ { t: 'Héberger : le serveur web', d: '15 min', html: 'Sous Debian, apt install apache2 installe le serveur ; les pages sont dans /var/www/html, la configuration dans /etc/apache2, les journaux dans /var/log/apache2. HTTPS ajoute TLS et un certificat (Let’s Encrypt).' }],
+ synthese: ['Client → requête HTTP → serveur → réponse avec code', 'HTML = structure, CSS = présentation', 'GET dans l’URL, POST dans le corps', 'Apache : /var/www/html et /var/log/apache2'],
+ qcm: [
+ ['Que signifie le code 403 ?', ['Introuvable', 'Accès interdit', 'Erreur serveur', 'Redirection'], 1, '403 Forbidden.'],
+ ['Quelle partie de l’URL est ?id=3 ?', ['Le chemin', 'Les paramètres', 'Le port', 'Le protocole'], 1, 'La chaîne de requête.'],
+ ['Quelle balise pour le titre principal ?', ['df["note"] * 2 s’applique à toute la colonne en une instruction, bien plus vite qu’une boucle Python.' },
+ { t: 'Charger des données réelles', d: '', html: 'pd.read_csv accepte de nombreux paramètres indispensables avec les exports français : sep=";", decimal=",", encoding="utf-8-sig" ou "latin-1", parse_dates, dtype. On inspecte toujours avant de calculer : df.head(), df.info() (types et valeurs manquantes), df.describe() (statistiques).', exemple: 'import pandas as pd\ndf = pd.read_csv("notes.csv", sep=";", decimal=",", encoding="utf-8-sig", parse_dates=["date"], dayfirst=True)\ndf.info()' },
+ { t: 'Sélectionner et filtrer', d: '', html: 'df["col"] sélectionne une colonne, df[["a","b"]] plusieurs. df.loc[lignes, colonnes] sélectionne par étiquette, df.iloc par position. Le filtrage utilise des masques booléens combinés par &, | et ~, chaque condition entre parenthèses.', exemple: 'df.loc[(df["classe"] == "SIO1") & (df["note"] < 8), ["nom", "matiere", "note"]]', attention: 'Modifier le résultat d’un filtre (df[df.note < 8]["note"] = 8) ne modifie pas df et produit un avertissement SettingWithCopy. On écrit df.loc[df.note < 8, "note"] = 8.' },
+ { t: 'Nettoyer', d: '', html: 'Les valeurs manquantes sont NaN. isna().sum() les compte, dropna retire les lignes, fillna les remplace. Le choix est métier : une note absente n’est pas un zéro. drop_duplicates retire les doublons, str.strip().str.upper() normalise le texte, astype et pd.to_numeric(errors="coerce") convertissent les types en transformant les valeurs invalides en NaN.' },
+ { t: 'Agréger et joindre', d: '', html: 'groupby découpe, applique, combine, exactement comme GROUP BY en SQL : df.groupby("classe")["note"].agg(["mean","median","count"]). pivot_table produit un tableau croisé. merge joint deux DataFrame comme un JOIN, avec how="left" pour garder toutes les lignes de gauche et validate="m:1" pour vérifier qu’on ne multiplie pas les lignes par erreur.' },
+ { t: 'Performances et export', d: '', html: 'Sur de gros volumes : lire seulement les colonnes utiles (usecols), typer le texte répétitif en category, éviter apply ligne à ligne au profit des opérations vectorisées, et stocker les résultats intermédiaires en Parquet, format colonne compressé et typé, bien plus rapide que le CSV. L’export final se fait avec to_csv, to_excel ou directement dans une base avec to_sql.' }
+ ],
+ synthese: ['DataFrame = colonnes typées partageant un index ; opérations vectorisées', 'read_csv avec sep, decimal, encoding, parse_dates', 'Inspecter : head, info, describe, isna().sum()', 'loc pour sélectionner et modifier ; masques entre parenthèses', 'Valeurs manquantes : décision métier', 'groupby, pivot_table, merge avec validate', 'Parquet et category pour les gros volumes'],
+ qcm: [
+ ['Quel paramètre pour lire « 12,5 » comme un nombre ?', ['sep=","', 'decimal=","', 'dtype=float', 'encoding'], 1, 'Virgule décimale française.'],
+ ['Que montre df.info() ?', ['Les 5 premières lignes', 'Types et nombre de valeurs non nulles par colonne', 'La moyenne', 'Le graphique'], 1, 'Premier réflexe.'],
+ ['Comment combiner deux conditions ?', ['and', '(c1) & (c2)', 'c1 && c2', 'c1 + c2'], 1, 'Opérateurs bit à bit sur des masques.'],
+ ['Une note absente doit-elle devenir 0 ?', ['Toujours', 'Non, c’est une décision métier (absence ≠ zéro)', 'Oui avec fillna', 'Peu importe'], 1, 'Elle fausserait la moyenne.'],
+ ['Équivalent pandas de GROUP BY ?', ['merge', 'groupby', 'pivot', 'concat'], 1, 'Découper, appliquer, combiner.'],
+ ['Pourquoi préférer Parquet au CSV pour les fichiers intermédiaires ?', ['Plus lisible', 'Typé, compressé, lecture par colonne rapide', 'Obligatoire', 'Compatible Excel'], 1, 'Format colonne.']
+ ],
+ td: [
+ { n: 'Application', c: 'Charger l’export notes.csv (point-virgule, virgule décimale), afficher le nombre de notes manquantes par matière, puis la moyenne par classe et par matière en tableau croisé.', r: 'df = pd.read_csv("notes.csv", sep=";", decimal=",")\ndf.groupby("matiere")["note"].apply(lambda s: s.isna().sum())\ndf.pivot_table(index="classe", columns="matiere", values="note", aggfunc="mean").round(1)' },
+ { n: 'Application', c: 'Joindre notes.csv et eleves.csv sur l’identifiant, en vérifiant qu’aucun élève n’est dupliqué, et lister les élèves sans aucune note.', r: 'm = eleves.merge(notes, on="id", how="left", validate="1:m")\nm[m["note"].isna()].drop_duplicates("id")[["nom","prenom"]]' },
+ { n: 'Approfondissement', c: 'Repérer les élèves dont la moyenne a baissé de plus de 3 points entre le 1er et le 2e trimestre.', r: 'p = df.pivot_table(index="id", columns="trimestre", values="note", aggfunc="mean")\np[(p[1] - p[2]) > 3]' }
+ ],
+ tp: { type: 'IDE Python', url: 'apercu-ide.html', desc: 'Jeu de données anonymisé d’un établissement, tests automatiques.', etapes: ['Charger et inspecter', 'Nettoyer types et doublons', 'Agrégats par classe', 'Jointure avec les effectifs', 'Exporter un bilan en CSV'] },
+ plusLoin: [['Documentation pandas', 'https://pandas.pydata.org/docs/'], ['DataCamp · Data Manipulation with pandas', 'https://www.datacamp.com/courses/data-manipulation-with-pandas'], ['data.gouv.fr · jeux de données ouverts', 'https://www.data.gouv.fr/']] },
+plus: { cas: { titre: '', texte: '' },
+ resolu: { enonce: 'Le tableau de bord du conseil de classe affiche une moyenne générale de 4,2 pour la SIO1, alors que les enseignants constatent des moyennes autour de 12. Trouver et corriger l’erreur du script d’analyse.', etapes: [
+ ['Inspecter les types', 'df.info()\n note 1840 non-null object\n→ La colonne note est du texte : read_csv n’a pas reconnu la virgule décimale.'],
+ ['Voir ce qui a été calculé', 'df["note"].head(3)\n0 12,5\n1 14\n2 abs\n→ Des valeurs « abs » et des virgules. Le script faisait pd.to_numeric(errors="coerce") : « 12,5 » et « abs » devenaient NaN puis étaient remplacés par 0 avec fillna(0).'],
+ ['Corriger le chargement', 'df = pd.read_csv("notes.csv", sep=";", decimal=",", na_values=["abs", "ABS", "disp"])\ndf["note"].dtype\nfloat64\n→ Les absences deviennent des valeurs manquantes, pas des zéros.'],
+ ['Recalculer', 'df.groupby("classe")["note"].mean().round(2)\nSIO1 11.87\n→ Moyenne cohérente avec le terrain.'],
+ ['Prévenir', '→ Ajout de contrôles automatiques dans le script : assert df["note"].between(0, 20).all(), et journalisation du nombre d’absences traitées. Aucun fillna(0) sur des notes.']
+ ] },
+ erreurs: ['Oublier decimal="," sur un export français', 'Remplacer les absences par zéro', 'Modifier un filtre au lieu d’utiliser loc', 'Boucler ligne par ligne avec iterrows', 'Joindre sans vérifier les doublons', 'Calculer sans avoir regardé info()'],
+ memo: [['Instruction', 'Usage'], ['pd.read_csv(f, sep=";", decimal=",")', 'lire un export français'], ['df.head() · df.info() · df.describe()', 'inspecter'], ['df.isna().sum()', 'valeurs manquantes par colonne'], ['df.loc[masque, cols]', 'filtrer et sélectionner'], ['df.groupby(k)[c].agg([...])', 'agréger'], ['df.pivot_table(index, columns, values)', 'tableau croisé'], ['a.merge(b, on, how, validate)', 'joindre'], ['df.drop_duplicates()', 'retirer les doublons'], ['pd.to_numeric(s, errors="coerce")', 'convertir en nombre'], ['df.to_parquet() · df.to_csv()', 'exporter']],
+ examen: { titre: 'Sujet type · 20 points', q: ['Écrire le chargement d’un export fourni. (3 pts)', 'Nettoyer les valeurs manquantes en justifiant. (4 pts)', 'Produire trois agrégats demandés. (6 pts)', 'Joindre deux tables et détecter les incohérences. (4 pts)', 'Expliquer vectorisation et Parquet. (3 pts)'], r: ['read_csv paramétré', 'na_values, pas de 0', 'groupby / pivot_table', 'merge validate, how', 'voir cours'] },
+ prof: { deroule: [['Ouverture', 'Un vrai export raté projeté'], ['Cours', 'DataFrame, chargement, inspection'], ['Pratique', 'Nettoyage dans l’IDE'], ['Pratique', 'Agrégats et jointures'], ['Clôture', 'Quiz flash']], diff: 'Élèves en difficulté : cellules à trous. Élèves avancés : Parquet, polars, DataCamp.', eval: 'Tests IDE, sujet type.' } },
+exemples: [
+ ['Inspecter un export', 'Premier chargement.', 'df.info()', 'RangeIndex: 1840 entries\n # Column Non-Null Count Dtype\n 0 nom 1840 non-null object\n 1 classe 1840 non-null object\n 2 note 1712 non-null float64\n 3 date 1840 non-null datetime64[ns]', '128 notes manquantes (absences), types corrects : on peut calculer.'],
+ ['Compter par groupe', 'Effectifs par classe.', 'df.groupby("classe")["nom"].nunique()', 'classe\nSIO1 31\nSIO2 27', 'nunique compte les élèves distincts, pas le nombre de lignes de notes.'],
+ ['Détecter des doublons', 'Un élève apparaît deux fois.', 'eleves[eleves.duplicated("ine", keep=False)]', ' ine nom prenom\n12 070123456AB MARTIN Léa\n88 070123456AB Martin Lea', 'Même identifiant INE, casse et accents différents : on normalise avant de dédoublonner.'],
+ ['Jointure qui multiplie les lignes', 'Le nombre de lignes explose après merge.', 'notes.merge(eleves, on="nom", validate="m:1")', 'MergeError: Merge keys are not unique in right dataset; not a many-to-one merge', 'Deux élèves portent le même nom : on joint sur l’identifiant, jamais sur le nom.'],
+ ['Tableau croisé', 'Bilan pour le conseil.', 'df.pivot_table(index="classe", columns="matiere", values="note", aggfunc="mean").round(1)', 'matiere Maths Réseaux Dev\nclasse\nSIO1 11.2 12.8 10.4\nSIO2 12.0 13.1 12.7', 'Le Dev de SIO1 est le point faible, piste pour le conseil.'],
+ ['Mesurer un gain de performance', 'Script lent sur 2 millions de lignes.', '%timeit df["total"] = df.apply(lambda r: r.note * r.coef, axis=1)\n%timeit df["total"] = df["note"] * df["coef"]', '8.41 s ± 120 ms\n6.2 ms ± 0.3 ms', 'La version vectorisée est plus de mille fois plus rapide.']
+],
+termes: ['pandas', 'DataFrame', 'Series', 'index', 'dtype', 'read_csv', 'loc', 'iloc', 'NaN', 'isna', 'fillna', 'dropna', 'groupby', 'agg', 'pivot_table', 'merge', 'validate', 'drop_duplicates', 'Parquet', 'category', 'vectorisé']
+});
+
+reg({
+cours: { id: 'ml', match: /apprentissage automatique|machine learning|scikit|régression|classification|intelligence artificielle|\bIA\b/i,
+ titre: 'Apprentissage automatique : du jeu de données au modèle évalué', duree: '',
+ niveau: 'NSI Terminale (k plus proches voisins) · BUT SD / Informatique · École d’ingénieurs · Master IA',
+ prerequis: ['Analyse de données avec pandas', 'Statistiques descriptives'],
+ competences: ['NSI · Algorithme des k plus proches voisins', 'BUT SD · Modéliser', 'Master · Concevoir un système d’apprentissage'],
+ intro: 'Un modèle d’apprentissage automatique apprend une règle à partir d’exemples plutôt qu’on ne la lui programme. Il détecte un courriel frauduleux, prédit le risque de décrochage d’un élève ou reconnaît un caractère manuscrit. Mais un modèle mal évalué donne des chiffres flatteurs et des décisions fausses. Ce module suit la démarche complète avec scikit-learn : préparer les données, séparer apprentissage et test, choisir un modèle, mesurer correctement, et comprendre les limites éthiques et réglementaires.',
+ cm: [
+ { t: 'Apprendre à partir d’exemples', d: '', html: 'En apprentissage supervisé, chaque exemple a des variables explicatives (X) et une cible (y) connue : on apprend à prédire y à partir de X. C’est une classification si y est une catégorie (décroche / ne décroche pas), une régression si y est un nombre (note finale). En apprentissage non supervisé, il n’y a pas de cible : on cherche une structure, par exemple des groupes d’élèves aux profils proches (clustering).' },
+ { t: 'Séparer apprentissage et test', d: '', html: 'Un modèle évalué sur les données qui ont servi à l’entraîner paraît toujours excellent : il les a apprises par cœur. On sépare donc un jeu d’apprentissage et un jeu de test jamais vu (train_test_split, souvent 80/20, stratifié pour garder la proportion des classes). Pour régler les hyperparamètres sans toucher au test, on utilise la validation croisée : l’apprentissage est découpé en k parts, chacune servant tour à tour de validation.nginx:latest ne désigne pas la même image aujourd’hui et dans six mois. En production, on fixe une version précise (nginx:1.27.2-alpine) voire le digest, pour que chaque déploiement soit reproductible.docker pull télécharge, docker push publie.', attention: 'Ne jamais utiliser le tag latest en production : un redémarrage peut récupérer silencieusement une nouvelle version majeure et casser l’application.' },
+ { t: 'Écrire un Dockerfile de production', d: '', html: 'Le Dockerfile décrit la construction d’une image. Chaque instruction produit une couche, et Docker réutilise en cache les couches dont les instructions et les fichiers n’ont pas changé. L’ordre est donc décisif : on place en premier ce qui change rarement (système, dépendances) et en dernier ce qui change souvent (code).docker run crée et démarre un conteneur à partir d’une image. Les options essentielles : -d en arrière-plan, --name pour le nommer, -p 8080:80 pour publier un port, -e pour une variable d’environnement, -v pour un volume, --restart unless-stopped pour le redémarrer automatiquement, --memory et --cpus pour le limiter.docker stop (au bout de 10 secondes, Docker envoie SIGKILL).docker rm.' },
+ { t: 'Persister les données : volumes et bind mounts', d: '', html: 'Puisque le conteneur est jetable, les données qui doivent survivre (base de données, fichiers envoyés, configuration) vont dans un volume. Un volume nommé est géré par Docker dans /var/lib/docker/volumes : c’est la solution recommandée pour les données d’application. Un bind mount monte un dossier précis de l’hôte : pratique pour la configuration ou le développement, mais il dépend de l’arborescence de l’hôte et de ses droits.-p : Docker crée alors une règle de DNAT dans netfilter vers le conteneur.docker network create), les conteneurs se trouvent par leur nom grâce au DNS intégré de Docker (127.0.0.11) : l’application joint la base de données par le nom db, sans connaître son adresse. C’est la pratique recommandée. Le mode host supprime l’isolation réseau : le conteneur utilise directement les interfaces de l’hôte.', attention: 'Les ports publiés par Docker passent par ses propres règles netfilter, avant celles d’un pare-feu comme UFW : un -p 5432:5432 expose la base de données sur Internet même si UFW semble la bloquer. On publie uniquement sur la boucle locale (-p 127.0.0.1:5432:5432) ou pas du tout, en utilisant un réseau interne.' },
+ { t: 'Sécurité des conteneurs', d: '', html: 'Appartenir au groupe docker équivaut à être root sur l’hôte : on peut lancer un conteneur qui monte / et le modifier. On réserve ce groupe aux administrateurs, ou on utilise Docker en mode rootless ou Podman.--privileged sans raison impérative, secrets passés par fichiers ou gestionnaire de secrets plutôt qu’en variables d’environnement visibles dans docker inspect, et limites de ressources pour qu’un conteneur ne puisse pas saturer l’hôte.' }
+ ],
+ synthese: ['Conteneur = processus isolé par namespaces et limité par cgroups, noyau partagé', 'Image en couches, immuable, identifiée par tag et digest ; jamais latest en production', 'Dockerfile : base minimale versionnée, multi-étapes, USER non root, .dockerignore', 'PID 1 et SIGTERM : un processus au premier plan par conteneur', 'Données dans des volumes nommés, sauvegarde avec les outils de la base', 'Réseau bridge utilisateur et DNS par nom ; attention aux ports publiés qui contournent UFW', 'Groupe docker = root ; scanner les images, limiter les ressources'],
+ qcm: [
+ ['Quels mécanismes du noyau isolent un conteneur ?', ['Hyperviseur et BIOS', 'Namespaces et cgroups', 'chroot et sudo', 'SELinux uniquement'], 1, 'Namespaces pour la vue, cgroups pour les ressources.'],
+ ['Pourquoi éviter le tag latest en production ?', ['Il est payant', 'Il peut désigner une nouvelle version à chaque pull', 'Il est lent', 'Il n’existe pas'], 1, 'Le déploiement devient non reproductible.'],
+ ['Quel est l’intérêt d’un build multi-étapes ?', ['Accélérer le réseau', 'Obtenir une image finale sans outils de compilation', 'Lancer plusieurs conteneurs', 'Chiffrer l’image'], 1, 'Image plus petite et surface d’attaque réduite.'],
+ ['Que se passe-t-il quand le processus PID 1 d’un conteneur se termine ?', ['Rien', 'Le conteneur s’arrête', 'Docker le relance toujours', 'L’hôte redémarre'], 1, 'Le conteneur vit tant que son processus principal vit.'],
+ ['Où stocker les données d’une base PostgreSQL conteneurisée ?', ['Dans la couche du conteneur', 'Dans un volume nommé', 'Dans l’image', 'Dans /tmp'], 1, 'Elles survivent à la suppression du conteneur.'],
+ ['Comment une application joint-elle la base de données sur un réseau bridge utilisateur ?', ['Par l’adresse 172.17.0.1', 'Par le nom du conteneur', 'Par localhost', 'Impossible'], 1, 'DNS intégré de Docker.'],
+ ['Pourquoi -p 5432:5432 peut-il exposer la base malgré UFW ?', ['UFW est désactivé par Docker', 'Docker insère ses règles DNAT avant celles d’UFW', 'Le port 5432 est public par nature', 'Ce n’est pas possible'], 1, 'Publier sur 127.0.0.1 ou ne pas publier.'],
+ ['Être membre du groupe docker revient à :', ['n’avoir aucun droit', 'être root sur l’hôte', 'pouvoir seulement lire les journaux', 'être administrateur réseau'], 1, 'On peut monter / dans un conteneur.']
+ ],
+ td: [
+ { n: 'Échauffement', c: 'Classer VM ou conteneur : (a) serveur Windows pour un logiciel métier, (b) API Python déployée dix fois par jour, (c) isolation forte entre deux clients hébergés, (d) base de tests jetable pour chaque élève.', r: '(a) VM · (b) conteneur · (c) VM (ou conteneurs dans des VM séparées) · (d) conteneur' },
+ { n: 'Application', c: 'Réécrire ce Dockerfile pour la production : « FROM python:latest / COPY . /app / RUN pip install -r /app/requirements.txt / CMD python /app/app.py ».', r: 'Version fixée (python:3.12-slim), COPY requirements.txt avant le code pour le cache, pip --no-cache-dir, utilisateur non root et USER, .dockerignore, CMD en forme exec ["python","app.py"], éventuellement multi-étapes et HEALTHCHECK.' },
+ { n: 'Application', c: 'Lancer Nginx accessible uniquement depuis l’hôte sur le port 8080, redémarré automatiquement, limité à 256 Mo, avec un dossier de configuration en lecture seule.', r: 'docker run -d --name web --restart unless-stopped --memory 256m -p 127.0.0.1:8080:80 -v /srv/web/conf:/etc/nginx/conf.d:ro nginx:1.27-alpine' },
+ { n: 'Approfondissement', c: 'Montrer avec des commandes qu’un conteneur n’est qu’un processus de l’hôte, et retrouver son PID et ses cgroups.', r: 'docker inspect -f "{{.State.Pid}}" web → 4312\nps -fp 4312 · cat /proc/4312/cgroup · ls -l /proc/4312/ns' }
+ ],
+ tp: { type: 'Lab VM', url: 'apercu-labs.html', desc: 'Une VM Debian avec Docker : construire, publier, exploiter.', etapes: ['Construire l’image d’une API Python multi-étapes', 'La lancer avec limites de ressources et redémarrage automatique', 'Ajouter PostgreSQL sur un réseau utilisateur avec volume', 'Vérifier les ports réellement exposés', 'Scanner l’image avec Trivy'] },
+ plusLoin: [['Docker Docs · Dockerfile best practices', 'https://docs.docker.com/build/building/best-practices/'], ['ANSSI · Recommandations de sécurité relatives au déploiement de conteneurs Docker', 'https://cyber.gouv.fr/publications/recommandations-de-securite-relatives-au-deploiement-de-conteneurs-docker'], ['Trivy', 'https://trivy.dev/']] },
+plus: {
+ cas: { titre: '', texte: '' },
+ resolu: { enonce: 'L’application de réservation de salles, conteneurisée, redémarre en boucle depuis la mise à jour de ce matin. Les utilisateurs obtiennent une erreur 502 du reverse proxy. Diagnostiquer et rétablir.', etapes: [
+ ['Constater l’état', 'docker ps -a --filter name=resa\nNAMES IMAGE STATUS\nresa resa-app:2.4.0 Restarting (1) 12 seconds ago\n→ Le conteneur démarre puis s’arrête avec le code 1, et la politique de redémarrage le relance sans fin. Le reverse proxy ne trouve donc jamais de backend : d’où les 502.'],
+ ['Lire les journaux', 'docker logs --tail 20 resa\nKeyError: \'DATABASE_URL\'\n→ L’application s’arrête au démarrage faute de la variable DATABASE_URL. La nouvelle version attend un nom de variable différent de l’ancienne (DB_URL).'],
+ ['Comparer avec la version précédente', 'docker inspect -f "{{range .Config.Env}}{{println .}}{{end}}" resa | grep -i db\nDB_URL=postgresql://resa@db/resa\n→ Le conteneur est lancé avec l’ancien nom de variable. Le changement était annoncé dans les notes de version 2.4.0, mais le fichier de déploiement n’a pas été adapté.'],
+ ['Rétablir le service', 'docker rm -f resa\ndocker run -d --name resa --network resa-net --restart unless-stopped -e DATABASE_URL=postgresql://resa@db/resa resa-app:2.4.0\ndocker ps --filter name=resa\nresa resa-app:2.4.0 Up 20 seconds (healthy)\n→ On ne corrige pas le conteneur existant : on le recrée avec la bonne configuration. Le HEALTHCHECK confirme que l’application répond.'],
+ ['Vérifier et prévenir', 'curl -sI https://resa.lycee.local | head -1\nHTTP/2 200\n→ Service rétabli. Actions préventives : décrire le déploiement dans un fichier Compose versionné plutôt qu’une commande docker run tapée à la main, relire les notes de version, et tester la nouvelle image sur un environnement de préproduction avant la production.']
+ ] },
+ erreurs: ['Utiliser latest en production', 'Lancer le processus en root dans l’image', 'Stocker des données dans la couche du conteneur', 'Modifier un conteneur à la main au lieu de reconstruire l’image', 'Publier une base de données sur 0.0.0.0', 'Mettre des secrets dans le Dockerfile ou l’image', 'Oublier .dockerignore et embarquer .git', 'Donner le groupe docker à des utilisateurs non administrateurs'],
+ memo: [['Commande', 'Usage en production'], ['docker ps -a', 'conteneurs et leur état, y compris arrêtés'], ['docker logs -f --tail 100 compose.yaml (anciennement docker-compose.yml) déclare des services, chacun correspondant à un conteneur issu d’une image ou d’un Dockerfile, ainsi que des volumes et des réseaux. Compose crée automatiquement un réseau par projet : chaque service y est joignable par son nom.docker compose (plugin intégré, version 2), qui remplace l’ancien binaire docker-compose écrit en Python.', exemple: 'services:\n web:\n image: nginx:1.27-alpine\n ports: ["443:443"]\n volumes: ["./nginx:/etc/nginx/conf.d:ro", "certs:/etc/ssl/app:ro"]\n depends_on: [app]\n app:\n build: .\n env_file: .env\n depends_on:\n db: { condition: service_healthy }\n db:\n image: postgres:16\n environment:\n POSTGRES_PASSWORD_FILE: /run/secrets/db_password\n secrets: [db_password]\n volumes: ["pgdata:/var/lib/postgresql/data"]\n healthcheck:\n test: ["CMD", "pg_isready", "-U", "postgres"]\n interval: 5s\n retries: 10\nvolumes:\n pgdata:\n certs:\nsecrets:\n db_password:\n file: ./secrets/db_password.txt' },
+ { t: 'Ordre de démarrage et healthchecks', d: '', html: 'depends_on seul garantit uniquement que le conteneur de la base est démarré avant l’application, pas qu’il est prêt à accepter des connexions. PostgreSQL met plusieurs secondes à s’initialiser au premier lancement, et l’application qui s’y connecte trop tôt échoue.condition: service_healthy dans le depends_on de l’application. L’application doit aussi savoir réessayer sa connexion : en production, un redémarrage de la base peut survenir à tout moment.' },
+ { t: 'Variables, fichiers .env et secrets', d: '', html: 'Compose lit automatiquement le fichier .env du dossier du projet pour substituer les variables ${VAR} du fichier YAML, et env_file injecte des variables dans un conteneur. Ces fichiers ne doivent jamais être versionnés s’ils contiennent des mots de passe : on versionne un .env.example sans valeurs./run/secrets/ : le mot de passe n’apparaît ni dans les variables d’environnement, ni dans docker inspect. Les images officielles comme postgres ou mariadb acceptent les variables en _FILE pour lire leur valeur dans ce fichier.' },
+ { t: 'Exploiter un projet Compose', d: '', html: 'docker compose up -d crée ou met à jour tout le projet ; il ne recrée que les services dont la configuration ou l’image a changé. docker compose pull récupère les nouvelles images, docker compose up -d --build reconstruit celles qui ont un Dockerfile. docker compose ps, logs -f service, exec service sh et down complètent l’exploitation courante.docker compose down supprime conteneurs et réseau mais conserve les volumes ; down -v supprime aussi les volumes, donc les données. Cette option ne doit jamais être tapée par réflexe en production.', attention: 'docker compose down -v sur le serveur de production efface la base de données. Sauvegarder avant toute opération de maintenance, et réserver -v aux environnements de test.' },
+ { t: 'Plusieurs environnements', d: '', html: 'Un même projet tourne en développement, en préproduction et en production avec des différences : ports, volumes de code montés, niveau de journalisation, nombre de répliques. Compose fusionne plusieurs fichiers : compose.yaml contient la base commune, compose.override.yaml (chargé automatiquement) les réglages de développement, et compose.prod.yaml ceux de production, appliqués avec docker compose -f compose.yaml -f compose.prod.yaml up -d. Les profils permettent d’activer des services optionnels (outils d’administration, tests).' },
+ { t: 'Limites de Compose', d: '', html: 'Compose pilote les conteneurs d’une seule machine. Il ne répartit pas la charge entre plusieurs serveurs, ne déplace pas un service quand un nœud tombe, et ne gère pas les mises à jour sans interruption. Pour un établissement ou une PME, c’est souvent largement suffisant et bien plus simple à maintenir. Au-delà, on passe à un orchestrateur comme Kubernetes, dont les notions (services, volumes, secrets, sondes de santé) prolongent directement celles de Compose.' }
+ ],
+ synthese: ['compose.yaml versionné = documentation exécutable du déploiement', 'Réseau par projet, services joignables par leur nom', 'depends_on + healthcheck + condition service_healthy', '.env jamais versionné ; secrets montés dans /run/secrets', 'up -d ne recrée que ce qui a changé ; down -v efface les données', 'Plusieurs fichiers pour plusieurs environnements', 'Une seule machine : au-delà, Kubernetes'],
+ qcm: [
+ ['Que garantit depends_on sans condition ?', ['Que la base accepte les connexions', 'Que le conteneur de la base est démarré avant', 'Que la base est sauvegardée', 'Rien'], 1, 'Démarré ne veut pas dire prêt.'],
+ ['Que fait docker compose down -v ?', ['Redémarre', 'Supprime conteneurs, réseau et volumes', 'Met à jour les images', 'Affiche la version'], 1, 'Les données sont effacées.'],
+ ['Comment le service app joint-il le service db ?', ['Par l’IP de l’hôte', 'Par le nom db', 'Par localhost', 'Par un port publié'], 1, 'DNS du réseau du projet.'],
+ ['Pourquoi préférer les secrets aux variables d’environnement pour un mot de passe ?', ['Plus rapide', 'Le mot de passe n’apparaît pas dans docker inspect', 'Obligatoire', 'Chiffrement automatique sur le disque'], 1, 'Fichier monté en lecture seule.'],
+ ['Quel fichier est chargé automatiquement en plus de compose.yaml ?', ['compose.prod.yaml', 'compose.override.yaml', 'docker.yaml', '.env.example'], 1, 'Réglages de développement.'],
+ ['Après modification de l’image d’un seul service, docker compose up -d :', ['recrée tous les services', 'recrée seulement ce service', 'ne fait rien', 'supprime les volumes'], 1, 'Mise à jour ciblée.']
+ ],
+ td: [
+ { n: 'Application', c: 'Écrire le compose.yaml d’un GLPI : service web (image diouxx/glpi ou équivalent), service MariaDB avec volume et healthcheck, mot de passe en secret, seul le web publié sur 443.', r: 'services: web (ports 443, depends_on db service_healthy) ; db (mariadb:11, MARIADB_ROOT_PASSWORD_FILE, secrets, volume dbdata, healthcheck healthcheck.sh --connect) ; volumes: dbdata ; secrets: db_root.' },
+ { n: 'Application', c: 'Écrire la procédure de mise à jour d’un projet Compose en production sans perte de données.', r: '1. Sauvegarde (docker compose exec db pg_dump …) · 2. docker compose pull · 3. docker compose up -d · 4. docker compose ps et logs · 5. test fonctionnel · 6. en cas d’échec : revenir au tag précédent dans compose.yaml puis up -d.' },
+ { n: 'Approfondissement', c: 'Séparer la configuration de développement (code monté, port 8000 publié, débogage) de celle de production (image construite, pas de port applicatif publié).', r: 'compose.yaml : base commune · compose.override.yaml : volumes ./:/app, ports 8000, APP_DEBUG=1 · compose.prod.yaml : image registre:tag, restart unless-stopped, pas de ports sur app · lancement prod : -f compose.yaml -f compose.prod.yaml.' }
+ ],
+ tp: { type: 'Lab VM', url: 'apercu-labs.html', desc: 'Déployer une application web, sa base et son cache avec Compose.', etapes: ['Écrire compose.yaml avec trois services', 'Ajouter healthcheck et secrets', 'Démarrer, vérifier ps et logs', 'Mettre à jour une image sans perte de données', 'Sauvegarder et restaurer la base'] },
+ plusLoin: [['Docker Docs · Compose file reference', 'https://docs.docker.com/reference/compose-file/'], ['Docker Docs · Secrets in Compose', 'https://docs.docker.com/compose/how-tos/use-secrets/']] },
+plus: {
+ cas: { titre: '', texte: '' },
+ resolu: { enonce: 'Après un redémarrage du serveur, l’application Laravel du CDI affiche « SQLSTATE[HY000] [2002] Connection refused » pendant plusieurs minutes, puis parfois reste en erreur. Diagnostiquer et fiabiliser.', etapes: [
+ ['Observer l’ordre de démarrage', 'docker compose ps\nNAME SERVICE STATUS\ncdi-app app Up 3 minutes\ncdi-db db Up 3 minutes (health: starting)\n→ L’application tourne alors que la base n’est pas encore prête.'],
+ ['Lire les journaux', 'docker compose logs app | head -3\nSQLSTATE[HY000] [2002] Connection refused\ndocker compose logs db | tail -2\nInnoDB: Starting crash recovery...\nready for connections.\n→ Après un arrêt brutal, MariaDB effectue une récupération qui prend du temps. L’application a tenté de se connecter trop tôt et a mis la base en échec dans son cache de configuration.'],
+ ['Lire le fichier Compose', 'grep -A3 depends_on compose.yaml\n depends_on:\n - db\n→ depends_on sans condition : Compose attend seulement que le conteneur db soit lancé.'],
+ ['Corriger', 'db:\n healthcheck:\n test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]\n interval: 5s\n retries: 30\napp:\n depends_on:\n db: { condition: service_healthy }\n restart: unless-stopped\ndocker compose up -d\n→ L’application ne démarre plus qu’une fois la base réellement prête, et redémarre automatiquement en cas d’échec.'],
+ ['Valider', 'sudo reboot (sur la préproduction)\ndocker compose ps\ncdi-db Up 2 minutes (healthy)\ncdi-app Up 1 minute\n→ L’ordre est respecté. Compte rendu : cause (depends_on sans healthcheck), correction, test de redémarrage ajouté à la procédure de validation.']
+ ] },
+ erreurs: ['depends_on sans healthcheck', 'Versionner le fichier .env avec les mots de passe', 'Taper docker compose down -v en production', 'Publier les ports de la base de données', 'Ne pas fixer les versions des images', 'Mettre à jour sans sauvegarde préalable'],
+ memo: [['Commande', 'Usage'], ['docker compose up -d', 'créer ou mettre à jour le projet'], ['docker compose ps', 'état et santé des services'], ['docker compose logs -f changed=0.group_vars/ et host_vars/, ce qui sépare les données (quelle machine, quelle valeur) de la logique (les tâches).', exemple: '# inventaire/hosts.yaml\nall:\n children:\n web:\n hosts:\n web1.lycee.local:\n web2.lycee.local:\n db:\n hosts:\n db1.lycee.local:\n ansible_host: 10.62.40.31\n vars:\n ansible_user: admin\n\n$ ansible -i inventaire all -m ping\nweb1.lycee.local | SUCCESS => {"changed": false, "ping": "pong"}' },
+ { t: 'Playbooks, tâches et modules', d: '', html: 'Un playbook est une liste de plays : chacun associe un groupe de machines à une liste de tâches. Chaque tâche appelle un module avec des paramètres : ansible.builtin.apt pour les paquets, template pour générer un fichier de configuration, service ou systemd pour les services, user, lineinfile, copy, file. On utilise les noms complets (FQCN) pour éviter toute ambiguïté.become: true élève les privilèges avec sudo. Les handlers sont des tâches déclenchées par notify seulement si une tâche a réellement changé quelque chose : on ne redémarre Nginx que si sa configuration a été modifiée.', exemple: '- name: Serveurs web\n hosts: web\n become: true\n tasks:\n - name: Installer nginx\n ansible.builtin.apt:\n name: nginx\n state: present\n update_cache: true\n - name: Déployer la configuration du site\n ansible.builtin.template:\n src: site.conf.j2\n dest: /etc/nginx/conf.d/site.conf\n mode: "0644"\n notify: Recharger nginx\n - name: Nginx actif au démarrage\n ansible.builtin.service:\n name: nginx\n state: started\n enabled: true\n handlers:\n - name: Recharger nginx\n ansible.builtin.service:\n name: nginx\n state: reloaded' },
+ { t: 'Templates Jinja2 et variables', d: '', html: 'Le module template génère un fichier à partir d’un modèle Jinja2 : {{ variable }} insère une valeur, {% for %} et {% if %} ajoutent de la logique. La même configuration sert ainsi à toutes les machines, avec leurs valeurs propres. Les facts collectés automatiquement (adresse IP, distribution, mémoire) sont aussi disponibles comme variables.-e en ligne de commande, qui l’emporte sur tout. Mal maîtrisé, cet ordre explique des valeurs « inattendues ».' },
+ { t: 'Rôles et collections', d: '', html: 'Au-delà de quelques dizaines de tâches, on range le code en rôles : une arborescence normalisée (tasks, handlers, templates, defaults, vars, files) qui regroupe tout ce qu’il faut pour une fonction, par exemple « serveur web » ou « durcissement SSH ». Un rôle se réutilise dans plusieurs playbooks et se partage. Les collections distribuent rôles et modules (community.general, ansible.posix) et s’installent avec ansible-galaxy.' },
+ { t: 'Tester avant d’appliquer et protéger les secrets', d: '', html: '--check simule l’exécution sans rien modifier, --diff montre les différences de fichiers, --limit web1 restreint à une machine, --tags à certaines tâches. En production, on valide toujours sur une machine avant tout le parc.ansible-lint détecte les mauvaises pratiques (tâches non nommées, modules shell là où un module dédié existe, droits de fichiers absents).', attention: 'Les modules command et shell ne sont pas idempotents par nature : ils s’exécutent à chaque passage. Préférer un module dédié, ou ajouter creates, removes ou changed_when pour décrire l’état.' }
+ ],
+ synthese: ['Ansible décrit un état désiré ; les modules sont idempotents', 'Sans agent : SSH et Python sur les machines gérées', 'Inventaire en groupes, variables dans group_vars et host_vars', 'Playbook → plays → tâches → modules ; become pour sudo', 'Handlers déclenchés uniquement en cas de changement', 'Templates Jinja2, rôles réutilisables', '--check --diff et --limit avant d’appliquer ; Vault pour les secrets'],
+ qcm: [
+ ['Que signifie qu’une tâche Ansible est idempotente ?', ['Elle est rapide', 'La relancer sur une machine conforme ne change rien', 'Elle s’exécute en parallèle', 'Elle est chiffrée'], 1, 'changed=0 au second passage.'],
+ ['De quoi Ansible a-t-il besoin sur les machines gérées ?', ['Un agent Ansible', 'SSH et Python', 'Docker', 'Un serveur web'], 1, 'Architecture sans agent.'],
+ ['Quand un handler s’exécute-t-il ?', ['À chaque tâche', 'Quand une tâche qui le notifie a produit un changement', 'Au début du playbook', 'Jamais automatiquement'], 1, 'Par exemple recharger Nginx seulement si sa configuration a changé.'],
+ ['Quelle option simule sans modifier ?', ['--dry', '--check', '--test', '--simulate'], 1, 'Souvent combinée avec --diff.'],
+ ['Où placer une variable commune à tous les serveurs web ?', ['host_vars/web1.yaml', 'group_vars/web.yaml', 'dans le template', 'dans /etc/ansible/ansible.cfg'], 1, 'Variables de groupe.'],
+ ['Comment protéger un mot de passe dans le dépôt ?', ['Le mettre en commentaire', 'Ansible Vault', 'Le coder en base64', 'Le mettre dans le template'], 1, 'Chiffrement AES-256.'],
+ ['Pourquoi éviter le module shell pour installer un paquet ?', ['Il est interdit', 'Il n’est pas idempotent et masque l’état réel', 'Il est plus lent', 'Il ne supporte pas sudo'], 1, 'Utiliser apt ou dnf.']
+ ],
+ td: [
+ { n: 'Application', c: 'Écrire un playbook qui crée l’utilisateur technicien, lui dépose une clé SSH publique, désactive l’authentification SSH par mot de passe et recharge sshd seulement si nécessaire.', r: 'user (name, groups: sudo, shell) · ansible.posix.authorized_key · lineinfile sur /etc/ssh/sshd_config avec regexp "^#?PasswordAuthentication" line "PasswordAuthentication no" validate "sshd -t -f %s" notify Recharger ssh · handler service ssh reloaded.' },
+ { n: 'Application', c: 'Transformer ce passage en tâche idempotente : « shell: echo "10.62.40.20 ent" >> /etc/hosts ».', r: 'ansible.builtin.lineinfile: path=/etc/hosts line="10.62.40.20 ent" (la ligne n’est ajoutée qu’une fois).' },
+ { n: 'Approfondissement', c: 'Organiser en rôle le déploiement d’un serveur web : arborescence, variables par défaut, template et handler.', r: 'roles/web/{tasks/main.yml, handlers/main.yml, templates/site.conf.j2, defaults/main.yml (web_port: 443, web_root: /var/www/site)} · playbook : roles: [web].' }
+ ],
+ tp: { type: 'Lab VM', url: 'apercu-labs.html', desc: 'Un poste de contrôle et trois VM Debian à configurer.', etapes: ['Écrire l’inventaire et tester ansible -m ping', 'Playbook : paquets et utilisateurs', 'Déployer Nginx avec un template et un handler', 'Vérifier l’idempotence (changed=0)', 'Chiffrer un secret avec Vault', 'Passer ansible-lint'] },
+ plusLoin: [['Documentation Ansible', 'https://docs.ansible.com/'], ['Ansible Lint', 'https://ansible.readthedocs.io/projects/lint/'], ['Xavki · tutoriels Ansible en français', 'https://www.youtube.com/@xavki']] },
+plus: {
+ cas: { titre: '', texte: '' },
+ resolu: { enonce: 'Le playbook de mise à jour des 12 serveurs web s’est interrompu cette nuit : 4 serveurs ont la nouvelle configuration Nginx, 8 l’ancienne, et web3 ne répond plus. Diagnostiquer, rétablir et fiabiliser.', etapes: [
+ ['Lire le récapitulatif', 'PLAY RECAP\nweb1 ok=6 changed=2 failed=0\nweb3 ok=4 changed=1 failed=1\nweb4…web12 (non traités)\n→ Ansible s’est arrêté après l’échec sur web3 : par défaut, un play traite les machines par lots et s’arrête si toutes celles du lot échouent. L’état du parc est hétérogène.'],
+ ['Identifier l’erreur', 'TASK [Recharger nginx] fatal: [web3]: FAILED! => {"msg": "Unable to reload service nginx: Job for nginx.service failed"}\nssh web3 sudo nginx -t\nnginx: [emerg] unknown directive "ssl_protocol" in /etc/nginx/conf.d/site.conf:7\n→ Le template contient une faute (ssl_protocol au lieu de ssl_protocols). La configuration invalide a été déposée, le rechargement a échoué et Nginx s’est arrêté sur web3.'],
+ ['Rétablir web3', 'Correction du template site.conf.j2 (ssl_protocols TLSv1.2 TLSv1.3;)\nansible-playbook site.yml --limit web3 --diff\nweb3 ok=6 changed=2 failed=0\ncurl -sI https://web3.lycee.local | head -1\nHTTP/2 200\n→ On corrige la source (le template), jamais le fichier à la main sur le serveur : sinon le prochain passage réintroduirait l’erreur.'],
+ ['Fiabiliser le playbook', '- ansible.builtin.template:\n src: site.conf.j2\n dest: /etc/nginx/conf.d/site.conf\n validate: nginx -t -c /etc/nginx/nginx.conf\n notify: Recharger nginx\n- hosts: web\n serial: 2\n max_fail_percentage: 0\n→ validate teste le fichier avant de le mettre en place ; serial: 2 déploie deux serveurs à la fois et arrête tout au premier échec. Une erreur ne touche plus qu’un lot.'],
+ ['Appliquer au parc et contrôler', 'ansible-playbook site.yml --check --diff --limit web4\nansible-playbook site.yml\nweb1…web12 failed=0\nansible-playbook site.yml (second passage)\nweb1…web12 changed=0\n→ Le parc est homogène et le second passage confirme l’idempotence. Compte rendu : cause, impact, correction, et règle d’équipe : --check sur une machine témoin avant tout déploiement, validation des templates dans la CI avec ansible-lint.']
+ ] },
+ erreurs: ['Utiliser shell ou command là où un module dédié existe', 'Modifier un fichier à la main sur un serveur géré par Ansible', 'Laisser des mots de passe en clair dans le dépôt', 'Déployer sur tout le parc sans --check ni serial', 'Redémarrer un service à chaque passage au lieu d’un handler', 'Déposer une configuration sans validate'],
+ memo: [['Commande', 'Usage'], ['ansible all -m ping', 'tester la connexion à tout l’inventaire'], ['ansible web -m ansible.builtin.setup', 'afficher les facts d’un groupe'], ['ansible-playbook site.yml --check --diff', 'simuler et voir les différences'], ['ansible-playbook site.yml --limit web1', 'restreindre à une machine'], ['ansible-playbook site.yml --tags nginx', 'n’exécuter que certaines tâches'], ['ansible-inventory --graph', 'visualiser l’inventaire'], ['ansible-vault create|edit|encrypt', 'gérer les secrets chiffrés'], ['ansible-playbook … --ask-vault-pass', 'fournir le mot de passe du coffre'], ['ansible-galaxy collection install', 'installer une collection'], ['ansible-lint', 'contrôler les bonnes pratiques']],
+ examen: { titre: 'Sujet type · 20 points', q: ['Expliquer l’idempotence et l’architecture sans agent. (4 pts)', 'Écrire un inventaire et un playbook de déploiement avec template et handler. (8 pts)', 'Rendre idempotentes trois tâches shell fournies. (4 pts)', 'Proposer une stratégie de déploiement sûr sur 50 serveurs. (4 pts)'], r: ['État désiré, SSH + Python', 'hosts.yaml, apt, template, service, handler', 'lineinfile, apt, creates', '--check, serial, validate, max_fail_percentage'] },
+ prof: { deroule: [['Ouverture', 'Configurer trois VM à la main en chronométrant, puis avec Ansible'], ['Cours', 'Inventaire, playbooks, modules, idempotence'], ['Pratique', 'Lab trois VM'], ['Incident', 'Template invalide sur un parc'], ['Clôture', 'Quiz flash']], diff: 'Élèves en difficulté : playbook à compléter. Élèves avancés : rôles, Vault, CI avec ansible-lint, Molecule.', eval: 'Lab validé (idempotence vérifiée), sujet type.' }
+},
+exemples: [
+ ['Tester l’accès à tout le parc', 'Avant un déploiement.', 'ansible -i inventaire all -m ping -o', 'web1.lycee.local | SUCCESS => {"changed": false,"ping": "pong"}\nweb2.lycee.local | UNREACHABLE! => {"msg": "Failed to connect to the host via ssh: Connection timed out"}', 'web2 est injoignable en SSH : on le traite avant de lancer le playbook, sinon le parc sera partiellement configuré.'],
+ ['Simuler un changement', 'Nouvelle version du template Nginx.', 'ansible-playbook site.yml --check --diff --limit web1', '--- before: /etc/nginx/conf.d/site.conf\n+++ after: site.conf.j2\n- client_max_body_size 8m;\n+ client_max_body_size 64m;\nweb1 : ok=5 changed=1 failed=0', 'Seule la ligne attendue change. On peut appliquer sereinement.'],
+ ['Vérifier l’idempotence', 'Contrôle qualité d’un playbook.', 'ansible-playbook site.yml | tail -3', 'PLAY RECAP\nweb1 : ok=7 changed=1 unreachable=0 failed=0\nweb2 : ok=7 changed=1 unreachable=0 failed=0', 'Au second passage, une tâche est encore « changed » : c’est une tâche shell sans changed_when. Il faut la remplacer par un module dédié ou décrire sa condition de changement.'],
+ ['Lire les facts d’une machine', 'Adapter un template à la mémoire disponible.', 'ansible db1 -m ansible.builtin.setup -a "filter=ansible_memtotal_mb"', 'db1 | SUCCESS => {"ansible_facts": {"ansible_memtotal_mb": 7957}}', 'La variable ansible_memtotal_mb est utilisable dans un template, par exemple pour dimensionner shared_buffers de PostgreSQL au quart de la mémoire.'],
+ ['Chiffrer un secret', 'Mot de passe de la base dans group_vars.', 'ansible-vault encrypt group_vars/db/vault.yml ; head -1 group_vars/db/vault.yml', 'Encryption successful\n$ANSIBLE_VAULT;1.1;AES256', 'Le fichier peut être versionné : sans le mot de passe du coffre, il est illisible.'],
+ ['Détecter les mauvaises pratiques', 'Revue de code avant fusion.', 'ansible-lint site.yml', 'command-instead-of-module: apt-get used in place of apt module\nsite.yml:14 Task/Handler: shell apt-get install -y nginx\nname[missing]: All tasks should be named\nsite.yml:22', 'ansible-lint signale une installation via shell et une tâche sans nom. On l’intègre dans la CI pour bloquer ces erreurs avant qu’elles atteignent la production.']
+],
+termes: ['Ansible', 'playbook', 'inventaire', 'module', 'tâche', 'handler', 'notify', 'idempotence', 'become', 'group_vars', 'host_vars', 'Jinja2', 'template', 'facts', 'rôle', 'collection', 'ansible-galaxy', 'Ansible Vault', 'ansible-lint', '--check', '--diff', '--limit', 'serial', 'validate', 'changed=0']
+});
+})();
diff --git a/design/js/contenus-devops-2.js b/design/js/contenus-devops-2.js
new file mode 100644
index 0000000..7770712
--- /dev/null
+++ b/design/js/contenus-devops-2.js
@@ -0,0 +1,122 @@
+// Cours complets · DevOps lot 2 : Git, CI/CD
+(function () {
+var reg = function (c) {
+ (window.CONTENUS_PRO = window.CONTENUS_PRO || []).unshift(c.cours);
+ (window.CONTENUS_PLUS = window.CONTENUS_PLUS || {})[c.cours.id] = c.plus;
+ (window.CONTENUS_EXEMPLES = window.CONTENUS_EXEMPLES || {})[c.cours.id] = c.exemples;
+ (window.CONTENUS_SCHEMAS = window.CONTENUS_SCHEMAS || {})[c.cours.id] = { termes: c.termes, figs: [] };
+};
+
+reg({
+cours: { id: 'git', match: /\bGit\b|versionn|gestion de versions/i,
+ titre: 'Git : versionner, collaborer et revenir en arrière', duree: '',
+ niveau: 'NSI Terminale · BTS SIO SLAM / SISR · BUT Informatique / R&T · Master',
+ prerequis: ['Le terminal Linux'],
+ competences: ['BTS SIO · Bloc 1 · Travailler en mode projet', 'BTS SIO SLAM · Bloc 2 · Gérer les versions d’une solution applicative', 'BUT Info · Compétence « Collaborer au sein d’une équipe informatique »'],
+ intro: 'Un fichier « rapport_final_v3_corrigé_VRAIMENT_final.docx » résume le problème que Git résout. Dès que plusieurs personnes modifient le même code, ou qu’une seule personne veut pouvoir revenir à la version d’hier, il faut un historique fiable. Git enregistre chaque état du projet, permet de travailler en parallèle sur des branches et de fusionner le travail de chacun. C’est l’outil commun à tous les développeurs et, de plus en plus, aux administrateurs qui versionnent leurs configurations, leurs playbooks et leurs fichiers Compose.',
+ cm: [
+ { t: 'Le modèle de Git : instantanés et empreintes', d: '', html: 'Git ne stocke pas des différences mais des instantanés complets du projet. Chaque fichier, chaque dossier et chaque commit est un objet identifié par l’empreinte de son contenu (SHA-1, en transition vers SHA-256). Deux fichiers identiques ne sont stockés qu’une fois, et toute modification de l’historique change les empreintes : l’intégrité est vérifiable.git add. Le dépôt (.git) contient l’historique, et git commit y enregistre l’index.git status montre à tout moment l’état des trois zones.', exemple: 'git init\ngit add index.html style.css\ngit commit -m "Page d’accueil du TP"\ngit status\ngit log --oneline --graph' },
+ { t: 'Branches et fusions', d: '', html: 'On crée une branche pour chaque fonctionnalité ou correction (git switch -c correctif-login). La branche principale (main) reste stable. Quand le travail est terminé, on le fusionne. Si main n’a pas bougé, Git avance simplement le pointeur (fast-forward). Sinon, il crée un commit de fusion qui a deux parents.<<<<<<<, =======, >>>>>>>). On édite pour garder la bonne version, on ajoute le fichier et on termine le commit.git clone copie un dépôt, git fetch récupère les nouveautés sans les appliquer, git pull récupère et fusionne, git push publie ses commits. Les branches distantes apparaissent sous le nom origin/main.git restore fichier annule les modifications non ajoutées. git restore --staged fichier retire un fichier de l’index. git commit --amend corrige le dernier commit s’il n’a pas été poussé. git revert id crée un nouveau commit qui annule un commit précédent : c’est la seule méthode sûre sur un historique partagé. git reset déplace la branche en arrière et réécrit l’historique local.git reflog liste les positions successives de HEAD et permet de retrouver un commit « supprimé ».' },
+ { t: 'Ce qui ne va pas dans Git', d: '', html: 'Le fichier .gitignore exclut ce qui ne doit pas être versionné : dépendances (node_modules, vendor), fichiers générés, journaux, et surtout secrets (.env, clés). Un mot de passe poussé une fois reste dans l’historique même après suppression du fichier : il faut le considérer comme compromis et le changer.ip, du paquet iproute2, remplace depuis longtemps les anciens ifconfig, route et arp, qui ne sont plus installés par défaut sur Debian. Elle se décline en sous-commandes : ip link pour les interfaces, ip addr pour les adresses, ip route pour la table de routage, ip neigh pour la table de voisinage (ARP).ip -s link ajoute les compteurs de paquets, d’erreurs et de pertes, très utiles pour repérer un câble abîmé ou un duplex mal négocié.-br (brief) donne une ligne par interface, idéale pour un coup d’œil. On y vérifie l’adresse, mais surtout le masque : un poste en 192.168.10.65/24 alors que le réseau est un /26 croira que 192.168.10.130 est sur son réseau local et ne passera jamais par la passerelle.default via 192.168.10.1 est la passerelle par défaut : sans elle, la machine ne sait joindre que son propre réseau. La commande ip route get 8.8.8.8 est précieuse : elle indique quelle route, quelle interface et quelle adresse source seraient utilisées pour joindre une destination donnée, sans envoyer le moindre paquet.', exemple: '$ ip -br link\nlo UNKNOWN 00:00:00:00:00:00 ping envoie des messages ICMP Echo Request et attend des Echo Reply. Il mesure trois choses : si la destination répond, en combien de temps (le RTT, round-trip time, aller et retour), et quelle proportion des messages se perd en route.icmp_seq), un TTL et un temps. Des numéros de séquence qui sautent indiquent des pertes. Le TTL de la réponse donne un indice sur la distance et le système distant : Linux part en général de 64, Windows de 128, beaucoup d’équipements réseau de 255 ; un TTL reçu de 57 signifie qu’un paquet parti à 64 a traversé 7 routeurs.packet loss doit être à 0 % sur un réseau sain ; quelques pour cent de pertes suffisent à rendre une visioconférence pénible et un transfert de fichiers très lent, car TCP réduit son débit à chaque perte. La ligne rtt min/avg/max/mdev donne le temps minimum, moyen, maximum et l’écart moyen (gigue). Une gigue élevée révèle un lien saturé ou un Wi-Fi perturbé.-c 5 limite le nombre de paquets (sans elle, ping tourne jusqu’à Ctrl+C), -i 0.2 accélère l’envoi, -s 1472 -M do envoie un gros paquet interdit de fragmentation pour tester la MTU d’un chemin, -I ens18 force l’interface de sortie.', exemple: '$ ping -c 4 192.168.10.1\nPING 192.168.10.1 (192.168.10.1) 56(84) bytes of data.\n64 bytes from 192.168.10.1: icmp_seq=1 ttl=64 time=0.412 ms\n64 bytes from 192.168.10.1: icmp_seq=2 ttl=64 time=0.387 ms\n64 bytes from 192.168.10.1: icmp_seq=3 ttl=64 time=0.401 ms\n64 bytes from 192.168.10.1: icmp_seq=4 ttl=64 time=0.395 ms\n\n--- 192.168.10.1 ping statistics ---\n4 packets transmitted, 4 received, 0% packet loss, time 3055ms\nrtt min/avg/max/mdev = 0.387/0.398/0.412/0.009 ms', attention: 'Un ping qui échoue ne prouve pas qu’une machine est éteinte. De nombreux pare-feux, dont celui de Windows par défaut et ceux des hébergeurs, bloquent ICMP. À l’inverse, un ping qui répond ne prouve pas qu’un service fonctionne : la machine peut répondre au ping avec un serveur web planté.' },
+ { t: 'traceroute et mtr : voir le chemin', d: '', html: 'Quand la destination ne répond pas ou répond lentement, il faut savoir où se situe le problème. traceroute exploite astucieusement le champ TTL de l’en-tête IP. Chaque routeur décrémente ce TTL de 1 ; lorsqu’il atteint 0, le routeur détruit le paquet et renvoie un message ICMP Time Exceeded à l’expéditeur. traceroute envoie donc un premier paquet avec un TTL de 1 (il meurt au premier routeur, qui se dénonce), puis un TTL de 2 (il meurt au deuxième), et ainsi de suite jusqu’à la destination.traceroute -I utilise ICMP comme Windows (tracert), et traceroute -T -p 443 utilise des paquets TCP SYN vers le port 443, qui passent presque partout puisqu’ils ressemblent à une connexion web.mtr combine ping et traceroute : il interroge chaque saut en continu et affiche pour chacun le taux de perte et les temps. C’est l’outil de référence pour documenter un problème de qualité auprès d’un opérateur. Attention à l’interprétation : une perte affichée sur un saut intermédiaire mais pas sur les suivants vient d’un routeur qui limite ses réponses, pas d’une vraie perte. Seule compte la perte qui persiste jusqu’à la destination.', exemple: '$ traceroute -n 1.1.1.1\ntraceroute to 1.1.1.1, 30 hops max, 60 byte packets\n 1 192.168.10.1 0.512 ms 0.470 ms 0.455 ms\n 2 10.255.0.1 2.118 ms 2.097 ms 2.230 ms\n 3 * * *\n 4 62.34.2.57 9.874 ms 9.812 ms 9.930 ms\n 5 1.1.1.1 10.402 ms 10.377 ms 10.361 ms', attention: 'Un temps qui augmente brusquement à un saut puis reste élevé indique un lien lent ou long (câble sous-marin, par exemple). Un temps élevé sur un seul saut, suivi de temps normaux, n’indique rien : le routeur traite simplement ses réponses ICMP avec une faible priorité.' },
+ { t: 'ss : qui écoute, qui est connecté', d: '', html: 'ss (socket statistics) remplace netstat. Il liste les sockets ouvertes sur la machine, c’est-à-dire les points de communication entre un programme et le réseau. C’est l’outil qui répond à la question « le service écoute-t-il ? », la plus fréquente après « la machine est-elle joignable ? ».ss -tlnp : t pour TCP, l pour les sockets en écoute (LISTEN), n pour afficher les numéros de port au lieu des noms, p pour afficher le processus propriétaire (nécessite sudo). Remplacez t par u pour UDP, ou mettez les deux.0.0.0.0:80 ou *:80 signifie que le service écoute sur toutes les interfaces. 127.0.0.1:3306 signifie qu’il n’écoute que sur la boucle locale : il est invisible depuis le réseau, ce qui est voulu pour une base de données, mais une erreur classique pour un service censé être public.ss -tn state established '( dport = :443 )'.', exemple: '$ sudo ss -tlnp\nState Recv-Q Send-Q Local Address:Port Peer Address:Port Process\nLISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=611,fd=3))\nLISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("apache2",pid=842,fd=4))\nLISTEN 0 80 127.0.0.1:3306 0.0.0.0:* users:(("mariadbd",pid=790,fd=21))\n\n$ ss -tn state established\nRecv-Q Send-Q Local Address:Port Peer Address:Port\n0 0 192.168.10.20:22 192.168.10.54:51522' },
+ { t: 'ARP et ip neigh : le voisinage', d: '', html: 'Pour envoyer une trame Ethernet, il faut l’adresse MAC du destinataire direct, c’est-à-dire la machine elle-même si elle est sur le même réseau, sinon la passerelle. Le protocole ARP fait la correspondance : la machine diffuse à tout le réseau local « qui a 192.168.10.1 ? », la passerelle répond avec sa MAC, et la réponse est gardée en cache.ip neigh affiche ce cache avec l’état de chaque entrée. REACHABLE : le voisin a été confirmé récemment. STALE : l’entrée est ancienne mais encore utilisable, elle sera vérifiée au prochain envoi. INCOMPLETE : une requête ARP est partie, aucune réponse n’est encore arrivée. FAILED : le voisin n’a jamais répondu.arping envoie des requêtes ARP directement et permet de détecter un conflit d’adresse : si deux MAC différentes répondent pour la même IP, deux machines ont été configurées avec la même adresse. Le même phénomène peut signaler une attaque par usurpation ARP (ARP spoofing), où un attaquant se fait passer pour la passerelle afin d’intercepter le trafic.', exemple: '$ ip neigh\n192.168.10.1 dev ens18 lladdr 3c:52:82:1a:0f:9b REACHABLE\n192.168.10.54 dev ens18 lladdr 00:15:5d:0a:11:03 STALE\n192.168.10.99 dev ens18 FAILED\n\n$ sudo arping -c 3 -I ens18 192.168.10.30\nUnicast reply from 192.168.10.30 [00:15:5D:0A:11:07] 0.645ms\nUnicast reply from 192.168.10.30 [08:00:27:3B:C4:12] 0.702ms\nUnicast reply from 192.168.10.30 [00:15:5D:0A:11:07] 0.610ms', attention: 'Deux adresses MAC différentes pour une même IP, comme ci-dessus : conflit d’adresse à traiter immédiatement. Les symptômes typiques sont des coupures aléatoires de quelques secondes pour les deux machines.' },
+ { t: 'tcpdump et Wireshark : regarder le fil', d: '', html: 'Tous les outils précédents déduisent ce qui se passe. tcpdump montre ce qui passe réellement sur l’interface, paquet par paquet. C’est l’outil de dernier recours, et souvent celui qui tranche les débats entre équipes (« le pare-feu bloque » contre « l’application ne répond pas »).host 192.168.10.54, port 443, tcp, icmp, combinables avec and, or, not. Sans filtre, sur un serveur actif, l’écran défile trop vite pour être lu, et votre propre session SSH apparaît dans la capture ; on l’exclut avec not port 22. Les options essentielles : -i ens18 choisit l’interface, -n évite la résolution des noms (plus rapide, plus lisible), -c 20 s’arrête après 20 paquets, -w capture.pcap enregistre dans un fichier.tcpdump -w, on rapatrie le fichier .pcap avec scp, puis on l’ouvre dans Wireshark sur son poste. Wireshark décode chaque protocole couche par couche, reconstitue les échanges avec « Suivre le flux TCP » et permet des filtres d’affichage comme tcp.flags.syn == 1 && tcp.flags.ack == 0 ou http.response.code == 500.', exemple: '$ sudo tcpdump -ni ens18 -c 6 "tcp port 80 and host 192.168.10.54"\n10:14:02.118 IP 192.168.10.54.51544 > 192.168.10.20.80: Flags [S], seq 3308715651, win 64240\n10:14:02.118 IP 192.168.10.20.80 > 192.168.10.54.51544: Flags [S.], seq 1920458830, ack 3308715652\n10:14:02.119 IP 192.168.10.54.51544 > 192.168.10.20.80: Flags [.], ack 1\n10:14:02.119 IP 192.168.10.54.51544 > 192.168.10.20.80: Flags [P.], length 78: HTTP: GET / HTTP/1.1\n10:14:02.121 IP 192.168.10.20.80 > 192.168.10.54.51544: Flags [P.], length 3460: HTTP: HTTP/1.1 200 OK\n10:14:02.122 IP 192.168.10.54.51544 > 192.168.10.20.80: Flags [.], ack 3461', attention: 'Capturer du trafic, c’est potentiellement lire des données personnelles et des mots de passe transmis en clair. Sur un réseau d’entreprise ou d’établissement, on ne capture qu’avec une autorisation et on supprime les fichiers après analyse. C’est une obligation liée au RGPD et à la charte informatique.' },
+ { t: 'Les compléments indispensables : dig, curl, nc', d: '', html: 'Trois outils finissent le diagnostic au niveau applicatif. dig interroge le DNS et montre la réponse brute : dig +short intranet.lycee.fr donne l’adresse, dig @1.1.1.1 intranet.lycee.fr interroge un serveur précis pour comparer, et le champ status: NXDOMAIN indique que le nom n’existe pas. Beaucoup de « pannes réseau » sont en réalité des pannes DNS.curl -I affiche les en-têtes de réponse, curl -v détaille toute la négociation (résolution, connexion TCP, poignée de main TLS, requête, réponse), curl --resolve site.fr:443:192.168.10.20 https://site.fr teste un serveur précis en contournant le DNS.nc -zv 192.168.10.20 3306 répond « succeeded » ou « Connection refused ». C’est le moyen le plus rapide de vérifier qu’un pare-feu laisse passer un flux entre deux serveurs.' }
+ ],
+ synthese: ['On diagnostique de bas en haut et on note chaque résultat', 'ip link / ip addr / ip route : lien, adresse, masque, passerelle', 'ping mesure joignabilité, latence, pertes ; ICMP peut être filtré', 'traceroute et mtr localisent l’endroit du problème ; seule compte la perte qui persiste jusqu’à la destination', 'ss -tlnp : le service écoute-t-il, et sur quelle adresse ?', 'ip neigh : une passerelle en FAILED oriente vers la couche 2', 'tcpdump tranche : RST = port fermé, silence = port filtré', 'dig, curl, nc terminent le diagnostic applicatif'],
+ qcm: [
+ ['ip link affiche ens18 en UP mais sans LOWER_UP. Que faut-il vérifier en priorité ?', ['Le DNS', 'Le câble et le port du switch', 'Le pare-feu', 'Le service web'], 1, 'L’interface est activée mais ne détecte pas de lien physique.'],
+ ['Quelle commande indique la route et l’adresse source utilisées pour joindre 8.8.8.8, sans rien envoyer ?', ['ping 8.8.8.8', 'ip route get 8.8.8.8', 'traceroute 8.8.8.8', 'ss -r'], 1, 'ip route get interroge la table de routage.'],
+ ['Un ping renvoie « 100 % packet loss » vers un serveur web qui affiche pourtant bien son site. Explication la plus probable ?', ['Le serveur est éteint', 'ICMP est filtré par un pare-feu', 'Le DNS est en panne', 'Le câble est coupé'], 1, 'Le site répond, donc la machine est joignable ; seul ICMP est bloqué.'],
+ ['Sur quel mécanisme repose traceroute ?', ['Le numéro de séquence TCP', 'La décrémentation du TTL et les messages ICMP Time Exceeded', 'Les requêtes ARP', 'Le DNS inverse'], 1, 'Chaque routeur qui met le TTL à 0 se signale.'],
+ ['Dans mtr, le saut 4 affiche 40 % de pertes, les sauts 5 à 9 et la destination 0 %. Conclusion ?', ['Le lien du saut 4 est défaillant', 'Le routeur 4 limite ses réponses ICMP, pas de vraie perte', 'La destination est saturée', 'Il faut changer d’opérateur'], 1, 'Une perte qui ne se propage pas n’est pas une vraie perte.'],
+ ['ss -tlnp montre 127.0.0.1:8080 pour l’application. Les postes du réseau ne peuvent pas y accéder. Pourquoi ?', ['Le port 8080 est interdit', 'L’application n’écoute que sur la boucle locale', 'Il manque sudo', 'Le pare-feu est désactivé'], 1, 'Il faut la configurer pour écouter sur 0.0.0.0 ou l’IP du serveur.'],
+ ['Que signifie l’état SYN-SENT persistant dans ss ?', ['Connexion établie', 'On attend une réponse au SYN, souvent un pare-feu qui jette les paquets', 'Connexion fermée proprement', 'Le serveur a refusé'], 1, 'Un refus donnerait un RST immédiat.'],
+ ['ip neigh affiche la passerelle en FAILED. Où chercher ?', ['Au niveau DNS', 'Au niveau 2 : VLAN, câble, passerelle éteinte', 'Dans Apache', 'Dans le navigateur'], 1, 'La machine n’obtient même pas la MAC de son routeur.'],
+ ['Dans tcpdump, un SYN reçoit immédiatement une réponse [R.]. Le port est :', ['filtré', 'fermé', 'ouvert', 'chiffré'], 1, 'La machine répond activement qu’il n’y a rien sur ce port.'],
+ ['Pourquoi ajouter not port 22 à une capture tcpdump lancée en SSH ?', ['Pour aller plus vite', 'Pour ne pas capturer sa propre session', 'C’est obligatoire', 'Pour chiffrer la capture'], 1, 'Sinon chaque ligne affichée génère du trafic SSH capturé.'],
+ ['Quel est le rôle de l’option -n de tcpdump et ss ?', ['Capturer moins', 'Afficher les adresses et ports en numérique, sans résolution de noms', 'Ignorer IPv6', 'Afficher en couleur'], 1, 'Plus rapide et plus lisible pour le diagnostic.'],
+ ['Deux MAC différentes répondent à arping pour la même IP. C’est :', ['normal', 'un conflit d’adresse ou une usurpation ARP', 'un problème DNS', 'un effet du Wi-Fi'], 1, 'À traiter immédiatement.']
+ ],
+ td: [
+ { n: 'Échauffement', c: 'Pour chaque symptôme, indiquer la couche concernée et la première commande à lancer : (a) « la carte réseau n’a pas de voyant », (b) « je n’ai pas d’adresse IP », (c) « je ping la passerelle mais pas Internet », (d) « le site s’ouvre par son IP mais pas par son nom ».', r: '(a) couches 1-2 · ip link\n(b) couche 3 locale · ip addr puis journal DHCP\n(c) couche 3 au-delà de la passerelle · ip route puis traceroute\n(d) couche 7 · dig nom-du-site' },
+ { n: 'Échauffement', c: 'Interpréter la ligne : « 64 bytes from 10.0.0.5: icmp_seq=7 ttl=121 time=38.2 ms ». Que peut-on dire du système distant et de la distance ?', r: 'TTL initial probablement 128 (Windows) : 128 − 121 = 7 routeurs traversés. RTT de 38 ms aller-retour.' },
+ { n: 'Application', c: 'Un serveur répond au ping mais le site ne s’affiche pas. Écrire la suite de commandes, sur le serveur, qui permet de savoir si Apache tourne, sur quel port et sur quelle adresse il écoute, et s’il répond localement.', r: 'systemctl status apache2\nsudo ss -tlnp | grep -E ":80|:443"\ncurl -I http://127.0.0.1\n(puis, depuis un poste client : curl -I http://IP-du-serveur)' },
+ { n: 'Application', c: 'Écrire la commande tcpdump qui capture, sur ens18, les 50 premiers paquets échangés avec 192.168.10.54 sur le port 443, sans résolution de noms, dans le fichier https.pcap.', r: 'sudo tcpdump -ni ens18 -c 50 -w https.pcap "host 192.168.10.54 and tcp port 443"' },
+ { n: 'Application', c: 'À partir de la sortie mtr fournie par l’enseignant, déterminer si la perte vient du réseau local, de l’opérateur ou de la destination, et rédiger le message à envoyer au support de l’opérateur.', r: 'Repérer le premier saut où la perte apparaît ET persiste jusqu’à la destination. Si c’est un saut de l’opérateur, joindre la sortie mtr -rwc 100, l’heure, l’IP source et l’IP destination.' },
+ { n: 'Approfondissement', c: 'Proposer une méthode, avec les commandes, pour distinguer un port fermé d’un port filtré par un pare-feu, depuis un client Linux.', r: 'nc -zv IP port : « refused » immédiat = fermé ; attente puis timeout = filtré.\nConfirmation : sudo tcpdump -ni ens18 host IP and port N → RST reçu (fermé) ou SYN répétés sans réponse (filtré).' },
+ { n: 'Approfondissement', c: 'Un transfert de gros fichiers entre deux sites échoue alors que les petites requêtes passent. Formuler une hypothèse sur la MTU et la vérifier avec ping.', r: 'Hypothèse : un tunnel ou un lien réduit la MTU et les paquets ICMP « Fragmentation needed » sont filtrés.\nTest : ping -M do -s 1472 IP (1500 octets) puis réduire -s jusqu’à ce que ça passe, par exemple 1392 → MTU 1420.' }
+ ],
+ tp: { type: 'Lab VM', url: 'apercu-labs.html', desc: 'Deux VM Debian reliées, pannes injectées par l’enseignant, diagnostic vérifié étape par étape.', etapes: ['Relever l’état réseau complet avec ip -br link, ip -br addr, ip route', 'Mesurer latence et pertes vers la passerelle et vers Internet', 'Localiser une panne avec traceroute -n puis mtr', 'Trouver pourquoi le service web est injoignable avec ss et curl', 'Capturer une connexion avec tcpdump et identifier SYN, SYN-ACK, ACK', 'Rédiger le compte rendu d’incident'] },
+ plusLoin: [['Documentation iproute2 (man ip, man ss)', 'https://man7.org/linux/man-pages/man8/ip.8.html'], ['Documentation officielle de tcpdump et des filtres pcap', 'https://www.tcpdump.org/manpages/pcap-filter.7.html'], ['Wireshark User’s Guide', 'https://www.wireshark.org/docs/wsug_html_chunked/'], ['RFC 792 · ICMP', 'https://www.rfc-editor.org/rfc/rfc792'], ['RFC 9293 · TCP', 'https://www.rfc-editor.org/rfc/rfc9293']]
+});
+
+window.CONTENUS_PLUS = window.CONTENUS_PLUS || {};
+window.CONTENUS_PLUS.diagnostic = {
+ cas: { titre: 'Mise en situation · Le lundi où l’ENT n’a plus répondu', texte: 'Lundi, 8 h 05. Le service informatique du lycée reçoit une dizaine d’appels : l’intranet pédagogique ne s’affiche plus, ni en salle de classe ni en salle des professeurs. Le serveur est une VM Debian hébergée sur l’hyperviseur de l’établissement. Le technicien s’y connecte en SSH, suit sa méthode couche par couche, découvre que le service web a bien redémarré après la mise à jour du week-end mais qu’il n’écoute plus que sur la boucle locale à cause d’une directive Listen modifiée, corrige la configuration, vérifie depuis un poste client puis rédige un compte rendu d’incident pour l’équipe. Temps d’indisponibilité : 25 minutes, dont 5 de diagnostic effectif.' },
+ erreurs: ['Conclure qu’une machine est éteinte parce qu’elle ne répond pas au ping', 'Interpréter les étoiles d’un saut de traceroute comme une panne alors que les sauts suivants répondent', 'Lancer tcpdump sans filtre en SSH et capturer sa propre session', 'Oublier sudo avec ss -p : la colonne Process reste vide', 'Vérifier l’adresse IP sans vérifier le masque', 'Modifier la configuration avec ip addr add et oublier de la rendre permanente', 'Tout redémarrer avant d’avoir compris, et perdre les traces de la panne', 'Tester uniquement depuis le serveur lui-même (curl localhost) sans tester depuis un client'],
+ memo: [
+ ['Commande', 'À quoi ça sert', 'Ce qu’on regarde'],
+ ['ip -br link', 'état des interfaces', 'UP et LOWER_UP'],
+ ['ip -br addr', 'adresses et masques', 'IP attendue, bon préfixe /24, /26…'],
+ ['ip route', 'table de routage', 'ligne default via kubectl rollout undo revient à la version précédente.', exemple: 'apiVersion: apps/v1\nkind: Deployment\nmetadata: { name: resa, namespace: vie-scolaire }\nspec:\n replicas: 3\n selector: { matchLabels: { app: resa } }\n template:\n metadata: { labels: { app: resa } }\n spec:\n containers:\n - name: app\n image: registre.lycee.local/resa:9c1e4f2\n ports: [{ containerPort: 8000 }]\n resources:\n requests: { cpu: 100m, memory: 128Mi }\n limits: { memory: 256Mi }\n readinessProbe: { httpGet: { path: /health, port: 8000 } }\n livenessProbe: { httpGet: { path: /health, port: 8000 }, initialDelaySeconds: 10 }' },
+ { t: 'Services et Ingress', d: '', html: 'Les pods sont éphémères et changent d’adresse. Un Service fournit une adresse stable et un nom DNS (resa.vie-scolaire.svc.cluster.local) et répartit le trafic entre les pods dont les labels correspondent à son sélecteur. Le type ClusterIP est interne, NodePort ouvre un port sur chaque nœud, LoadBalancer demande un équilibreur au fournisseur cloud.', 'événements, sondes, raisons d’échec'], ['kubectl logs
--previous', 'journaux du conteneur précédent'], ['kubectl get events --sort-by=.lastTimestamp', 'derniers événements'], ['kubectl get endpoints -- sh', 'shell dans un pod'], ['kubectl top pods', 'consommation CPU et mémoire'], ['kubectl apply -f fichier.yaml', 'appliquer un état désiré'], ['kubectl auth can-i
On supervise à plusieurs niveaux : matériel (disques, température), système (CPU, mémoire, charge, espace disque), réseau (interfaces, pertes), services (ports, processus), et surtout expérience utilisateur : une sonde qui se connecte réellement à l’ENT et vérifie que la page de connexion s’affiche en moins de deux secondes.' },
+ { t: 'Collecte : agent, SNMP, export', d: '', html: 'Trois modes de collecte coexistent. Un agent installé sur la machine (Zabbix agent, node_exporter) remonte des métriques système détaillées. SNMP interroge les équipements réseau qui ne peuvent pas recevoir d’agent : switchs, bornes, onduleurs, imprimantes ; on lit des valeurs identifiées par des OID dans des MIB. Les applications modernes exposent elles-mêmes leurs métriques sur une page HTTP (/metrics).
SNMPv1 et v2c transmettent la communauté (le « mot de passe ») en clair ; on utilise SNMPv3, avec authentification et chiffrement, ou à défaut on limite v2c en lecture seule à l’adresse du serveur de supervision.' },
+ { t: 'Prometheus et Grafana', d: '', html: 'Prometheus vient chercher (pull) les métriques des cibles à intervalle régulier et les stocke en séries temporelles, chaque série étant identifiée par un nom et des labels (instance, job, mountpoint). Le langage PromQL interroge ces séries : taux, moyennes, prédictions. Les règles d’alerte sont évaluées par Prometheus et envoyées à Alertmanager, qui regroupe, déduplique et notifie par courriel, messagerie ou SMS. Grafana affiche les tableaux de bord.', exemple: '# Espace disque libre en %\n100 * node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}\n\n# Règle : disque plein dans moins de 24 h au rythme actuel\n- alert: DisquePleinSous24h\n expr: predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 24*3600) < 0\n for: 30m\n labels: { severity: warning }\n annotations: { summary: "{{ $labels.instance }} : disque plein sous 24 h" }' },
+ { t: 'Zabbix', d: '', html: 'Zabbix est une solution intégrée très répandue dans les collectivités et les établissements : serveur, base de données, interface web et agents. On y définit des hôtes, auxquels on applique des modèles (templates) qui regroupent éléments (items, les valeurs collectées), déclencheurs (triggers, les conditions d’alerte) et graphiques. Les modèles fournis couvrent Linux, Windows, les principaux switchs et les services courants. La découverte automatique (LLD) crée les éléments pour chaque disque ou chaque interface détectée.' },
+ { t: 'Bien alerter', d: '', html: 'Une alerte doit être actionnable : si personne ne doit rien faire en la recevant, ce n’est pas une alerte mais une information pour un tableau de bord. Trop d’alertes produisent la fatigue d’alerte : l’équipe ne les lit plus, et la vraie panne passe inaperçue.
Les bonnes pratiques : alerter sur les symptômes vus par l’utilisateur plutôt que sur chaque cause possible ; ajouter une durée (for: 5m) pour ignorer les pics d’une seconde ; utiliser des seuils prédictifs (plein dans 24 h) plutôt que fixes ; hiérarchiser (info, avertissement, critique) ; et regrouper les alertes dépendantes : si le routeur d’un site tombe, on veut une alerte, pas cinquante.' },
+ { t: 'Journaux centralisés', d: '', html: 'Les métriques disent qu’il se passe quelque chose ; les journaux disent quoi. On les centralise pour les consulter en un seul endroit et les conserver même si un serveur est compromis : rsyslog ou journald vers un serveur central, ou des piles comme Loki avec Grafana, ou Elasticsearch. La centralisation est aussi une exigence de sécurité : l’ANSSI recommande de conserver et d’horodater les journaux d’authentification et d’administration.' }
+ ],
+ synthese: ['Disponibilité, performance, capacité, erreurs ; latence, trafic, erreurs, saturation', 'Agent, SNMP (v3), métriques exposées', 'Prometheus : pull, séries à labels, PromQL, Alertmanager ; Grafana pour l’affichage', 'Zabbix : hôtes, modèles, éléments, déclencheurs', 'Alertes actionnables, durée, seuils prédictifs, dépendances', 'Journaux centralisés et conservés'],
+ qcm: [
+ ['Quel protocole pour superviser un switch sans agent ?', ['SSH', 'SNMP', 'SMTP', 'DHCP'], 1, 'Lecture d’OID.'],
+ ['Pourquoi préférer SNMPv3 ?', ['Plus rapide', 'Authentification et chiffrement', 'Plus de métriques', 'Obligatoire'], 1, 'v2c envoie la communauté en clair.'],
+ ['Prometheus collecte les métriques en mode :', ['push', 'pull', 'SNMP trap', 'courriel'], 1, 'Il interroge les cibles.'],
+ ['Que fait for: 5m dans une règle d’alerte ?', ['Répète l’alerte', 'N’alerte que si la condition dure 5 minutes', 'Supprime l’alerte', 'Envoie 5 messages'], 1, 'Ignore les pics.'],
+ ['Qu’est-ce qu’une alerte actionnable ?', ['Une alerte rouge', 'Une alerte qui demande une action précise', 'Une alerte fréquente', 'Une alerte par SMS'], 1, 'Sinon c’est du bruit.'],
+ ['Dans Zabbix, un déclencheur est :', ['une valeur collectée', 'une condition qui génère un problème', 'un graphique', 'un agent'], 1, 'Trigger.']
+ ],
+ td: [
+ { n: 'Application', c: 'Lister ce qu’il faut superviser pour l’ENT d’un lycée, du matériel à l’expérience utilisateur, avec un seuil pour chaque élément.', r: 'Disque < 15 % · mémoire > 90 % pendant 10 min · charge > nb de cœurs · port 443 fermé · certificat expirant < 14 j · page de connexion > 2 s · taux de 5xx > 2 % · sauvegarde de la nuit en échec.' },
+ { n: 'Application', c: 'Écrire la requête PromQL du taux d’erreurs HTTP 5xx sur 5 minutes, et la règle d’alerte associée.', r: 'sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > 0.02 avec for: 10m.' },
+ { n: 'Approfondissement', c: 'Le routeur du site B tombe : 40 alertes arrivent en même temps. Proposer la configuration pour n’en recevoir qu’une.', r: 'Zabbix : dépendance des déclencheurs des hôtes du site B envers celui du routeur. Alertmanager : inhibit_rules qui masquent les alertes d’un site quand l’alerte « routeur injoignable » du même site est active.' }
+ ],
+ tp: { type: 'Lab VM', url: 'apercu-labs.html', desc: 'Prometheus, node_exporter, Alertmanager et Grafana sur deux VM.', etapes: ['Installer node_exporter', 'Déclarer la cible dans Prometheus', 'Créer un tableau de bord Grafana', 'Écrire une alerte disque prédictive', 'Remplir le disque et recevoir l’alerte'] },
+ plusLoin: [['Documentation Prometheus', 'https://prometheus.io/docs/'], ['Documentation Zabbix', 'https://www.zabbix.com/documentation/current/fr/manual'], ['Google SRE Book · Monitoring Distributed Systems', 'https://sre.google/sre-book/monitoring-distributed-systems/']] },
+plus: { cas: { titre: '', texte: '' },
+ resolu: { enonce: 'Lundi 7 h 50 : l’alerte « DisquePleinSous24h » est arrivée à 2 h sur le serveur de fichiers, sans que personne ne réagisse. À 7 h 45 le disque est plein et les enseignants ne peuvent plus enregistrer. Rétablir puis fiabiliser la chaîne d’alerte.', etapes: [
+ ['Rétablir le service', 'df -h /srv\n/dev/sdb1 500G 500G 0 100% /srv\nsudo du -xh --max-depth=2 /srv | sort -h | tail -3\n180G /srv/partage/tmp/exports-pronote\n→ Un script d’export mal configuré écrit un fichier toutes les minutes depuis vendredi.'],
+ ['Arrêter la cause et libérer de la place', 'sudo systemctl stop export-pronote.timer\nsudo find /srv/partage/tmp/exports-pronote -mtime +0 -delete\ndf -h /srv\n/dev/sdb1 500G 322G 178G 65% /srv\n→ Les enseignants peuvent de nouveau enregistrer.'],
+ ['Comprendre pourquoi l’alerte n’a servi à rien', 'amtool alert query DisquePleinSous24h\nalertname=DisquePleinSous24h severity=warning instance=fichiers:9100\n→ L’alerte a bien été émise, mais en severity warning, routée vers une adresse de courriel lue seulement en journée.'],
+ ['Corriger le routage', 'route:\n routes:\n - matchers: [severity="critical"]\n receiver: astreinte-sms\n# nouvelle règle : disque plein sous 6 h → critical\n→ L’alerte à 24 h reste un avertissement par courriel ; une seconde règle à 6 h devient critique et part vers l’astreinte.'],
+ ['Superviser la cause', '→ Ajout d’une alerte sur le nombre de fichiers créés par heure dans /srv/partage/tmp, et correction du script d’export (rotation des anciens fichiers). Compte rendu : l’outil avait détecté le problème six heures à l’avance ; le défaut était dans l’organisation de la réponse.']
+ ] },
+ erreurs: ['Alerter sur tout, sans hiérarchie', 'Seuils fixes sans durée', 'Aucune supervision de l’expérience utilisateur', 'SNMP v2c en écriture avec la communauté public', 'Alertes envoyées à une boîte que personne ne lit', 'Oublier de superviser les sauvegardes et les certificats'],
+ memo: [['Outil / commande', 'Usage'], ['curl -s localhost:9100/metrics | head', 'vérifier un node_exporter'], ['promtool check config prometheus.yml', 'valider la configuration'], ['promtool check rules regles.yml', 'valider les règles d’alerte'], ['amtool alert query', 'alertes actives dans Alertmanager'], ['snmpwalk -v3 -l authPriv … CN=Léa M.,OU=SIO1,OU=Eleves,DC=lycee,DC=local. Les entrées appartiennent à des classes d’objets (user, group, organizationalUnit) qui définissent leurs attributs (sAMAccountName, mail, memberOf). LDAP écoute sur le port 389, LDAPS (chiffré) sur 636.' },
+ { t: 'Active Directory : domaine, forêt, contrôleurs', d: '', html: 'Un domaine AD regroupe comptes, groupes et ordinateurs sous une même autorité, avec un nom DNS (lycee.local, ou mieux un sous-domaine d’un domaine possédé : ad.lycee-exemple.fr). Les contrôleurs de domaine (DC) hébergent l’annuaire et le répliquent entre eux ; on en installe au moins deux. Plusieurs domaines peuvent former une forêt.
AD dépend entièrement du DNS : les clients trouvent les DC grâce aux enregistrements SRV (_ldap._tcp.dc._msdcs.lycee.local). Un poste qui n’utilise pas le DNS du domaine ne peut pas le rejoindre. L’authentification repose sur Kerberos, qui impose des horloges synchronisées à cinq minutes près.' },
+ { t: 'Organiser : OU, groupes et délégation', d: '', html: 'Les unités d’organisation (OU) rangent les objets pour appliquer des stratégies et déléguer l’administration : OU Eleves, Professeurs, Administration, Ordinateurs\\Salles. Les groupes portent les droits. La méthode AGDLP résume la bonne pratique : les comptes (A) vont dans des groupes globaux par fonction (G, « Profs-SIO »), placés dans des groupes locaux de domaine par ressource (DL, « Partage-SIO-Modification »), auxquels on donne les permissions (P). On ne donne jamais un droit directement à un utilisateur.' },
+ { t: 'Stratégies de groupe (GPO)', d: '', html: 'Une GPO applique des paramètres aux ordinateurs et aux utilisateurs d’une OU : fond d’écran, lecteurs réseau, imprimantes, mises à jour, pare-feu, restrictions, déploiement de logiciels. L’ordre d’application est LSDOU : local, site, domaine, OU (de la plus haute à la plus basse) ; la dernière appliquée l’emporte, sauf blocage ou application forcée. gpupdate /force applique immédiatement, gpresult /r montre les GPO effectivement reçues.' },
+ { t: 'Samba et intégration Linux', d: '', html: 'Samba partage des fichiers et des imprimantes avec les postes Windows (protocole SMB) et peut même servir de contrôleur de domaine compatible AD, solution répandue dans les établissements attachés aux logiciels libres. Un serveur Linux rejoint un domaine AD avec realmd et SSSD (realm join) : les comptes du domaine s’y connectent en SSH et les groupes AD pilotent les droits sudo.', exemple: 'sudo realm discover lycee.local\nsudo realm join -U administrateur lycee.local\nid lea.martin@lycee.local\nuid=1854201103(lea.martin@lycee.local) … groupes=…(eleves-sio1@lycee.local)' },
+ { t: 'Sécurité de l’annuaire', d: '', html: 'L’annuaire est la cible principale des attaquants : compromettre un compte d’administrateur du domaine, c’est posséder tout le réseau. Les recommandations de l’ANSSI s’organisent en niveaux (tiering) : les comptes d’administration du domaine ne se connectent qu’aux DC, jamais à un poste utilisateur. Autres mesures : comptes d’administration séparés des comptes du quotidien, mots de passe longs, LAPS pour des mots de passe administrateur local différents sur chaque poste, désactivation des protocoles anciens (NTLMv1, SMBv1), LDAPS ou signature LDAP, et audit régulier avec des outils comme PingCastle.' }
+ ],
+ synthese: ['LDAP : arbre, DN, classes et attributs ; 389 et 636', 'AD : domaine, forêt, au moins deux DC ; dépend du DNS et de Kerberos', 'OU pour organiser et appliquer, groupes pour les droits (AGDLP)', 'GPO appliquées en LSDOU ; gpresult pour vérifier', 'Samba, realmd et SSSD pour Linux', 'Tiering, comptes séparés, LAPS, protocoles anciens désactivés'],
+ qcm: [
+ ['Que désigne un DN ?', ['Un nom DNS', 'Le chemin unique d’une entrée dans l’arbre LDAP', 'Un groupe', 'Un port'], 1, 'Distinguished Name.'],
+ ['Pourquoi un poste ne trouve-t-il pas le domaine ?', ['Pare-feu Windows', 'Il n’utilise pas le DNS du domaine', 'Mauvais fond d’écran', 'LAPS'], 1, 'Enregistrements SRV.'],
+ ['Quel écart d’horloge maximal tolère Kerberos par défaut ?', ['1 s', '5 min', '1 h', 'Aucun'], 1, 'D’où NTP obligatoire.'],
+ ['Où donner une permission sur un partage selon AGDLP ?', ['À l’utilisateur', 'À un groupe local de domaine', 'À l’OU', 'Au DC'], 1, 'Comptes → global → local → permission.'],
+ ['Quelle commande montre les GPO reçues par un poste ?', ['gpupdate', 'gpresult /r', 'ipconfig', 'netstat'], 1, 'Résultat de la stratégie.'],
+ ['Quel outil donne un mot de passe administrateur local différent à chaque poste ?', ['GPO', 'LAPS', 'SSSD', 'Kerberos'], 1, 'Local Administrator Password Solution.']
+ ],
+ td: [
+ { n: 'Application', c: 'Proposer l’arborescence d’OU et les groupes d’un lycée avec BTS SIO, sa salle de TP et le partage « Sujets » accessible en modification aux profs de SIO, en lecture aux élèves de SIO.', r: 'OU Utilisateurs\\Eleves\\SIO1, SIO2 · OU Utilisateurs\\Profs · OU Ordinateurs\\Salles\\B204 · groupes globaux G-Eleves-SIO, G-Profs-SIO · groupes locaux DL-Sujets-Lecture, DL-Sujets-Modif · permissions NTFS et partage sur ces DL.' },
+ { n: 'Application', c: 'Écrire la requête ldapsearch qui liste les comptes de l’OU SIO1 avec leur adresse mail.', r: 'ldapsearch -H ldaps://dc1.lycee.local -D "cn=lecture,…" -W -b "OU=SIO1,OU=Eleves,DC=lycee,DC=local" "(objectClass=user)" sAMAccountName mail' },
+ { n: 'Approfondissement', c: 'Expliquer pourquoi un administrateur du domaine ne doit pas ouvrir de session sur un poste d’élève.', r: 'Son jeton ou ses identifiants restent en mémoire du poste ; si celui-ci est compromis, l’attaquant les récupère et devient administrateur du domaine (modèle de tiering de l’ANSSI).' }
+ ],
+ tp: { type: 'Lab VM', url: 'apercu-labs.html', desc: 'Un contrôleur Samba AD, un client Windows et un serveur Linux.', etapes: ['Provisionner le domaine Samba AD', 'Vérifier les enregistrements SRV', 'Créer OU, comptes et groupes', 'Joindre le serveur Linux avec realmd', 'Appliquer une GPO de lecteur réseau'] },
+ plusLoin: [['ANSSI · Recommandations de sécurité relatives à Active Directory', 'https://cyber.gouv.fr/publications/recommandations-de-securite-relatives-active-directory'], ['Samba Wiki · Setting up Samba as an AD DC', 'https://wiki.samba.org/index.php/Setting_up_Samba_as_an_Active_Directory_Domain_Controller'], ['PingCastle', 'https://www.pingcastle.com/']] },
+plus: { cas: { titre: '', texte: '' },
+ resolu: { enonce: 'Ce matin, aucun élève de la salle B204 ne parvient à ouvrir de session (« La relation d’approbation entre cette station de travail et le domaine principal a échoué » sur certains postes, « L’heure du serveur diffère » sur d’autres). Les autres salles fonctionnent.', etapes: [
+ ['Vérifier l’heure', 'Sur un poste de B204 (session locale) : w32tm /stripchart /computer:dc1.lycee.local /samples:1\n11:47:02, d:+00.0012s o:-00:07:41.3\n→ Le poste a 7 min 41 s de retard sur le DC : Kerberos refuse l’authentification au-delà de 5 minutes.'],
+ ['Trouver pourquoi', 'w32tm /query /source\nLocal CMOS Clock\n→ Les postes de B204, réinstallés pendant les vacances à partir d’une image, ne prennent plus l’heure du domaine.'],
+ ['Corriger l’heure', 'w32tm /config /syncfromflags:domhier /update\nnet stop w32time && net start w32time\nw32tm /resync\n→ Le poste se synchronise sur la hiérarchie du domaine.'],
+ ['Réparer la relation d’approbation', 'Sur les postes au message « relation d’approbation » :\nTest-ComputerSecureChannel -Repair -Credential lycee\\technicien\nTrue\n→ Le mot de passe du compte ordinateur, restauré depuis une image ancienne, ne correspondait plus à celui de l’annuaire ; le canal sécurisé est réinitialisé.'],
+ ['Généraliser et prévenir', '→ La correction est déployée par GPO sur l’OU Salles (source de temps du domaine) ; les images de poste sont préparées avec Sysprep et jointes au domaine après déploiement. Compte rendu rédigé.']
+ ] },
+ erreurs: ['Postes qui n’utilisent pas le DNS du domaine', 'Horloges non synchronisées', 'Un seul contrôleur de domaine', 'Droits donnés directement aux utilisateurs', 'Administrateur du domaine utilisé sur les postes', 'Même mot de passe administrateur local partout', 'LDAP simple non chiffré'],
+ memo: [['Commande', 'Usage'], ['nslookup -type=SRV _ldap._tcp.dc._msdcs.lycee.local', 'trouver les contrôleurs de domaine'], ['ldapsearch -H ldaps://… -b … "(filtre)"', 'interroger l’annuaire'], ['gpupdate /force', 'appliquer les GPO'], ['gpresult /r', 'GPO effectivement appliquées'], ['w32tm /query /status', 'source et écart de temps'], ['Test-ComputerSecureChannel -Repair', 'réparer la relation avec le domaine'], ['samba-tool user create|list', 'gérer les comptes Samba AD'], ['samba-tool drs showrepl', 'état de la réplication'], ['realm join -U admin domaine', 'joindre un Linux au domaine'], ['id utilisateur@domaine', 'vérifier un compte depuis Linux']],
+ examen: { titre: 'Sujet type · 20 points', q: ['Décrire le rôle de DNS et Kerberos dans AD. (4 pts)', 'Proposer OU et groupes pour un cas donné selon AGDLP. (6 pts)', 'Expliquer l’ordre d’application des GPO et diagnostiquer une GPO non appliquée. (5 pts)', 'Citer cinq mesures de sécurité de l’annuaire. (5 pts)'], r: ['SRV, tickets, horloge', 'voir TD', 'LSDOU, gpresult', 'tiering, LAPS, comptes séparés, NTLMv1/SMBv1, audit'] },
+ prof: { deroule: [['Ouverture', 'Combien de mots de passe auriez-vous sans annuaire ?'], ['Cours', 'LDAP, AD, DNS, Kerberos'], ['Pratique', 'Lab Samba AD'], ['Incident', 'Heure et relation d’approbation'], ['Clôture', 'Quiz flash']], diff: 'Élèves en difficulté : arborescence fournie. Élèves avancés : audit PingCastle, tiering.', eval: 'Lab validé, sujet type.' } },
+exemples: [
+ ['Trouver les contrôleurs de domaine', 'Un poste ne rejoint pas le domaine.', 'nslookup -type=SRV _ldap._tcp.dc._msdcs.lycee.local', '_ldap._tcp.dc._msdcs.lycee.local SRV service location:\n priority = 0, weight = 100, port = 389, svr hostname = dc1.lycee.local\n priority = 0, weight = 100, port = 389, svr hostname = dc2.lycee.local', 'Les deux DC sont annoncés. Si la commande échoue, le poste n’interroge pas le DNS du domaine : on vérifie sa configuration DNS avant tout le reste.'],
+ ['Chercher un compte', 'Retrouver les groupes d’un élève.', 'ldapsearch -LLL -H ldaps://dc1.lycee.local -D "CN=lecture,OU=Services,DC=lycee,DC=local" -W -b "DC=lycee,DC=local" "(sAMAccountName=lea.martin)" memberOf', 'dn: CN=Léa M.,OU=SIO1,OU=Eleves,DC=lycee,DC=local\nmemberOf: CN=G-Eleves-SIO,OU=Groupes,DC=lycee,DC=local', 'LDAPS chiffre l’échange ; le compte de lecture dédié n’a aucun autre droit.'],
+ ['Vérifier les GPO d’un poste', 'Le lecteur réseau n’apparaît pas.', 'gpresult /r /scope:user', 'Objets Stratégie de groupe appliqués\n GPO-Eleves-Fond\nLes GPO suivants n’ont pas été appliqués car ils ont été filtrés\n GPO-Lecteurs-SIO\n Filtrage : Refusé (Sécurité)', 'La GPO des lecteurs est filtrée par sécurité : le groupe de l’élève n’a pas le droit « Appliquer la stratégie de groupe ».'],
+ ['Contrôler la réplication', 'Un compte créé sur dc1 n’existe pas sur dc2.', 'sudo samba-tool drs showrepl | grep -A3 "INBOUND" | tail -3', 'DC=lycee,DC=local\n Default-First-Site-Name\\DC1 via RPC\n Last attempt @ … failed, result 1256 (WERR_NO_SUCH_SERVICE)', 'La réplication de dc1 vers dc2 échoue. On vérifie la résolution de dc1 depuis dc2 et l’ouverture des ports RPC.'],
+ ['Joindre un Linux au domaine', 'Nouveau serveur Debian.', 'sudo realm join -U technicien lycee.local && realm list | grep -E "realm-name|configured"', 'realm-name: LYCEE.LOCAL\nconfigured: kerberos-member', 'Le serveur est membre ; les comptes du domaine peuvent s’y connecter selon les règles de realm permit.'],
+ ['Repérer les mots de passe qui n’expirent pas', 'Audit des comptes.', 'Get-ADUser -Filter {PasswordNeverExpires -eq $true -and Enabled -eq $true} | Select Name', 'Name\n----\nsvc-sauvegarde\nancien.stagiaire', 'Un compte de stagiaire parti est encore actif avec un mot de passe éternel : on le désactive. Le compte de service doit devenir un compte de service géré (gMSA).']
+],
+termes: ['LDAP', 'LDAPS', 'DN', 'OU', 'Active Directory', 'domaine', 'forêt', 'contrôleur de domaine', 'Kerberos', 'SRV', 'GPO', 'LSDOU', 'AGDLP', 'gpupdate', 'gpresult', 'Samba', 'SSSD', 'realmd', 'LAPS', 'tiering', 'NTLM', 'SMB', 'ldapsearch', 'samba-tool']
+});
+})();
diff --git a/design/js/contenus-long.js b/design/js/contenus-long.js
new file mode 100644
index 0000000..d1e2790
--- /dev/null
+++ b/design/js/contenus-long.js
@@ -0,0 +1,64 @@
+// Lecture longue, schémas et emplacements photo pour chaque cours complet
+(function () {
+var K = 'stroke="#000" stroke-width="3"';
+var box = function (x, y, w, h, fill, txt, fs) { return 'sorted, Timsort), mais comprendre ces algorithmes permet de raisonner sur les coûts et de réussir les épreuves.', exemple: 'def dichotomie(t, x):\n g, d = 0, len(t) - 1\n while g <= d:\n m = (g + d) // 2\n if t[m] == x:\n return m\n if t[m] < x:\n g = m + 1\n else:\n d = m - 1\n return -1' },
+ { t: 'Récursivité', d: '', html: 'Une fonction récursive s’appelle elle-même sur un problème plus petit, jusqu’à un cas de base qui s’arrête. Elle exprime naturellement les problèmes à structure récursive : parcours d’arborescence de fichiers, tri fusion, calculs sur des arbres. Chaque appel occupe une place sur la pile d’appels : sans cas de base atteint, on obtient un dépassement (RecursionError en Python, limite par défaut de 1 000 appels). Certaines récursions recalculent plusieurs fois les mêmes valeurs (Fibonacci naïf en O(2ⁿ)) : la mémoïsation (functools.cache) ou une version itérative corrige le problème.' },
+ { t: 'Structures de données linéaires', d: '', html: 'Une pile (LIFO, dernier entré premier sorti) sert à l’historique d’annulation, à la pile d’appels, à la vérification des parenthèses. Une file (FIFO) sert aux files d’attente : impressions, requêtes, mains levées dans l’ordre d’arrivée. En Python, une liste fait une bonne pile (append, pop), mais une mauvaise file (pop(0) en O(n)) : on utilise collections.deque. Une liste chaînée relie des maillons par des références : insertion en tête en O(1), accès au k-ième élément en O(k). Le dictionnaire (table de hachage) donne un accès moyen en O(1) par clé : c’est souvent la structure qui transforme un O(n²) en O(n).' },
+ { t: 'Graphes et parcours', d: '', html: 'Un graphe est un ensemble de sommets reliés par des arêtes, éventuellement orientées et pondérées : routeurs et liens, pages web, dépendances entre tâches. On le représente par une matrice d’adjacence ou, plus économiquement, par des listes d’adjacence (un dictionnaire de voisins). Le parcours en largeur (BFS, avec une file) visite par distance croissante et trouve le plus court chemin en nombre d’arêtes ; le parcours en profondeur (DFS, avec une pile ou la récursivité) sert à détecter des cycles ou des composantes connexes.' },
+ { t: 'Plus courts chemins : Dijkstra', d: '', html: 'L’algorithme de Dijkstra calcule les plus courts chemins depuis un sommet dans un graphe à poids positifs : il sélectionne à chaque étape le sommet non traité le plus proche et met à jour les distances de ses voisins. Avec une file de priorité (heapq), il s’exécute en O((V + E) log V). C’est exactement ce que fait chaque routeur OSPF pour construire sa table de routage à partir de la carte du réseau, avec un coût par lien inversement proportionnel au débit.', exemple: 'import heapq\ndef dijkstra(g, s):\n dist = {s: 0}\n file = [(0, s)]\n while file:\n d, u = heapq.heappop(file)\n if d > dist[u]:\n continue\n for v, w in g[u].items():\n if d + w < dist.get(v, float("inf")):\n dist[v] = d + w\n heapq.heappush(file, (d + w, v))\n return dist' }
+ ],
+ synthese: ['Complexité O : O(1) < O(log n) < O(n) < O(n log n) < O(n²) < O(2ⁿ)', 'Dichotomie sur tableau trié en O(log n) ; tri fusion en O(n log n)', 'Récursivité : cas de base, pile d’appels, mémoïsation', 'Pile LIFO, file FIFO avec deque, dictionnaire en O(1) moyen', 'Graphes : listes d’adjacence ; BFS et DFS', 'Dijkstra et OSPF'],
+ qcm: [
+ ['Complexité de la recherche dichotomique ?', ['O(1)', 'O(log n)', 'O(n)', 'O(n²)'], 1, 'On divise par deux à chaque étape.'],
+ ['Condition pour utiliser la dichotomie ?', ['Tableau trié', 'Tableau court', 'Nombres entiers', 'Aucune'], 0, 'Sinon on ne sait pas quelle moitié choisir.'],
+ ['Quelle structure pour une file d’attente en Python ?', ['list avec pop(0)', 'collections.deque', 'set', 'tuple'], 1, 'popleft en O(1).'],
+ ['Que manque-t-il à une récursion qui provoque RecursionError ?', ['Un return', 'Un cas de base atteint', 'Une boucle', 'Un print'], 1, 'Elle ne s’arrête jamais.'],
+ ['Quel parcours trouve le plus court chemin en nombre d’arêtes ?', ['DFS', 'BFS', 'Tri fusion', 'Dichotomie'], 1, 'Par distance croissante.'],
+ ['Quel protocole de routage utilise Dijkstra ?', ['RIP', 'OSPF', 'DHCP', 'ARP'], 1, 'État de liens.'],
+ ['Deux boucles imbriquées sur n éléments :', ['O(n)', 'O(n²)', 'O(log n)', 'O(2n)'], 1, 'n × n.']
+ ],
+ td: [
+ { n: 'Échauffement', c: 'Donner la complexité de : parcourir une liste ; vérifier si deux listes ont un élément commun avec deux boucles ; même chose en transformant la seconde en ensemble.', r: 'O(n) · O(n × m) · O(n + m)' },
+ { n: 'Application', c: 'Écrire un tri par insertion, puis compter le nombre de comparaisons sur une liste déjà triée et sur une liste triée à l’envers de 1 000 éléments.', r: 'Déjà triée : environ n comparaisons (O(n)) · à l’envers : environ n²/2 = 500 000 (O(n²)).' },
+ { n: 'Application', c: 'Vérifier le bon parenthésage d’une expression avec une pile.', r: 'Empiler chaque ouvrante ; pour chaque fermante, la pile ne doit pas être vide et son sommet doit correspondre ; à la fin, la pile doit être vide.' },
+ { n: 'Approfondissement', c: 'Appliquer Dijkstra à la main sur un réseau de cinq routeurs fourni, puis en déduire la table de routage du routeur A.', r: 'Tableau des distances étape par étape ; la table associe à chaque destination le premier saut du plus court chemin.' }
+ ],
+ tp: { type: 'IDE Python', url: 'apercu-ide.html', desc: 'Exercices avec tests et mesure du temps d’exécution.', etapes: ['Dichotomie et tests', 'Tri fusion', 'Comparaison des temps selon n', 'File des mains levées avec deque', 'BFS sur un plan de salles', 'Dijkstra sur un réseau de routeurs'] },
+ plusLoin: [['France-IOI · parcours algorithmique', 'https://www.france-ioi.org/'], ['HackerRank · Data Structures et Algorithms', 'https://www.hackerrank.com/domains/algorithms'], ['VisuAlgo (visualisation)', 'https://visualgo.net/fr']] },
+plus: { cas: { titre: '', texte: '' },
+ resolu: { enonce: 'Le calcul des doublons dans l’export des 12 000 élèves de l’académie prend 40 minutes. Rendre le traitement quasi instantané.', etapes: [
+ ['Lire le code', 'for a in eleves:\n for b in eleves:\n if a is not b and a["ine"] == b["ine"]: doublons.append(a)\n→ Deux boucles imbriquées : 144 millions de comparaisons, O(n²).'],
+ ['Choisir la structure', '→ Un dictionnaire (ou un Counter) compte les occurrences de chaque identifiant en un seul parcours.'],
+ ['Réécrire', 'from collections import Counter\nc = Counter(e["ine"] for e in eleves)\ndoublons = [e for e in eleves if c[e["ine"]] > 1]\n→ Deux parcours : O(n).'],
+ ['Mesurer', 'Temps : 40 min → 0,02 s\n→ Même résultat vérifié par un test sur un petit jeu de données connu.'],
+ ['Retenir', '→ Devant une double boucle de recherche, se demander quelle clé permettrait un accès direct par dictionnaire ou ensemble.']
+ ] },
+ erreurs: ['Dichotomie sur une liste non triée', 'Oublier le cas de base', 'list.pop(0) pour une file', 'Double boucle là où un dictionnaire suffit', 'Recalculer sans mémoïsation', 'Dijkstra avec des poids négatifs'],
+ memo: [['Outil', 'Usage'], ['len, in sur set/dict', 'O(1) en moyenne'], ['sorted(t, key=…)', 'tri O(n log n)'], ['bisect', 'dichotomie de la bibliothèque'], ['collections.deque', 'file'], ['collections.Counter', 'compter'], ['heapq', 'file de priorité'], ['functools.cache', 'mémoïsation'], ['timeit', 'mesurer le temps'], ['assert f(x) == y', 'tests simples'], ['sys.setrecursionlimit', 'limite de récursion (avec prudence)']],
+ examen: { titre: 'Sujet type · 20 points', q: ['Déterminer la complexité de trois fonctions. (4 pts)', 'Écrire la recherche dichotomique et ses tests. (4 pts)', 'Écrire une fonction récursive et justifier sa terminaison. (4 pts)', 'Implémenter une file avec deque. (3 pts)', 'Appliquer Dijkstra à la main. (5 pts)'], r: ['O(n), O(n²), O(log n)', 'voir cours', 'cas de base, taille décroissante', 'append / popleft', 'tableau des distances'] },
+ prof: { deroule: [['Ouverture', 'Chronométrer une double boucle puis un dictionnaire'], ['Cours', 'Complexité'], ['Pratique', 'Tris et dichotomie'], ['Cours', 'Récursivité et structures'], ['Pratique', 'Graphes et Dijkstra'], ['Clôture', 'Quiz flash']], diff: 'Élèves en difficulté : visualisations VisuAlgo. Élèves avancés : HackerRank Medium, A*.', eval: 'Tests IDE, sujet type.' } },
+exemples: [
+ ['Comparer deux complexités', 'Justifier un choix.', 'python3 -m timeit -s "l=list(range(10**5)); s=set(l)" "99999 in l"\npython3 -m timeit -s "l=list(range(10**5)); s=set(l)" "99999 in s"', '500 loops, best of 5: 612 usec per loop\n5000000 loops, best of 5: 42.1 nsec per loop', 'La recherche dans un ensemble est environ 15 000 fois plus rapide que dans une liste.'],
+ ['Dichotomie de la bibliothèque', 'Retrouver un seuil de note.', 'import bisect; bisect.bisect_left([8, 10, 12, 14, 16], 13)', '3', 'Position d’insertion de 13 dans la liste triée, en O(log n).'],
+ ['Limite de récursion', 'Fonction récursive sur une longue liste.', 'def somme(l): return 0 if not l else l[0] + somme(l[1:])\nsomme(list(range(5000)))', 'RecursionError: maximum recursion depth exceeded', 'Au-delà de 1 000 appels : on écrit une version itérative, plus adaptée ici.'],
+ ['Mémoïsation', 'Fibonacci lent.', 'from functools import cache\n@cache\ndef fib(n): return n if n < 2 else fib(n-1) + fib(n-2)\nfib(200)', '280571172992510140037611932413038677189525', 'Instantané grâce au cache ; la version naïve ne terminerait pas.'],
+ ['File des mains levées', 'Fonction Lever la main.', 'from collections import deque\nq = deque(["Nora", "Yanis"]); q.append("Léa"); q.popleft(), list(q)', "('Nora', ['Yanis', 'Léa'])", 'Premier arrivé, premier servi, en O(1).'],
+ ['Plus courts chemins', 'Réseau de quatre routeurs.', 'g = {"A":{"B":10,"C":1},"B":{"D":1},"C":{"B":1,"D":20},"D":{}}\ndijkstra(g, "A")', "{'A': 0, 'C': 1, 'B': 2, 'D': 3}", 'Le chemin vers D passe par C puis B (coût 3) plutôt que par le lien direct C–D (21).']
+],
+termes: ['complexité', 'O(n)', 'O(log n)', 'O(n²)', 'O(n log n)', 'recherche dichotomique', 'tri par insertion', 'tri fusion', 'récursivité', 'cas de base', 'pile d’appels', 'mémoïsation', 'pile', 'file', 'deque', 'liste chaînée', 'dictionnaire', 'graphe', 'BFS', 'DFS', 'Dijkstra', 'heapq']
+});
+
+reg({
+cours: { id: 'backend', match: /Laravel|MVC|API REST|OpenAPI|Authentification : sessions|OAuth|PHP : bases|Framework back|Déployer une application web|Sécurité web|CSP|CORS|Tests : unitaires, intégration/i,
+ titre: 'Développement web back-end : MVC avec Laravel, API REST, authentification et sécurité', duree: '',
+ niveau: 'BTS SIO SLAM · BUT Informatique · licence pro · Master',
+ prerequis: ['Le Web : HTTP et HTML', 'SQL', 'Git'],
+ competences: ['BTS SIO SLAM · Bloc 2 · Concevoir et développer une solution applicative', 'BTS SIO · Bloc 3 · Cybersécurité des services', 'BUT Info · Réaliser et déployer'],
+ intro: 'Une application web professionnelle se compose d’une interface, d’une logique métier, d’une base de données et d’une API, le tout sécurisé et testé. Les frameworks comme Laravel, sur lequel est construit Syllabus, apportent une organisation éprouvée et des protections intégrées. Ce module présente l’architecture MVC, le routage, l’ORM, la conception d’une API REST, l’authentification, les protections contre les failles courantes et le déploiement.',
+ cm: [
+ { t: 'Architecture MVC', d: '', html: 'Le motif Modèle-Vue-Contrôleur sépare les responsabilités. Le modèle représente les données et les règles métier (un élève, une classe, un devoir). La vue présente les données (templates Blade). Le contrôleur reçoit la requête, appelle le modèle et choisit la vue ou la réponse. Le routeur associe chaque URL et méthode HTTP à une action. Cette séparation rend le code testable et permet à plusieurs développeurs de travailler en parallèle.', exemple: '// routes/web.php\nRoute::middleware("auth")->group(function () {\n Route::get("/classes/{classe}", [ClasseController::class, "show"])->name("classes.show");\n});\n\n// app/Http/Controllers/ClasseController.php\npublic function show(Classe $classe) {\n $this->authorize("view", $classe);\n return view("classes.show", [\n "classe" => $classe->load("eleves"),\n ]);\n}' },
+ { t: 'Modèles, ORM et migrations', d: '', html: 'L’ORM Eloquent associe chaque table à une classe : Eleve::where("classe_id", 3)->orderBy("nom")->get() produit une requête SQL préparée. Les relations (hasMany, belongsTo, belongsToMany) décrivent les clés étrangères. Les migrations versionnent le schéma de la base avec le code : chaque modification est un fichier, appliqué dans le même ordre partout. Piège de performance classique : le problème N+1, une requête par élément d’une liste, évité par le chargement anticipé (with("eleves")).' },
+ { t: 'Concevoir une API REST', d: '', html: 'Une API REST expose des ressources identifiées par des URL et manipulées par les méthodes HTTP : GET /api/devoirs liste, POST /api/devoirs crée, GET /api/devoirs/12 lit, PUT ou PATCH modifie, DELETE supprime. Les réponses sont en JSON avec des codes cohérents : 200, 201 Created, 204 No Content, 400 et 422 pour une requête invalide, 401 non authentifié, 403 interdit, 404 introuvable. On versionne l’API (/api/v1), on pagine les listes, et on la documente avec OpenAPI, qui génère une documentation interactive et des clients.' },
+ { t: 'Authentification et autorisation', d: '', html: 'L’authentification établit qui est l’utilisateur ; l’autorisation décide de ce qu’il peut faire. Pour une application web, une session côté serveur, identifiée par un cookie HttpOnly, Secure et SameSite, reste la solution la plus sûre. Pour une API consommée par d’autres applications, on utilise des jetons (tokens d’API, Laravel Sanctum) ou OAuth 2 / OpenID Connect pour déléguer l’authentification à un fournisseur d’identité (ENT, EduConnect). Les mots de passe sont hachés avec bcrypt ou Argon2. L’autorisation se centralise dans des politiques (policies) : un professeur ne voit que ses classes.' },
+ { t: 'Sécurité : les failles courantes', d: '', html: 'L’OWASP Top 10 recense les failles les plus fréquentes. Contrôle d’accès défaillant : changer un identifiant dans l’URL donne accès aux données d’un autre (IDOR) ; on vérifie l’autorisation à chaque action. Injection : requêtes préparées systématiques. XSS : Blade échappe automatiquement {{ }} ; {!! !!} ne s’utilise que sur du contenu maîtrisé. CSRF : un jeton dans chaque formulaire (@csrf). Assignation de masse : déclarer les champs modifiables ($fillable). À quoi s’ajoutent les en-têtes : Content-Security-Policy contre l’injection de scripts, CORS limité aux origines autorisées, HSTS.', attention: 'Le mode débogage (APP_DEBUG=true) en production affiche les traces d’erreur, les variables d’environnement et parfois les mots de passe de la base. Il doit être désactivé, et le fichier .env ne doit jamais être accessible par le web ni versionné.' },
+ { t: 'Tester et déployer', d: '', html: 'Les tests unitaires vérifient une classe isolée, les tests de fonctionnalité envoient de vraies requêtes à l’application ($this->actingAs($prof)->get("/classes/3")->assertOk()), les tests de bout en bout pilotent un navigateur. Le déploiement suit toujours les mêmes étapes, automatisées par la CI : récupération du code, composer install --no-dev, migrations, mise en cache de la configuration et des routes, redémarrage des workers de file d’attente, derrière Nginx et PHP-FPM, avec un retour arrière possible.' }
+ ],
+ synthese: ['MVC : modèle, vue, contrôleur, routeur', 'ORM et migrations ; éviter le N+1 avec with()', 'REST : ressources, méthodes, codes HTTP, JSON, versionnement, OpenAPI', 'Session sécurisée ou jetons ; OAuth 2 / OIDC ; policies pour l’autorisation', 'OWASP : contrôle d’accès, injection, XSS, CSRF, assignation de masse ; en-têtes', 'APP_DEBUG=false, .env protégé ; tests et déploiement automatisés'],
+ qcm: [
+ ['Dans MVC, qui reçoit la requête et choisit la réponse ?', ['Le modèle', 'Le contrôleur', 'La vue', 'La base'], 1, 'Il orchestre.'],
+ ['Quelle méthode pour créer une ressource en REST ?', ['GET', 'POST', 'DELETE', 'HEAD'], 1, 'Réponse 201.'],
+ ['Code HTTP pour « authentifié mais pas autorisé » ?', ['401', '403', '404', '500'], 1, '401 = non authentifié.'],
+ ['Qu’est-ce que le problème N+1 ?', ['Une faille', 'Une requête SQL par élément d’une liste', 'Un code HTTP', 'Une erreur de migration'], 1, 'Chargement anticipé.'],
+ ['Protection contre le CSRF ?', ['Un jeton dans chaque formulaire', 'HTTPS seul', 'Un captcha', 'Le hachage'], 0, '@csrf.'],
+ ['Pourquoi désactiver APP_DEBUG en production ?', ['Performance', 'Il expose des informations sensibles', 'Obligation légale', 'Pour le cache'], 1, 'Traces, variables, secrets.']
+ ],
+ td: [
+ { n: 'Application', c: 'Concevoir les routes REST de la ressource « devoirs » d’une classe, avec les codes de réponse attendus.', r: 'GET /api/v1/classes/{c}/devoirs 200 · POST 201 · GET /devoirs/{d} 200/404 · PATCH 200/422 · DELETE 204 · 401 sans jeton, 403 si pas professeur de la classe.' },
+ { n: 'Application', c: 'Corriger la faille : « public function show($id) { return Eleve::find($id); } ».', r: 'Liaison de modèle + autorisation : show(Eleve $eleve) { $this->authorize("view", $eleve); return $eleve; } avec une policy vérifiant que l’élève appartient à une classe du professeur.' },
+ { n: 'Approfondissement', c: 'Écrire un test de fonctionnalité qui vérifie qu’un professeur ne peut pas voir la fiche d’un élève d’une autre classe.', r: '$prof = User::factory()->prof()->create(); $eleve = Eleve::factory()->create(); $this->actingAs($prof)->get(route("eleves.show", $eleve))->assertForbidden();' }
+ ],
+ tp: { type: 'IDE', url: 'apercu-ide.html', desc: 'Mini-application Laravel de gestion de devoirs.', etapes: ['Migration et modèle', 'Contrôleur et vues', 'API REST', 'Policy d’autorisation', 'Tests de fonctionnalité', 'Déploiement par CI'] },
+ plusLoin: [['Documentation Laravel', 'https://laravel.com/docs'], ['OWASP Top 10', 'https://owasp.org/Top10/fr/'], ['OpenAPI Specification', 'https://spec.openapis.org/oas/latest.html'], ['ANSSI · Recommandations pour la mise en œuvre d’un site web', 'https://cyber.gouv.fr/']] },
+plus: { cas: { titre: '', texte: '' },
+ resolu: { enonce: 'Un élève signale qu’en modifiant le numéro dans l’adresse de sa page de résultats, il voit les notes d’un camarade.', etapes: [
+ ['Reproduire', 'Connecté comme élève 1204 : GET /resultats/1205 → 200 OK, notes de l’élève 1205.\n→ Faille de contrôle d’accès (IDOR).'],
+ ['Lire le code', 'public function show($id) { return view("resultats", ["eleve" => Eleve::findOrFail($id)]); }\n→ Aucune vérification que l’élève connecté est celui demandé.'],
+ ['Corriger', 'Policy EleveResultatsPolicy : un élève voit ses résultats, un professeur ceux de ses classes, la vie scolaire tout l’établissement.\npublic function show(Eleve $eleve) { $this->authorize("voirResultats", $eleve); … }\n→ Réponse 403 pour un autre élève.'],
+ ['Tester et vérifier les autres routes', '→ Test automatisé ajouté ; revue de toutes les routes prenant un identifiant : deux autres corrigées (exports, devoirs rendus).'],
+ ['Traiter les conséquences', '→ Analyse des journaux d’accès : consultations anormales par deux comptes. Information du DPO, qui évalue la notification à la CNIL et l’information des familles concernées.']
+ ] },
+ erreurs: ['Contrôler l’accès seulement dans l’interface', 'Requêtes SQL construites par concaténation', 'Utiliser {!! !!} sur une saisie utilisateur', 'APP_DEBUG=true en production', 'Pas de tests d’autorisation', 'Codes HTTP incohérents dans l’API'],
+ memo: [['Commande / élément', 'Usage'], ['php artisan route:list', 'lister les routes'], ['php artisan make:model -mcr Devoir', 'modèle, migration, contrôleur'], ['php artisan migrate', 'appliquer les migrations'], ['php artisan make:policy', 'politique d’autorisation'], ['$this->authorize()', 'vérifier un droit'], ['with("relation")', 'éviter le N+1'], ['@csrf', 'jeton de formulaire'], ['php artisan test', 'lancer les tests'], ['php artisan config:cache route:cache', 'optimiser en production'], ['curl -H "Authorization: Bearer …" /api/v1/…', 'tester une API']],
+ examen: { titre: 'Sujet type · 20 points', q: ['Expliquer MVC sur un exemple. (3 pts)', 'Concevoir une API REST. (5 pts)', 'Écrire un contrôleur avec autorisation. (5 pts)', 'Identifier et corriger trois failles dans un code fourni. (5 pts)', 'Décrire un déploiement. (2 pts)'], r: ['voir cours', 'ressources et codes', 'authorize + policy', 'IDOR, XSS, injection', 'composer, migrate, cache'] },
+ prof: { deroule: [['Ouverture', 'Démonstration d’une faille IDOR sur une application de lab'], ['Cours', 'MVC et routage'], ['Pratique', 'Modèle et contrôleur'], ['Cours', 'API et sécurité'], ['Pratique', 'Policies et tests'], ['Clôture', 'Quiz flash']], diff: 'Élèves en difficulté : squelette fourni. Élèves avancés : OAuth 2, files d’attente, OpenAPI.', eval: 'Application testée, sujet type.' } },
+exemples: [
+ ['Lister les routes', 'Audit d’une application.', 'php artisan route:list --path=api', 'GET|HEAD api/v1/devoirs ...... devoirs.index › DevoirController@index\nPOST api/v1/devoirs ...... devoirs.store › DevoirController@store\nDELETE api/v1/devoirs/{devoir} devoirs.destroy', 'On vérifie que chaque route sensible a un middleware d’authentification.'],
+ ['Détecter un N+1', 'Page lente.', 'DB::enableQueryLog(); $c = Classe::all(); foreach ($c as $x) $x->eleves->count(); count(DB::getQueryLog())', '31', '31 requêtes pour 30 classes. Avec Classe::withCount("eleves")->get(), une seule.'],
+ ['Tester une API', 'Création d’un devoir.', 'curl -s -X POST https://syllabus.local/api/v1/devoirs -H "Authorization: Bearer $T" -H "Content-Type: application/json" -d \'{"titre":"DM 3"}\'', '{"message":"The date limite field is required.","errors":{"date_limite":["…"]}} (HTTP 422)', 'La validation renvoie 422 avec le détail des champs manquants.'],
+ ['Test d’autorisation', 'Non-régression.', 'php artisan test --filter=ResultatsTest', 'PASS Tests\\Feature\\ResultatsTest\n✓ un élève voit ses résultats\n✓ un élève ne voit pas ceux d’un camarade', 'Le test échouerait si la faille réapparaissait.'],
+ ['Vérifier les en-têtes', 'Audit de sécurité.', 'curl -sI https://syllabus.local | grep -iE "content-security|set-cookie"', 'content-security-policy: default-src \'self\'; frame-ancestors \'none\'\nset-cookie: syllabus_session=…; secure; httponly; samesite=lax', 'CSP restrictive et cookie de session protégé.'],
+ ['Déploiement', 'Mise en production.', 'composer install --no-dev -o && php artisan migrate --force && php artisan optimize && php artisan queue:restart', 'INFO Running migrations. 2026_10_01_create_rendus_table ....... DONE\nINFO Caching framework bootstrap, configuration, and metadata.', 'Chaque étape est dans le pipeline CI, avec retour arrière en cas d’échec.']
+],
+termes: ['MVC', 'modèle', 'vue', 'contrôleur', 'routeur', 'Laravel', 'Blade', 'Eloquent', 'ORM', 'migration', 'N+1', 'API REST', 'JSON', 'OpenAPI', 'session', 'jeton', 'OAuth 2', 'OpenID Connect', 'policy', 'OWASP', 'IDOR', 'XSS', 'CSRF', 'CSP', 'CORS', 'APP_DEBUG']
+});
+
+reg({
+cours: { id: 'js', match: /JavaScript|TypeScript|DOM|fetch|Accessibilité web|RGAA|WCAG|Performance web/i,
+ titre: 'JavaScript et TypeScript côté navigateur : DOM, asynchrone, fetch, accessibilité', duree: '',
+ niveau: 'NSI Première · BTS SIO SLAM · BUT Informatique · Titre pro DWWM',
+ prerequis: ['Le Web : HTML et CSS', 'Python : bases de la programmation'],
+ competences: ['NSI · Interactions dans le navigateur', 'BTS SIO SLAM · Développer une interface', 'DWWM · Développer la partie front-end'],
+ intro: 'Tout ce qui réagit dans une page web, du bouton « Lever la main » au terminal xterm.js des labs, est écrit en JavaScript. Le langage s’exécute dans le navigateur, manipule la page, dialogue avec le serveur sans la recharger et doit rester utilisable par tous, y compris au clavier et avec un lecteur d’écran. Ce module présente le langage moderne, le DOM, la programmation asynchrone avec fetch, TypeScript et les exigences d’accessibilité et de performance.',
+ cm: [
+ { t: 'Le langage moderne', d: '', html: 'On déclare avec const (par défaut) et let ; var est à éviter. Les types de base : nombres, chaînes, booléens, null, undefined, objets et tableaux. Les fonctions fléchées (x => x * 2), la déstructuration (const { nom, classe } = eleve), les gabarits de chaînes (`Bonjour ${nom}`) et les méthodes de tableaux (map, filter, reduce, find) forment le socle quotidien. On compare avec ===, qui ne convertit pas les types ("1" == 1 est vrai, "1" === 1 est faux). Les modules (import / export) organisent le code.' },
+ { t: 'Le DOM et les événements', d: '', html: 'Le DOM est la représentation de la page sous forme d’arbre d’objets. On sélectionne un élément (document.querySelector("#liste")), on modifie son contenu (textContent), ses classes (classList.add) ou ses attributs, on en crée (createElement). On réagit aux actions de l’utilisateur avec addEventListener("click", …). La délégation d’événements place un seul écouteur sur un parent pour gérer de nombreux enfants, y compris ceux ajoutés plus tard.', attention: 'innerHTML avec une donnée saisie par un utilisateur ouvre une faille XSS : le texte peut contenir un script. On utilise textContent pour du texte, ou on échappe explicitement.' },
+ { t: 'Asynchrone : promesses et async/await', d: '', html: 'Le navigateur n’exécute qu’un seul fil de JavaScript ; une opération longue (requête réseau, minuterie) ne doit pas le bloquer. Elle renvoie une promesse, résolue plus tard. La syntaxe async / await permet d’écrire ce code de façon lisible, et try / catch gère les erreurs. Promise.all lance plusieurs requêtes en parallèle. La boucle d’événements exécute les rappels quand le fil principal est libre.' },
+ { t: 'Dialoguer avec le serveur : fetch', d: '', html: 'fetch envoie une requête HTTP et renvoie une promesse de réponse. Il ne rejette la promesse qu’en cas d’erreur réseau : une réponse 404 ou 500 est une réponse « réussie », il faut tester response.ok. On envoie du JSON avec l’en-tête Content-Type et on joint le jeton CSRF ou d’authentification. Pour des mises à jour en temps réel (mains levées, présences du quiz), on utilise les WebSockets ou les Server-Sent Events plutôt qu’interroger le serveur toutes les secondes.', exemple: 'async function leverLaMain(labId) {\n const r = await fetch(`/api/v1/labs/${labId}/mains`, {\n method: "POST",\n headers: { "Content-Type": "application/json", "X-CSRF-TOKEN": jeton },\n body: JSON.stringify({ etape: 4 }),\n });\n if (!r.ok) throw new Error(`Erreur ${r.status}`);\n const { position } = await r.json();\n document.querySelector("#position").textContent = `Vous êtes ${position}e dans la file.`;\n}' },
+ { t: 'TypeScript', d: '', html: 'TypeScript ajoute un typage statique à JavaScript : on déclare la forme des données (interface Eleve { id: number; nom: string; classe?: string }) et le compilateur signale les erreurs avant l’exécution : propriété mal orthographiée, valeur possiblement undefined, mauvais type d’argument. Le code est compilé en JavaScript standard. Sur un projet de plusieurs milliers de lignes, il réduit fortement les régressions et rend l’éditeur beaucoup plus utile (complétion, renommage sûr).' },
+ { t: 'Accessibilité et performance', d: '', html: 'Un site public en France doit respecter le RGAA, fondé sur les normes WCAG. Les règles de base : utiliser les bons éléments HTML (un <button> plutôt qu’un <div> cliquable, qui ne se commande pas au clavier), des étiquettes de formulaire liées, des textes alternatifs, un contraste suffisant (4,5:1 pour le texte), un focus visible, et aria-live pour annoncer les mises à jour dynamiques. Côté performance : réduire le JavaScript chargé, différer ce qui n’est pas indispensable (defer, chargement à la demande), optimiser les images, mettre en cache. Les outils de développement du navigateur et Lighthouse mesurent les deux.' }
+ ],
+ synthese: ['const/let, fonctions fléchées, déstructuration, ===, modules', 'DOM : querySelector, textContent, addEventListener, délégation', 'Jamais innerHTML avec une saisie utilisateur', 'Promesses, async/await, try/catch, Promise.all', 'fetch : tester response.ok ; WebSockets pour le temps réel', 'TypeScript : interfaces et vérification avant exécution', 'RGAA/WCAG : éléments natifs, clavier, contraste, aria-live ; performance'],
+ qcm: [
+ ['Que vaut "1" === 1 ?', ['true', 'false', 'undefined', 'erreur'], 1, 'Pas de conversion de type.'],
+ ['Quelle propriété insérer pour afficher un texte saisi par l’utilisateur ?', ['innerHTML', 'textContent', 'outerHTML', 'eval'], 1, 'Pas d’interprétation HTML.'],
+ ['Quand fetch rejette-t-il sa promesse ?', ['Sur un 404', 'Sur un 500', 'En cas d’erreur réseau', 'Jamais'], 2, 'Tester response.ok.'],
+ ['À quoi sert await ?', ['Bloquer le navigateur', 'Attendre le résultat d’une promesse dans une fonction async', 'Créer une boucle', 'Déclarer une variable'], 1, 'Sans bloquer le fil principal.'],
+ ['Pourquoi préférer