diff --git a/amc-templates/amc_template.zip b/amc-templates/amc_template.zip new file mode 100644 index 0000000..f9b0252 Binary files /dev/null and b/amc-templates/amc_template.zip differ diff --git a/amc-templates/amc_template/exam.pdf b/amc-templates/amc_template/exam.pdf index 8dc1d46..75aa530 100644 Binary files a/amc-templates/amc_template/exam.pdf and b/amc-templates/amc_template/exam.pdf differ diff --git a/amc-templates/amc_template/first_page.tex b/amc-templates/amc_template/first_page.tex index 0bb6588..3ac25ed 100644 --- a/amc-templates/amc_template/first_page.tex +++ b/amc-templates/amc_template/first_page.tex @@ -1,57 +1,57 @@ % First page - FRENCH \noindent \begin{minipage}[c]{350pt} \bf Prof./Ens. XXX~-~Examen de XXX~-~Section XX \\ ~ \\ \bf Date~-~durée\,: XhYYm \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{ID}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{NOM DE L'ETUDIANT}} \end{center} \end{minipage} \vfill \noindent \namefield{SCIPER\,: {\Large \bf SCIPER}} \hfill Signature\,:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Attendez le d\'ebut de l'\'epreuve avant de tourner la page.} \textbf{Ce document est imprim\'e recto-verso, il contient XX pages, les derni\`eres pouvant \^etre vides.} \textbf{Ne~pas d\'egrafer.} \medskip \begin{itemize} \item[--] Posez votre carte d'\'etudiant sur la table. \item[--] \textbf{Aucun} document n'est autoris\'{e}. \item[--] L'utilisation d'une \textbf{calculatrice} et de tout outil \'electronique est interdite pendant l'\'epreuve. \item[--] Pour les questions \`a \textbf{choix multiple}, on comptera\,: \begin{itemize} \item [$+3$] points si la r\'eponse est correcte, \item [$0$] point si la question n'est pas r\'epondue ou s'il y a plusieurs réponses inscrites, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item[--]Pour les questions de type \textbf{vrai-faux}, on comptera\,: \begin{itemize} \item [$+1$] point si la r\'eponse est correcte, \item [$0$] point si la question n'est pas r\'epondue ou s'il y a plusieurs réponses inscrites, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item[--] Utilisez un \textbf{stylo} \`a encre \textbf{noire ou bleu fonc\'e} et effacez proprement avec du \textbf{correcteur blanc} si n\'ecessaire. \item[--] Si une question est erronée, l'enseignant se réserve le droit de l'annuler. \end{itemize} \hfill \hspace{-28px}\includegraphics[scale=0.19]{good_bad_square} \hfill \newpage %% End of first page diff --git a/amc-templates/amc_template_kprime/first_page.tex b/amc-templates/amc_template_kprime/first_page.tex index 0bb6588..3ac25ed 100644 --- a/amc-templates/amc_template_kprime/first_page.tex +++ b/amc-templates/amc_template_kprime/first_page.tex @@ -1,57 +1,57 @@ % First page - FRENCH \noindent \begin{minipage}[c]{350pt} \bf Prof./Ens. XXX~-~Examen de XXX~-~Section XX \\ ~ \\ \bf Date~-~durée\,: XhYYm \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{ID}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{NOM DE L'ETUDIANT}} \end{center} \end{minipage} \vfill \noindent \namefield{SCIPER\,: {\Large \bf SCIPER}} \hfill Signature\,:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Attendez le d\'ebut de l'\'epreuve avant de tourner la page.} \textbf{Ce document est imprim\'e recto-verso, il contient XX pages, les derni\`eres pouvant \^etre vides.} \textbf{Ne~pas d\'egrafer.} \medskip \begin{itemize} \item[--] Posez votre carte d'\'etudiant sur la table. \item[--] \textbf{Aucun} document n'est autoris\'{e}. \item[--] L'utilisation d'une \textbf{calculatrice} et de tout outil \'electronique est interdite pendant l'\'epreuve. \item[--] Pour les questions \`a \textbf{choix multiple}, on comptera\,: \begin{itemize} \item [$+3$] points si la r\'eponse est correcte, \item [$0$] point si la question n'est pas r\'epondue ou s'il y a plusieurs réponses inscrites, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item[--]Pour les questions de type \textbf{vrai-faux}, on comptera\,: \begin{itemize} \item [$+1$] point si la r\'eponse est correcte, \item [$0$] point si la question n'est pas r\'epondue ou s'il y a plusieurs réponses inscrites, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item[--] Utilisez un \textbf{stylo} \`a encre \textbf{noire ou bleu fonc\'e} et effacez proprement avec du \textbf{correcteur blanc} si n\'ecessaire. \item[--] Si une question est erronée, l'enseignant se réserve le droit de l'annuler. \end{itemize} \hfill \hspace{-28px}\includegraphics[scale=0.19]{good_bad_square} \hfill \newpage %% End of first page diff --git a/data/templates/chemistry/de/first_page.tex b/data/templates/chemistry/de/first_page.tex index 0c8a7d4..b53e718 100644 --- a/data/templates/chemistry/de/first_page.tex +++ b/data/templates/chemistry/de/first_page.tex @@ -1,55 +1,56 @@ % First page - GERMAN \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~Dauer: \Time \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{\NAME{}}} \end{center} \end{minipage} \vfill \noindent -\namefield{SCIPER: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Unterschrift:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} +\namefield{SCIPER\,: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Signature\,:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Drehen Sie diese Seite nicht um, bevor Sie dazu aufgefordert werden.} \textbf{Jedes Blatt hat eine Vorder- und eine R\"uckseite. Es gibt \totalPages\ Seiten, die letzten sind m\"oglicherweise leer.} \textbf{L\"osen Sie nicht die Heftklammern.} +\medskip \begin{itemize} \item[--] Legen Sie Ihren Studentenausweis auf den Tisch. \item[--] Es sind \textbf{keine} weiteren Unterlagen zugelassen. \item[--] Die Nutzung eines \textbf{Taschenrechners} oder jedes anderen elektronischen Hilfsmittels ist w\"ahrend der Pr\"ufung nicht gestattet. \item[--] F\"ur die \textbf{Multiple Choice} Fragen erh\"alt man: \begin{itemize} \item [$+3$] Punkte, wenn die Antwort richtig ist, \item [$0$] Punkte, wenn die Frage nicht beantwortet ist oder mehrere M\"oglichkeiten markiert sind, \item [$-1$] Punkt, wenn die Antwort falsch ist. \end{itemize} \item[--] F\"ur die \textbf{Wahr/Falsch }Fragen erh\"alt man: \begin{itemize} \item [$+1$] Punkt, wenn die Antwort richtig ist, \item [$0$] Punkte, wenn die Frage nicht beantwortet ist oder mehrere M\"oglichkeiten markiert sind, \item [$-1$] Punkt, wenn die Antwort falsch ist. \end{itemize} \item[--] Benutzen Sie einen \textbf{Kugelschreiber mit schwarzer oder blauer Tinte} und verwenden Sie Korrekturfl\"ussigkeit (z.B. Tipp-Ex) um bei Bedarf Ihre Antwort zu \"andern. \item[--] Falls eine Fragestellung einen Fehler enth{\"a}lt, darf der/die Unterrichtende die entsprechende Frage annulieren. \end{itemize} \hfill \hspace{-13px}\includegraphics[scale=0.19]{good_bad_square} \hfill % End of first page diff --git a/data/templates/chemistry/en/first_page.tex b/data/templates/chemistry/en/first_page.tex index 4a53aeb..0ba3531 100644 --- a/data/templates/chemistry/en/first_page.tex +++ b/data/templates/chemistry/en/first_page.tex @@ -1,56 +1,56 @@ % First page - ENGLISH \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~duration: \Time \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{\NAME{}}} \end{center} \end{minipage} \vfill \noindent \namefield{SCIPER: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Signature:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Do not turn the page before the start of the exam.} \textbf{This document is double-sided, has \totalPages\ pages, the last ones possibly blank.} \textbf{Do not unstaple.} \medskip \begin{itemize} \item[--] Place your student card on your table. \item[--] \textbf{No other paper materials} are allowed to be used during the exam. \item[--] Using a \textbf{calculator} or any electronic device is not permitted during the exam. \item[--] For the \textbf{multiple choice} questions, we give \begin{itemize} \item [$+3$] points if your answer is correct, \item [$0$] points if you give no answer or more than one, \item [$-1$] points if your answer is incorrect. \end{itemize} \item[--] For the \textbf{true/false} questions, we give \begin{itemize} \item [$+1$] points if your answer is correct, \item [$0$] points if you give no answer or more than one, \item [$-1$] points if your answer is incorrect. \end{itemize} \item[--] Use a \textbf{black or dark blue ballpen} and clearly erase with \textbf{correction fluid} if necessary. \item[--] If a question is wrong, the teacher may decide to nullify it. \end{itemize} \hfill \hspace{-13px}\includegraphics[scale=0.19]{good_bad_square} \hfill % End of first page diff --git a/data/templates/chemistry/fr/first_page.tex b/data/templates/chemistry/fr/first_page.tex index 03ffa83..c3bb2eb 100644 --- a/data/templates/chemistry/fr/first_page.tex +++ b/data/templates/chemistry/fr/first_page.tex @@ -1,56 +1,56 @@ % First page - FRENCH \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~durée\,: \Time \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{\NAME{}}} \end{center} \end{minipage} \vfill \noindent \namefield{SCIPER\,: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Signature\,:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Attendez le d\'ebut de l'\'epreuve avant de tourner la page.} \textbf{Ce document est imprim\'e recto-verso, il contient \totalPages\ pages, les derni\`eres pouvant \^etre vides.} \textbf{Ne~pas d\'egrafer.} \medskip \begin{itemize} \item[--] Posez votre carte d'\'etudiant sur la table. \item[--] \textbf{Aucun} document n'est autoris\'{e}. \item[--] L'utilisation d'une \textbf{calculatrice} et de tout outil \'electronique est interdite pendant l'\'epreuve. \item[--] Pour les questions \`a \textbf{choix multiple}, on comptera\,: \begin{itemize} \item [$+3$] points si la r\'eponse est correcte, - \item [$0$] point si la question n'est pas r\'epondue ou s'il y a plusieurs réponses inscrites, + \item [$0$] point si il n'y a aucune ou plus d'une r\'eponse inscrite, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item[--]Pour les questions de type \textbf{vrai-faux}, on comptera\,: \begin{itemize} \item [$+1$] point si la r\'eponse est correcte, - \item [$0$] point si la question n'est pas r\'epondue ou s'il y a plusieurs réponses inscrites, + \item [$0$] point si il n'y a aucune ou plus d'une r\'eponse inscrite, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item[--] Utilisez un \textbf{stylo} \`a encre \textbf{noire ou bleu fonc\'e} et effacez proprement avec du \textbf{correcteur blanc} si n\'ecessaire. \item[--] Si une question est erronée, l'enseignant se réserve le droit de l'annuler. \end{itemize} \hfill \hspace{-13px}\includegraphics[scale=0.19]{good_bad_square} \hfill %% End of first page diff --git a/data/templates/linear-algebra/de/first_page.tex b/data/templates/linear-algebra/de/first_page.tex index 0c8a7d4..b53e718 100644 --- a/data/templates/linear-algebra/de/first_page.tex +++ b/data/templates/linear-algebra/de/first_page.tex @@ -1,55 +1,56 @@ % First page - GERMAN \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~Dauer: \Time \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{\NAME{}}} \end{center} \end{minipage} \vfill \noindent -\namefield{SCIPER: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Unterschrift:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} +\namefield{SCIPER\,: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Signature\,:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Drehen Sie diese Seite nicht um, bevor Sie dazu aufgefordert werden.} \textbf{Jedes Blatt hat eine Vorder- und eine R\"uckseite. Es gibt \totalPages\ Seiten, die letzten sind m\"oglicherweise leer.} \textbf{L\"osen Sie nicht die Heftklammern.} +\medskip \begin{itemize} \item[--] Legen Sie Ihren Studentenausweis auf den Tisch. \item[--] Es sind \textbf{keine} weiteren Unterlagen zugelassen. \item[--] Die Nutzung eines \textbf{Taschenrechners} oder jedes anderen elektronischen Hilfsmittels ist w\"ahrend der Pr\"ufung nicht gestattet. \item[--] F\"ur die \textbf{Multiple Choice} Fragen erh\"alt man: \begin{itemize} \item [$+3$] Punkte, wenn die Antwort richtig ist, \item [$0$] Punkte, wenn die Frage nicht beantwortet ist oder mehrere M\"oglichkeiten markiert sind, \item [$-1$] Punkt, wenn die Antwort falsch ist. \end{itemize} \item[--] F\"ur die \textbf{Wahr/Falsch }Fragen erh\"alt man: \begin{itemize} \item [$+1$] Punkt, wenn die Antwort richtig ist, \item [$0$] Punkte, wenn die Frage nicht beantwortet ist oder mehrere M\"oglichkeiten markiert sind, \item [$-1$] Punkt, wenn die Antwort falsch ist. \end{itemize} \item[--] Benutzen Sie einen \textbf{Kugelschreiber mit schwarzer oder blauer Tinte} und verwenden Sie Korrekturfl\"ussigkeit (z.B. Tipp-Ex) um bei Bedarf Ihre Antwort zu \"andern. \item[--] Falls eine Fragestellung einen Fehler enth{\"a}lt, darf der/die Unterrichtende die entsprechende Frage annulieren. \end{itemize} \hfill \hspace{-13px}\includegraphics[scale=0.19]{good_bad_square} \hfill % End of first page diff --git a/data/templates/linear-algebra/en/first_page.tex b/data/templates/linear-algebra/en/first_page.tex index 4a53aeb..0ba3531 100644 --- a/data/templates/linear-algebra/en/first_page.tex +++ b/data/templates/linear-algebra/en/first_page.tex @@ -1,56 +1,56 @@ % First page - ENGLISH \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~duration: \Time \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{\NAME{}}} \end{center} \end{minipage} \vfill \noindent \namefield{SCIPER: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Signature:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Do not turn the page before the start of the exam.} \textbf{This document is double-sided, has \totalPages\ pages, the last ones possibly blank.} \textbf{Do not unstaple.} \medskip \begin{itemize} \item[--] Place your student card on your table. \item[--] \textbf{No other paper materials} are allowed to be used during the exam. \item[--] Using a \textbf{calculator} or any electronic device is not permitted during the exam. \item[--] For the \textbf{multiple choice} questions, we give \begin{itemize} \item [$+3$] points if your answer is correct, \item [$0$] points if you give no answer or more than one, \item [$-1$] points if your answer is incorrect. \end{itemize} \item[--] For the \textbf{true/false} questions, we give \begin{itemize} \item [$+1$] points if your answer is correct, \item [$0$] points if you give no answer or more than one, \item [$-1$] points if your answer is incorrect. \end{itemize} \item[--] Use a \textbf{black or dark blue ballpen} and clearly erase with \textbf{correction fluid} if necessary. \item[--] If a question is wrong, the teacher may decide to nullify it. \end{itemize} \hfill \hspace{-13px}\includegraphics[scale=0.19]{good_bad_square} \hfill % End of first page diff --git a/data/templates/linear-algebra/fr/first_page.tex b/data/templates/linear-algebra/fr/first_page.tex index d78e380..c3bb2eb 100644 --- a/data/templates/linear-algebra/fr/first_page.tex +++ b/data/templates/linear-algebra/fr/first_page.tex @@ -1,56 +1,56 @@ % First page - FRENCH \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~durée\,: \Time \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{\NAME{}}} \end{center} \end{minipage} \vfill \noindent \namefield{SCIPER\,: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Signature\,:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Attendez le d\'ebut de l'\'epreuve avant de tourner la page.} \textbf{Ce document est imprim\'e recto-verso, il contient \totalPages\ pages, les derni\`eres pouvant \^etre vides.} \textbf{Ne~pas d\'egrafer.} \medskip \begin{itemize} \item[--] Posez votre carte d'\'etudiant sur la table. \item[--] \textbf{Aucun} document n'est autoris\'{e}. \item[--] L'utilisation d'une \textbf{calculatrice} et de tout outil \'electronique est interdite pendant l'\'epreuve. \item[--] Pour les questions \`a \textbf{choix multiple}, on comptera\,: \begin{itemize} \item [$+3$] points si la r\'eponse est correcte, \item [$0$] point si il n'y a aucune ou plus d'une r\'eponse inscrite, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item[--]Pour les questions de type \textbf{vrai-faux}, on comptera\,: \begin{itemize} \item [$+1$] point si la r\'eponse est correcte, \item [$0$] point si il n'y a aucune ou plus d'une r\'eponse inscrite, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item[--] Utilisez un \textbf{stylo} \`a encre \textbf{noire ou bleu fonc\'e} et effacez proprement avec du \textbf{correcteur blanc} si n\'ecessaire. \item[--] Si une question est erronée, l'enseignant se réserve le droit de l'annuler. \end{itemize} \hfill \hspace{-13px}\includegraphics[scale=0.19]{good_bad_square} \hfill %% End of first page diff --git a/data/templates/maths/de/first_page.tex b/data/templates/maths/de/first_page.tex index 8df0af6..b53e718 100644 --- a/data/templates/maths/de/first_page.tex +++ b/data/templates/maths/de/first_page.tex @@ -1,56 +1,56 @@ % First page - GERMAN \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~Dauer: \Time \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{\NAME{}}} \end{center} \end{minipage} \vfill \noindent \namefield{SCIPER\,: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Signature\,:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Drehen Sie diese Seite nicht um, bevor Sie dazu aufgefordert werden.} \textbf{Jedes Blatt hat eine Vorder- und eine R\"uckseite. Es gibt \totalPages\ Seiten, die letzten sind m\"oglicherweise leer.} \textbf{L\"osen Sie nicht die Heftklammern.} \medskip \begin{itemize} \item[--] Legen Sie Ihren Studentenausweis auf den Tisch. \item[--] Es sind \textbf{keine} weiteren Unterlagen zugelassen. \item[--] Die Nutzung eines \textbf{Taschenrechners} oder jedes anderen elektronischen Hilfsmittels ist w\"ahrend der Pr\"ufung nicht gestattet. \item[--] F\"ur die \textbf{Multiple Choice} Fragen erh\"alt man: \begin{itemize} \item [$+3$] Punkte, wenn die Antwort richtig ist, \item [$0$] Punkte, wenn die Frage nicht beantwortet ist oder mehrere M\"oglichkeiten markiert sind, \item [$-1$] Punkt, wenn die Antwort falsch ist. \end{itemize} \item[--] F\"ur die \textbf{Wahr/Falsch }Fragen erh\"alt man: \begin{itemize} \item [$+1$] Punkt, wenn die Antwort richtig ist, \item [$0$] Punkte, wenn die Frage nicht beantwortet ist oder mehrere M\"oglichkeiten markiert sind, \item [$-1$] Punkt, wenn die Antwort falsch ist. \end{itemize} \item[--] Benutzen Sie einen \textbf{Kugelschreiber mit schwarzer oder blauer Tinte} und verwenden Sie Korrekturfl\"ussigkeit (z.B. Tipp-Ex) um bei Bedarf Ihre Antwort zu \"andern. \item[--] Falls eine Fragestellung einen Fehler enth{\"a}lt, darf der/die Unterrichtende die entsprechende Frage annulieren. \end{itemize} \hfill \hspace{-13px}\includegraphics[scale=0.19]{good_bad_square} \hfill % End of first page diff --git a/data/templates/maths/en/first_page.tex b/data/templates/maths/en/first_page.tex index 4a53aeb..0ba3531 100644 --- a/data/templates/maths/en/first_page.tex +++ b/data/templates/maths/en/first_page.tex @@ -1,56 +1,56 @@ % First page - ENGLISH \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~duration: \Time \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{\NAME{}}} \end{center} \end{minipage} \vfill \noindent \namefield{SCIPER: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Signature:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Do not turn the page before the start of the exam.} \textbf{This document is double-sided, has \totalPages\ pages, the last ones possibly blank.} \textbf{Do not unstaple.} \medskip \begin{itemize} \item[--] Place your student card on your table. \item[--] \textbf{No other paper materials} are allowed to be used during the exam. \item[--] Using a \textbf{calculator} or any electronic device is not permitted during the exam. \item[--] For the \textbf{multiple choice} questions, we give \begin{itemize} \item [$+3$] points if your answer is correct, \item [$0$] points if you give no answer or more than one, \item [$-1$] points if your answer is incorrect. \end{itemize} \item[--] For the \textbf{true/false} questions, we give \begin{itemize} \item [$+1$] points if your answer is correct, \item [$0$] points if you give no answer or more than one, \item [$-1$] points if your answer is incorrect. \end{itemize} \item[--] Use a \textbf{black or dark blue ballpen} and clearly erase with \textbf{correction fluid} if necessary. \item[--] If a question is wrong, the teacher may decide to nullify it. \end{itemize} \hfill \hspace{-13px}\includegraphics[scale=0.19]{good_bad_square} \hfill % End of first page diff --git a/data/templates/maths/fr/first_page.tex b/data/templates/maths/fr/first_page.tex index d78e380..c3bb2eb 100644 --- a/data/templates/maths/fr/first_page.tex +++ b/data/templates/maths/fr/first_page.tex @@ -1,56 +1,56 @@ % First page - FRENCH \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~durée\,: \Time \end{minipage} \begin{minipage}[c]{100pt} - \includegraphics[scale=0.24]{Logo_EPFL} + \includegraphics[scale=0.20]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \begin{center} \fontsize{40}{48}{\selectfont{\NAME{}}} \end{center} \end{minipage} \vfill \noindent \namefield{SCIPER\,: {\Large \bf \SCIPER{} }}%SIGNATURE \hfill Signature\,:~\textcolor{light-Gray}{\rule{5cm}{1.5cm}} \\ ~ \\ \noindent \textbf{Attendez le d\'ebut de l'\'epreuve avant de tourner la page.} \textbf{Ce document est imprim\'e recto-verso, il contient \totalPages\ pages, les derni\`eres pouvant \^etre vides.} \textbf{Ne~pas d\'egrafer.} \medskip \begin{itemize} \item[--] Posez votre carte d'\'etudiant sur la table. \item[--] \textbf{Aucun} document n'est autoris\'{e}. \item[--] L'utilisation d'une \textbf{calculatrice} et de tout outil \'electronique est interdite pendant l'\'epreuve. \item[--] Pour les questions \`a \textbf{choix multiple}, on comptera\,: \begin{itemize} \item [$+3$] points si la r\'eponse est correcte, \item [$0$] point si il n'y a aucune ou plus d'une r\'eponse inscrite, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item[--]Pour les questions de type \textbf{vrai-faux}, on comptera\,: \begin{itemize} \item [$+1$] point si la r\'eponse est correcte, \item [$0$] point si il n'y a aucune ou plus d'une r\'eponse inscrite, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item[--] Utilisez un \textbf{stylo} \`a encre \textbf{noire ou bleu fonc\'e} et effacez proprement avec du \textbf{correcteur blanc} si n\'ecessaire. \item[--] Si une question est erronée, l'enseignant se réserve le droit de l'annuler. \end{itemize} \hfill \hspace{-13px}\includegraphics[scale=0.19]{good_bad_square} \hfill %% End of first page diff --git a/local/stats/lib/lib_amcstats.php b/local/stats/lib/lib_amcstats.php index 8d4c85b..3629f10 100755 --- a/local/stats/lib/lib_amcstats.php +++ b/local/stats/lib/lib_amcstats.php @@ -1,849 +1,854 @@ filename = $filename; $this->teacher = $teacher; $this->exam_points = $exam_points; $raw_data = file($this->filename, FILE_IGNORE_NEW_LINES); $this->raw_data = array(); foreach($raw_data as $line) { $line = array_map("clean_array", explode(';', $line)); $line = array_map("decimal_conversion", $line); $this->raw_data[] = $line; } $this->parseHeader(); $this->parseStudents($only_questions, $inverse_filter, $external); } public function getStudents() { return $this->students; } protected function parseHeader() { if (isset($this->raw_data[0])) //is_array($this->raw_data[0]) || is_object($this->raw_data[0])) { foreach($this->raw_data[0] as $col_id => $value) { // Analyse header from CSV file, based on content $item = array(); switch ($value) { case "ID": case "NAME": case "EMAIL": case "SECTION": case "Mark": $item['name'] = $value; $item['type'] = "info"; break; case "SCIPER": $item['name'] = $value; $item['type'] = "unique_id"; break; default: $item['name'] = $value; if (preg_match('/^TICKED:/', $value)) { $item['name'] = preg_replace('/^TICKED:/', '', $value); $item['type'] = "ticked"; } else { $item['type'] = "question"; $item['subtype'] = $this->guessSubtype($col_id); } } // Stats will be computed at a later stage $item['stats'] = null; $this->columns[] = $item; } } } protected function guessSubtype($col_id) { $subtype = null; $min_points = 0; $max_points = 0; $decimal = false; foreach($this->raw_data as $line) { if (preg_match('/\./', $line[$col_id])) $decimal = true; if ($line[$col_id] > $max_points) $max_points = $line[$col_id]; } + + //Tmp Global Issues + //if ($max_points == 1)return 'mc'; else return 'tf'; + + // This only works for MATHS exams... if ($decimal or $max_points > 3) { // Only open questions have decimal points return 'open'; } if ($max_points == 3) return 'mc'; if ($max_points == 1) return 'tf'; return 'unknown'; } protected function getColIdByName($name) { foreach ($this->columns as $id => $col) if ($col['name'] == $name) return $id; throw new Exception('Column not found: '.$name); } protected function getColIdsByType($type, $name = null) { $ids = array(); if (is_null($name)) { foreach ($this->columns as $id => $col) if ($col['type'] == $type) $ids[] = $id; } else { foreach ($this->columns as $id => $col) if ($col['type'] == $type and $col['name'] == $name) $ids[] = $id; } if (count($ids) == 0) { if (is_null($name)) throw new Exception('Column type not found: '.$type); throw new Exception('Column type not found: '.$type.'/'.$name); } if (count($ids) == 1) return $ids[0]; return $ids; } protected function getQuestionNameByColId($id) { if (array_key_exists($id, $this->columns) and $this->columns[$id]['type'] == 'question') return $this->columns[$id]['name']; throw new Exception('Column not found, or is not a question: '.$id); } protected function getMaximumPointsByColId($id) { $maximum = 0.0; foreach($this->raw_data as $student) if ((float)$student[$id] > $maximum) $maximum = (float)$student[$id]; return $maximum; } protected function parseStudents($only_questions, $inverse_filter, $external) { foreach($this->raw_data as $line => $student) { if ($line == 0) continue; // skip header $data = array('teacher' => $this->teacher); foreach(array('ID', 'SCIPER', 'NAME', 'EMAIL', 'SECTION') as $key) { $data[$key] = $student[$this->getColIdByName($key)]; } // Get points $points = array(); $data['items'] = array(); foreach($this->getColIdsByType('question') as $col) { $item = array(); $item['name'] = $this->getQuestionNameByColId($col); // Should we filter this question ? if (is_null($only_questions) or (!$inverse_filter and in_array($item['name'], $only_questions)) or ($inverse_filter and !in_array($item['name'], $only_questions)) ) { // Take this question into account $item['points'] = (float)$student[$col]; $item['max_points'] = $this->getMaximumPointsByColId($col); if ($item['max_points'] == 0) { // Cancelled question ? Count it right for everyone $item['right'] = 1; } else { $item['right'] = max((float)($item['points']/$item['max_points']), 0.0); } $points[] = $item['points']; $item['ticked'] = $student[$this->getColIdsByType('ticked', $item['name'])]; $item['type'] = $this->columns[$col]['type']; $item['subtype'] = $this->columns[$col]['subtype']; $data['items'][] = $item; } } $data['total'] = array_sum($points); $data['present'] = (int)(array_sum(array_map("square", $points))>0); $data['exam_points'] = $this->exam_points; // Compute marks if ($data['present']) { $data['positive_total'] = (float)max($data['total'], 0.0); if (is_null($external)) { $data['mark6'] = (float)min($data['positive_total']/($this->exam_points)*5.0+1, 6.0); } else { $output = array(); exec("./".$external." ".$data['total'], $output); $data['mark6'] = (float)trim($output[0]); } $data['quarter_mark6'] = (float)round($data['mark6']*4.0, 0)/4.0; } else { $data['positive_total'] = 'n/a'; $data['mark6'] = 'abs'; $data['quarter_mark6'] = 'abs'; } if (preg_match('/^FAKE/', $data['SCIPER'])) { if ($data['present']) $data['type'] = 'unregistered'; else $data['type'] = 'unused'; } else $data['type'] = 'student'; $this->students[] = $data; } } } // Compare students on total (higher to lower) function cmp_total($a, $b) { if ($a['total'] == $b['total']) { return 0; } return ($a['total'] < $b['total']) ? 1 : -1; } class ExamCalcs { protected $dataset = null; protected $tmp_dataset = null; public function __construct($dataset = null) { $this->dataset = array(); if (!is_null($dataset)) $this->dataset = $dataset; } public function addFile($teacher, $teacher_file, $max_points, $only_questions = null, $inverse_filter = false, $external = null) { #echo "Adding $teacher ($teacher_file) to the dataset ($max_points points).\n"; $AR = new AmcReader($teacher_file, $teacher, $max_points, $only_questions, $inverse_filter, $external); $this->addDataSet($AR->getStudents()); } public function addDataSet($data) { if (is_array($data) || is_object($data)) { foreach ($data as $student) $this->dataset[] = $student; } } public function filterBySections($sections, $update = true) { $dataset = array(); foreach ($this->dataset as $student) { if (is_array($sections)) { if (in_array($student['SECTION'], $sections)) $dataset[] = $student; } else { if ($student['SECTION'] == $sections) $dataset[] = $student; } } if ($update) $this->dataset = $dataset; return $dataset; } public function filterByTeachers($teachers, $update = true) { $dataset = array(); foreach ($this->dataset as $student) { if (is_array($teachers)) { if (in_array($student['teacher'], $teachers)) $dataset[] = $student; } else { if ($student['teacher'] == $teachers) $dataset[] = $student; } } if ($update) $this->dataset = $dataset; return $dataset; } public function getTeachers() { $teachers = array(); foreach ($this->dataset as $student) { if (!in_array($student['teacher'], $teachers)) $teachers[] = $student['teacher']; } return $teachers; } public function getSections() { $sections = array(); foreach ($this->dataset as $student) { $section = $student['SECTION']; if (!in_array($section, $sections) and $section != 'XXX') $sections[] = $section; } return $sections; } public function getQuestionsTxt() { $questions = array(); $items = array(); foreach ($this->dataset[0]['items'] as $item){ $questions[] = $item['name']; echo $item['name']; } return $questions; } public function printStatsOnCommonItems() { // Sort dataset by points $dataset = $this->sortByTotalPoints(false); if (count($dataset) < 3) throw new Exception('Dataset is too small.'); // Get items from the first student $items = array(); foreach ($this->dataset[0]['items'] as $item) $items[] = $item['name']; foreach ($dataset as $student) { // Get items for current student $tmp_items = array(); foreach ($student['items'] as $item) $tmp_items[] = $item['name']; // Keep only items in both '$items' AND '$tmp_items' $items = array_intersect($items, $tmp_items); } // Now, filter items in the dataset $filtered_dataset = array(); foreach ($dataset as $student) { if (!$student['present']) continue; $filtered_items = array(); foreach ($student['items'] as $item) { if (in_array($item['name'], $items)) $filtered_items[] = $item; } if (count($filtered_items)) { $student['items'] = $filtered_items; $filtered_dataset[] = $student; } } $dataset = $filtered_dataset; if (count($dataset) < 3) throw new Exception('Dataset is too small.'); // Compute limits $nb_students = count($dataset); $twenty_seven = (int)($nb_students*27.0/100); $upper_stop = $twenty_seven-1; $lower_start = $nb_students-$twenty_seven+1; #echo "$nb_students / $twenty_seven / 0 -> $upper_stop / $lower_start -> $nb_students \n"; $stats = array(); foreach ($dataset as $i => $student) { foreach ($student['items'] as $item) { $name = $item['name']; if (!array_key_exists($name, $stats)) $stats[$name] = array( '27%' => $twenty_seven, 'upper' => 0, 'lower' => 0, 'valid' => null, 'ticked'=> null, 'ticked_count'=> 0, 'empty_count'=> 0, 'type' => null, 'subtype' => null, 'max_points' => null, ); $stats[$name]['max_points'] = $item['max_points']; $stats[$name]['type'] = $item['type']; $stats[$name]['subtype'] = $item['subtype']; // Initialise 'ticked' table if (is_null($stats[$name]['ticked'])) { switch ($stats[$name]['subtype']) { case 'mc': $stats[$name]['ticked'] = array( 'A' => 0, 'B' => 0, 'C' => 0, 'D' => 0, 'multiple' => 0); break; case 'tf': $stats[$name]['ticked'] = array( 'TRUE' => 0, 'FALSE' => 0, 'multiple' => 0); break; default: $stats[$name]['ticked'] = array(); break; } } // Count right answers if ($item['right'] > 0) { // Save valid answer if (is_null($stats[$name]['valid'])) { switch ($stats[$name]['subtype']) { case 'tf': if ($item['ticked'] == 'A') $stats[$name]['valid'] = 'TRUE'; else $stats[$name]['valid'] = 'FALSE'; break; case 'mc': $stats[$name]['valid'] = $item['ticked']; break; case 'open': $stats[$name]['valid'] = 'n/a'; break; default: $stats[$name]['valid'] = 'n/a'; break; } } // 'upper 27%' and 'lower 27%' counters switch ($stats[$name]['subtype']) { case 'mc': case 'tf': if ($i <= $upper_stop) $stats[$name]['upper']++; if ($i >= $lower_start) $stats[$name]['lower']++; break; case 'open': if ($i <= $upper_stop) $stats[$name]['upper'] += $item['points']; if ($i >= $lower_start) $stats[$name]['lower'] += $item['points']; break; } } // Count empty answers if (empty($item['ticked'])) { $stats[$name]['empty_count']++; } else { // Stats on non-empty answers $stats[$name]['ticked_count']++; if (strlen($item['ticked']) > 1) { $stats[$name]['ticked'] = $this->createAndIncrement($stats[$name]['ticked'], 'multiple'); } else { switch ($item['subtype']) { case 'tf': if ($item['ticked'] == 'A') $field = 'TRUE'; if ($item['ticked'] == 'B') $field = 'FALSE'; $stats[$name]['ticked'] = $this->createAndIncrement($stats[$name]['ticked'], $field); break; case 'mc': $stats[$name]['ticked'] = $this->createAndIncrement($stats[$name]['ticked'], $item['ticked']); break; default: $stats[$name]['ticked'] = $this->createAndIncrement($stats[$name]['ticked'], $item['ticked']); break; } } } } } // Compute more stats $tmp = array(); foreach ($stats as $name => $stat) { // Discrimination index // For open questions, change the '27%' value. if ($stat['subtype'] == 'open') $stat['27%'] = $stat['27%']*$stat['max_points']; $stat['DI'] = ($stat['upper']-$stat['lower'])/(1.0*$stat['27%']); // Calculate percentages $ticked_percentage = array(); foreach ($stat['ticked'] as $t => $n) { $ticked_percentage[$t] = array( 'n' => $n, '%' => (float)(100.0*$n/$stat['ticked_count']), 'valid' => (int)($t == $stat['valid'])); } $stat['ticked'] = $ticked_percentage; $tmp[$name] = $stat; } $stats = $tmp; // Print CSV $previous_subtype = null; $header = '"question_id","subtype","27 %","upper","lower","DI","count","valid"'; foreach ($stats as $name => $stat) { if ($stat['subtype'] != $previous_subtype) { #if (!is_null($previous_subtype)) echo "\n"; echo $header; if ($stat['subtype'] != 'open') { foreach ($stat['ticked'] as $answer => $data) echo ",\"[$answer] count\""; foreach ($stat['ticked'] as $answer => $data) echo ",\"[$answer] %\""; } echo "\n"; $previous_subtype = $stat['subtype']; } echo "$name,{$stat['subtype']},{$stat['27%']},{$stat['upper']},{$stat['lower']},{$stat['DI']},{$stat['ticked_count']}"; if ($stat['subtype'] == 'open') { echo ",\"n/a\""; } else { foreach ($stat['ticked'] as $answer => $data) if ($data['valid'] == 1) echo ",\"$answer\""; foreach ($stat['ticked'] as $answer => $data) echo ",{$data['n']}"; foreach ($stat['ticked'] as $answer => $data) echo ",{$data['%']}"; } echo "\n"; } } public function printLatexHistoCommandsOnCommonItems() { // Sort dataset by points $dataset = $this->sortByTotalPoints(false); if (count($dataset) < 3) throw new Exception('Dataset is too small.'); // Get items from the first student $items = array(); foreach ($this->dataset[0]['items'] as $item) $items[] = $item['name']; foreach ($dataset as $student) { // Get items for current student $tmp_items = array(); foreach ($student['items'] as $item) $tmp_items[] = $item['name']; // Keep only items in both '$items' AND '$tmp_items' $items = array_intersect($items, $tmp_items); } // Now, filter items in the dataset $filtered_dataset = array(); foreach ($dataset as $student) { if (!$student['present']) continue; $filtered_items = array(); foreach ($student['items'] as $item) { if (in_array($item['name'], $items)) $filtered_items[] = $item; } if (count($filtered_items)) { $student['items'] = $filtered_items; $filtered_dataset[] = $student; } } $dataset = $filtered_dataset; if (count($dataset) < 3) throw new Exception('Dataset is too small.'); // Compute limits $nb_students = count($dataset); $twenty_seven = (int)($nb_students*27.0/100); $upper_stop = $twenty_seven-1; $lower_start = $nb_students-$twenty_seven+1; #echo "$nb_students / $twenty_seven / 0 -> $upper_stop / $lower_start -> $nb_students \n"; $stats = array(); foreach ($dataset as $i => $student) { foreach ($student['items'] as $item) { $name = $item['name']; $teacher = $student['teacher']; $name = $name . ";" . $teacher; if (!array_key_exists($name, $stats)) $stats[$name] = array( 'teacher' => null, 'valid' => null, 'ticked'=> null, 'ticked_count'=> 0, 'empty_count'=> 0, 'type' => null, 'subtype' => null, ); $stats[$name]['type'] = $item['type']; $stats[$name]['subtype'] = $item['subtype']; $stats[$name]['teacher'] = $student['teacher']; // Initialise 'ticked' table if (is_null($stats[$name]['ticked'])) { switch ($stats[$name]['subtype']) { case 'mc': $stats[$name]['ticked'] = array( 'A' => 0, 'B' => 0, 'C' => 0, 'D' => 0); break; case 'tf': $stats[$name]['ticked'] = array( 'TRUE' => 0, 'FALSE' => 0); break; default: $stats[$name]['ticked'] = array(); break; } } // Count right answers if ($item['right'] > 0) { // Save valid answer if (is_null($stats[$name]['valid'])) { switch ($stats[$name]['subtype']) { case 'tf': if ($item['ticked'] == 'A') $stats[$name]['valid'] = 'TRUE'; else $stats[$name]['valid'] = 'FALSE'; break; case 'mc': $stats[$name]['valid'] = $item['ticked']; break; case 'open': $stats[$name]['valid'] = 'n/a'; break; default: $stats[$name]['valid'] = 'n/a'; break; } } } // Count empty answers if (empty($item['ticked'])) { $stats[$name]['empty_count']++; } else { // Stats on non-empty answers $stats[$name]['ticked_count']++; if (strlen($item['ticked']) == 1) { switch ($item['subtype']) { case 'tf': if ($item['ticked'] == 'A') $field = 'TRUE'; if ($item['ticked'] == 'B') $field = 'FALSE'; $stats[$name]['ticked'] = $this->createAndIncrement($stats[$name]['ticked'], $field); break; case 'mc': $stats[$name]['ticked'] = $this->createAndIncrement($stats[$name]['ticked'], $item['ticked']); break; default: $stats[$name]['ticked'] = $this->createAndIncrement($stats[$name]['ticked'], $item['ticked']); break; } } } } } // Compute more stats $tmp = array(); foreach ($stats as $name => $stat) { // Calculate percentages $ticked_percentage = array(); foreach ($stat['ticked'] as $t => $n) { $ticked_percentage[$t] = array( 'n' => $n, '%' => (float)(100.0*$n/$stat['ticked_count']), 'valid' => (int)($t == $stat['valid'])); } $stat['ticked'] = $ticked_percentage; $tmp[$name] = $stat; } $stats = $tmp; // Print CSV, by question, then teacher //histo colors $i = 0; foreach($this->getTeachers() as $teacher){ $i++; switch ($i) { case 1: echo "\\newcommand{\\" . $teacher . "}{\\textbf{" . $teacher . "}} \n"; break; case 2: echo "\\newcommand{\\" . $teacher . "}{{\color{red}\\textbf{" . $teacher . "}}} \n"; break; case 3: echo "\\newcommand{\\" . $teacher . "}{{\color{blue}\\textbf{" . $teacher . "}}} \n"; break; case 4: echo "\\newcommand{\\" . $teacher . "}{{\color{magenta}\\textbf{" . $teacher . "}}} \n"; break; case 5: echo "\\newcommand{\\" . $teacher . "}{{\color{cyan}\\textbf{" . $teacher . "}}} \n"; break; case 6: echo "\\newcommand{\\" . $teacher . "}{{\color{olive}\\textbf{" . $teacher . "}}} \n"; break; case 7: echo "\\newcommand{\\" . $teacher . "}{{\color{orange}\\textbf{" . $teacher . "}}} \n"; break; case 8: echo "\\newcommand{\\" . $teacher . "}{{\color{black}\\textbf{" . $teacher . "}}} \n "; break; } } echo " \n"; //histo teachers present students foreach($this->getTeachers() as $teacher){ echo "\\newcommand{\N" . $teacher . "}{" . $this->getTotStudentsByTeacher($teacher) . "} \n"; } echo " \n"; $items = array(); foreach ($this->dataset[0]['items'] as $item){ if($item['subtype'] != 'open'){ echo "\inputFR{" . $item['name'] . ".tex} \n"; foreach($this->getTeachers() as $teacher){ foreach ($stats as $name => $stat) { //echo "[" . $stat['teacher'] . " - " . $teacher . " | " . $name . " - " . $item['name'] . "]"; if($stat['teacher'] == $teacher && explode(';',$name)[0] == $item['name']){ echo "\histoQCM{\\" . $teacher . "}{\N" . $teacher . "}{" . $stat['ticked_count'] . "}"; foreach ($stat['ticked'] as $answer => $data) echo "{{$data['n']}}"; } } echo "\n"; } echo "\n"; echo "\n"; } } } public function sortByTotalPoints($update = true) { if ($update) { usort($this->dataset, "cmp_total"); return $this->dataset; } else { $dataset = $this->dataset; usort($dataset, "cmp_total"); return $dataset; } } public function getDataSet() { return $this->dataset; } protected function createAndIncrement($table, $field, $increment = 1) { if (!array_key_exists($field, $table)) { $table[$field] = 0; } $table[$field] += $increment; return $table; } public function getMarks() { $marks = array(); foreach($this->dataset as $student) { $tmp = array(); $tmp['teacher'] = $student['teacher']; $tmp['ID'] = $student['ID']; $tmp['SECTION'] = $student['SECTION']; $tmp['exam_points'] = $student['exam_points']; $tmp['total'] = $student['total']; $tmp['present'] = $student['present']; $tmp['SCIPER'] = $student['SCIPER']; $tmp['quarter_mark6'] = $student['quarter_mark6']; $marks[] = $tmp; } return $marks; } public function getTotStudentsByTeacher($teacher){ $nb_students = 0; foreach($this->dataset as $student){ if($student['teacher'] == $teacher && $student['present']){ $nb_students++; } } return $nb_students; } public function getQuestions() { $questions = array(); foreach($this->dataset as $student) { //print_r($student['items']); $tmp = array(); $tmp['teacher'] = $student['teacher']; $tmp['ID'] = $student['ID']; $tmp['SECTION'] = $student['SECTION']; $tmp['SCIPER'] = $student['SCIPER']; if (!$student['present']) { $tmp['present'] = "ABS"; } else { $tmp['present'] = 1; } $tmp['exam_points'] = $student['exam_points']; $tmp['total'] = $student['total']; # Stats on questions $tmp['nb_questions'] = count($student['items']); $tmp['not_answered'] = 0; $tmp['right'] = 0; $tmp['wrong'] = 0; foreach($student['items'] as $question) { if (empty($question['ticked'])) { // Question was not answered $tmp['not_answered'] += 1; } else { if ($question['right']) $tmp['right'] += 1; else $tmp['wrong'] += 1; } } $questions[] = $tmp; } return $questions; } public function getStats() { $stats = array(); # Presence $stats['presence'] = array(); $marks = array(); $stats['quarter_mark6'] = array( 'n' => 0, 'tot' => 0, 'average' => null, 'stddev' => null, 'median' => null); foreach($this->dataset as $student) { // Presence $stats['presence'] = $this->createAndIncrement($stats['presence'], 'total'); switch ($student['type']) { case 'student': if ($student['present']) { $stats['presence'] = $this->createAndIncrement($stats['presence'], 'present'); } else { $stats['presence'] = $this->createAndIncrement($stats['presence'], 'absent'); } break; case 'unused': $stats['presence'] = $this->createAndIncrement($stats['presence'], 'unsused'); break; default: $stats['presence'] = $this->createAndIncrement($stats['presence'], 'unknown'); } // Average if ($student['present']) $marks[] = $student['quarter_mark6']; } $stats['quarter_mark6']['n'] = count($marks); if ($stats['quarter_mark6']['n'] > 0) { $stats['quarter_mark6']['tot'] = array_sum($marks); $stats['quarter_mark6']['average'] = $stats['quarter_mark6']['tot']/$stats['quarter_mark6']['n']; $stats['quarter_mark6']['stddev'] = stats_standard_deviation($marks); if (count($marks) >=3) { sort($marks); $stats['quarter_mark6']['median'] = $marks[round(count($marks)/2)]; } else { $stats['quarter_mark6']['median'] = 'n/a'; } } else { $stats['quarter_mark6']['tot'] = 0; $stats['quarter_mark6']['average'] = 0; $stats['quarter_mark6']['stddev'] = 0; $stats['quarter_mark6']['median'] = 0; } // Distribution (of marks) $distribution = array(); for ($m = 1.0 ; $m <= 6.0 ; $m += 0.25) $distribution[(string)$m] = 0; $stats['distribution_total'] = 0; foreach ($marks as $mark) { $distribution[(string)$mark]++; $stats['distribution_total']++; } $stats['distribution'] = $distribution; $stats['distribution_percentage'] = array(); if ($stats['quarter_mark6']['n']) { foreach ($stats['distribution'] as $mark => $count) $stats['distribution_percentage'][$mark] = $count*100.0/$stats['distribution_total']; } else { $stats['distribution_percentage'] = $stats['distribution']; } return($stats); } } ?>