Le fonctionnement est le suivant :
Le système permet d'afficher de multiples informations pendant que l'étudiant travaille :
Le système permet à l'étudiant de faire différentes actions, généralement on le laisse :
L'administrateur quand à lui peut modifier les droits et les options :
Ces droits et options sont très précis, il y en a une quarantaine. Ils permettent de modifier les actions qu'il est possible de faire ou bien le contenu de la page web.
Les droits permettent notamment :
Les premières questions du TP unix sont très faciles, elle servent à vérifier que l'étudiant est capable d'utiliser le système.
Voici quelques liens qui vous permettrons de l'utiliser sans l'installer :
Les exercices sont définis par les programmes Python stockés dans le répertoire Questions/unix dans le cas du questionnaire Unix. Chaque programme Python peut définir plusieurs exercices. Voici un exemple de programme Python.
# -*- coding: latin-1 -*- # Pour pouvoir mettre des accents from questions import * # Interface avec la base d'exercices from check import * # Les vérificateurs pour le shell add(name="copie de fichier", before = """Regardez dans votre cours, chapitre 2""", question="""Quelle commande permet de copier un ou des fichiers ?""", tests=( Good(Equal("cp")), Bad(Comment(Equal("copy"), "C'est la commande MS-DOS pas UNIX")), Bad(Comment(Equal("CP") | Equal("Cp"), "Sous UNIX la casse est importante"), ), ) add(name="copie de répertoire", required=["cp", "intro:final"], # Exercices à faire avant celui-ci question="""Quelle est l'option de cp pour faire une copie récursive ?""", tests=( Good( UpperCase(Equal("-R")) | Equal("--recursive") ), Good( Comment(Equal("-a"), "Elle fait plus que la copie !") ), ), indices = ("Il faut ajouter une option", "La première lettre de récursif est...", ), )
Le nom du fichier contenant les questions est important, ce sera :
Les chaînes de caractères sont en latin1 et aussi en HTML si c'est dans des commentaires. Donc attention aux caractères <, >, &.
De plus un système de remplacement est fait donc si vous voulez afficher un % il faut le doubler.
Tous les textes visibles par l'utilisateur peuvent contenir des marqueurs de la forme '%(paramètre)s' Ces marqueurs sont remplacés lors de l'affichage par la valeur du paramètre.
Il y en a plein d'autres, mais je ne pense pas qu'ils soient utiles pour poser les questions.
FAUT-IL SUPPRIMER CETTE FONCTIONNALITE DANGEREUSE ? : Oui, la nouvelle manière d'écrire les tests répond à ces problèmes mais ce n'est pas encore implémenté.
Vous pouvez utilisez des triples guillemets au lieu des simples pour pouvoir mettre des retours à la ligne ou des guillemets dans la question.
C'est lui qui donne un nom à la question. Ce nom est celui qui sera affiché pour que l'étudiant puisse choisir sa question.
Il contient une liste de noms des questions auxquels l'étudiant doit déjà avoir répondu avant que celle-ci s'affiche.
Si ce paramètre n'est pas indiqué, alors seule la question précédente est considérée comme requise. Il n'y a donc aucun prérequis pour la première question du fichier dans ce cas.
Si un nom de questions contient le caractère ':' alors on ne le touche pas, sinon on le préfixe par le nom du fichier courant.
Si le nom est suivie par une expression régulière entre parenthèse alors la réponse de l'étudiant à cette question doit vérifier l'expression régulière. personnel:sexe([mM]) permet de n'afficher la question que si la réponse m ou M a été donnée à la question sexe du fichier personnel.py
Ce paramètre contient un texte qui sera affiché avant la question elle-même. Cela pourra être un rappel de cours ou bien une action à faire par l'étudiant pour qu'il puisse répondre à la question.
Il peut simplement être le texte de la question.
Il peut aussi être une fonction sans paramètres retournant un chaîne de caractères. Avant l'appel de la fonction le système définit la graine de la série aléatoire si la question est aléatoire.
Pour mettre l'image toto.png dans la question : <IMG SRC='toto.png'> Cette image sera dans le répertoire HTML du répertoire qui contient la définition des questions.
Pour faire une question à choix multiple il suffit de mettre {{{a}}}, {{{b}}}... devant les textes représentant les différents choix possible. La réponse de l'étudiant sera la liste des textes cochés.
Cet entier indique le nombre de lignes de la zone dans laquelle l'étudiant va répondre. Par défaut 1.
C'est la réponse par défaut proposée quand l'utilisateur arrive sur la question pour la première fois.
C'est un texte qui sera affiché dans tous les cas si l'étudiant donne une mauvaise réponse. Au dessus de ce texte il sera écrit : ``peut être que ...´´
Il est conseillé d'utiliser le test comment qui n'affichera rien si un autre commentaire a déjà été affiché pour l'étudiant.
C'est un texte qui sera affiché dans tous les cas si l'étudiant donne une bonne réponse. Au dessus de ce texte il sera écrit : ``saviez vous que ...´´
Si il est mis à True alors le lien vers la question est mis en évidence pour que l'étudiant y réponde prioritairement (mais il n'est pas forcé).
Une liste de chaines de caractères contenant des indices pour aider l'étudiant s'il le demande. Les indices sont proposés dans l'ordre, un par un.
C'est le nombre maximum de réponses que peut donner l'étudiant. Il ne pourra ensuite plus répondre à la question.
ATTENTION : cette documentation est obsolète, les tests ne sont plus à définir de cette façon.
C'est une liste de tests. Les tests sont effectués dans l'ordre jusqu'à ce qu'un test indique que la réponse est mauvaise ou bonne (True/False). Si le test retourne None alors il peut ajouter un commentaire qui sera affiché à l'étudiant. Des commentaires successifs peuvent s'afficher.
Les fonctions de tests suivantes sont définies par défaut.
Si la réponse est exactement identique alors on considère que c'est une bonne réponse et l'on retourne le commentaire associé à la bonne réponse.
good( "a" ), good( "A", "Je préfère <tt>a</tt> comme réponse" ), good( ("c", "d") ), good( ("C", "D"), "Ok, mais je préfère les minuscules" ),
Si la réponse est exactement identique alors on considère que c'est une mauvaise réponse et l'on retourne le commentaire associé à la mauvaise réponse.
La syntaxe est la même que good
Si la réponse ne contient pas la chaine on considère que c'est une mauvaise réponse et l'on retourne le commentaire associé à la bonne réponse.
require( "a" ), require( "A", "Et alors, ou il est le <tt>A</tt>" ), require( ("c", "d") ), require( ("C", "D"), "Et C et D ? Ou sont-ils ?" ),
Si la réponse ne commence ou fini pas par la chaine on considère que c'est une mauvaise réponse et l'on retourne le commentaire associé à la bonne réponse.
require_startswith("/", "Un nom absolu commence par /"), require_endswith(".html", "Il faut indiquer que c'est du HTML"),
Si la réponse contient la chaine on considère que c'est une mauvaise réponse et l'on retourne le commentaire associé à la mauvaise réponse.
La syntaxe est la même que require
Si la réponse commence ou fini par la chaine on considère que c'est une mauvaise réponse et l'on retourne le commentaire associé à la bonne réponse.
reject_startswith("/", "Un nom relatif ne commence pas par /"), reject_endswith("/", "Le / final est inutile"),
Ce test sans paramètre refuse la réponse si ce n'est pas un entier.
Ce test a pour paramètre la longueur de la réponse attendue et un commentaire à retourner si ce n'est pas la bonne.
Ce test a pour paramètres une chaine de caractère et le nombre requis d'occurrence de cette chaine de caractère dans la réponse de l'étudiant. Le dernier paramètre est le commentaire.
Cette fonction a pour paramètre un commentaire. Dans tous les cas ce commentaire est ajouté à ce que l'étudiant va voir comme indication sur sa réponse.
Son utilisation la plus naturelle est de le mettre en dernier dans la liste des tests afin de donner un conseil général à l'étudiant quand on a pas pu lui faire un commentaire lui expliquant pourquoi sa réponse est mauvaise.
Ces tests sont utilisés pour les TP utilisant le shell et ne sont pas utiles pour les autres.
Le fonctionnement et la syntaxe sont la même que ceux sans shell_. Les différences sont :
dumb_replace = ( ("${HOME}", "$HOME"), (("~/.", "$HOME/"), "~/") )
replacement=( ("-d", "--directory", 0), ("-w", "--width", 1) )L'exemple précédent fait les subtitutions :
Ce test sans paramètre affiche simplement l'arbre syntaxique de la commande shell. Il doit être indiqué en dernier sinon il risque d'être affiché deux fois car les autres tests l'affichent quand ils interrompent la vérification .
C'est une liste de tests. Les tests sont effectués dans l'ordre jusqu'à ce qu'un test indique que la réponse est mauvaise ou bonne (True/False).
Un test est une expression algébrique définissant ce qu'il faut répondre à l'étudiant.
ATTENTION : ces explications sont pour la version 2 de Quenlig. Dans la version 3 l'écriture de test est simplifiée.
Les tests sont simple à réaliser.
Une feuille de test (elle n'utilise pas state), par exemple :
class Equal(TestString): def __call__(self, student_answer, state=None, parser=no_parse): return student_answer == parser(self.string, state, self), ""
Un modificateur pouvant utiliser state pour modifier en fonction de l'étudiant. C'est un peu compliqué car il peut y avoir des modificateurs de modificateur. D'autre part, la modification peut être faite ou non en fonction du test réalisé, par exemple le modificateur s'applique à Equal mais pas à Contain.
class UpperCase(TestUnary): def __call__(self, student_answer, state=None, parser=no_parse): return self.children[0]( student_answer.upper(), state, lambda string, state, test: parser(string.upper(), state, test))
Quand add est appelé, il stocke la valeur courante de cette variable dans la question elle même, cela évite de redonner ce paramètre à chaque add.
Cette fonction transforme systématiquement la réponse de l'étudiant.
def filter_student_answer(answer, state=None): answer = re.sub(' +', ' ', answer) answer = re.sub(' \n', '\n', answer) answer = re.sub('\n\n*', '\n', answer) return answer
Le système n'a été testé que sous Linux. Quelque points de détails l'empêcheront de fonctionner sous Windows.
Le fichier configuration.py contient quelques paramètres de configuration, notemment l'adresse du serveur CAS pour l'authentification.
Le répertoire HTML contient le fichier squelette de la page HTML ainsi que le fichier CSS qui contient tous les textes de l'interface. Il y a un fichier CSS par langue.
Les Packages obligatoires :
Pas besoin de compiler c'est du Python.
Pour voir toutes les options de lancement tapez : main.py
Les options de lancements sont concaténables.
Création d'une session |
main.py NomSession create RépertoireQuestions NumeroPort Ceci crée les répertoires mais ne lance pas le serveur. |
Définition de la date de début de TP |
main.py NomSession begin_date DateDébut Les dates sont sous la forme : "8:30 15/3/2006" |
Définition de la date de fin de TP |
main.py NomSession end_date DateDébut |
Désignation de l'administrateur | main.py NomSession admin NomDuCompte |
Lancement du serveur |
main.py NomSession start Le serveur vous affiche l'URL qu'il faut utiliser pour l'atteindre. |
Détection de problèmes |
main.py NomSession problems Indique à l'auteur du questionnaire les bonnes réponses données par les étudiants durant la session qui ne sont plus acceptées par le nouveau système. |
Ceci est en développement et instable...
Chaque fonctionnalité du système a son ACL. Si une ACL est préfixée par ! alors elle est enlevée même si elle est autorisée pour tout le monde (question_shuffle pour les profs par exemple). Ou interdir à un étudiant de répondre aux questions, ...
Les ACLS sont définies dans Students/???/Logs/Default/acls pour les étudiants et Students/???/Logs/Teacher/acls pour les enseignants.
Les roles sont définis dans Students/???/Logs/???/roles
Le premier administrateur doit être créé avant le lancement du système.
Si le serveur est trop lent ou les étudiants trop nombreux, enlevez l'ACL par défaut 'question_pixel_map_see' qui consomme beaucoup de ressources.
Taper make pour lister les buts possibles. Voici les principaux :
make regtest effectue des tests de régression. Il faut le lancer chaque fois que vous modifiez le système. pour s'assurer qu'il fonctionne toujours correctement.
make load_simulator reprend rejoue en temps réel des sessions d'étudiants qui ont réellement travaillé. Il permet de simuler autant d'étudiant que l'on veut. Il stocke le temps moyens de réponse du serveur au cours du temps.
make simulator_plot fait un affichage graphique des statistiques générées par make load_simulator
make profiling lance le simulateur avec le profiling pour voir ou le temps CPU passe.
make plots génère l'affichage graphique du graphe des questions pour les différents questionnaires. Ainsi que de nombreux autres fichiers dans le répertoire HTML de chacune des sessions.
Une fois le TP terminé, l'auteur du questionnaire doit l'améliorer pour que les étudiants reçoive un aide quand ils donne une mauvaise réponse. Ou bien pour tenir compte des commentaire des étudiants.
Avec vos droit enseignant, vous parcourez chaque question en cliquant sur 'question suivante'. Pour chaque question vous avez l'ensemble des mauvaises réponses données par le étudiants ainsi que les commentaires. Le fond rouge pour les mauvaises réponses indique que l'étudiant n'a eu aucun commentaire concernant sa mauvaise réponse. Après avoir mis la définition de la question à jour dans le fichier Python vous pouvez faire 'Recharge ce module' pour voir combien il reste de mauvaises réponses sur fond rouge. Pas besoin de relancer le serveur.
Le système fourni énormément d'informations via les pages Web. Si néanmoins elles ne sont pas suffisantes, on peut les extraire des fichiers.
Toutes les informations sont inscrites dans Students/nom_session/Logs. Il y a un répertoire par étudiant contenant :
Les champs de l'enregistrement sont séparés par control A (^A). La suite de la ligne peut être :