Version19.242

This commit is contained in:
acanas 2020-05-23 15:53:53 +02:00
parent 0a90198755
commit 91319694d2
9 changed files with 242 additions and 80 deletions

View File

@ -491,7 +491,7 @@ CREATE TABLE IF NOT EXISTS exa_log (
PrnCod INT NOT NULL, PrnCod INT NOT NULL,
ActCod INT NOT NULL, ActCod INT NOT NULL,
QstInd INT NOT NULL DEFAULT -1, QstInd INT NOT NULL DEFAULT -1,
Saved ENUM('N','Y') NOT NULL DEFAULT 'N', Open ENUM('N','Y') NOT NULL DEFAULT 'N',
ClickTime DATETIME NOT NULL, ClickTime DATETIME NOT NULL,
IP CHAR(15) NOT NULL, IP CHAR(15) NOT NULL,
SessionId CHAR(43) NOT NULL, SessionId CHAR(43) NOT NULL,

View File

@ -557,10 +557,14 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD: En OpenSWAD:
ps2pdf source.ps destination.pdf ps2pdf source.ps destination.pdf
*/ */
#define Log_PLATFORM_VERSION "SWAD 19.241.1 (2020-05-22)" #define Log_PLATFORM_VERSION "SWAD 19.242 (2020-05-23)"
#define CSS_FILE "swad19.238.2.css" #define CSS_FILE "swad19.238.2.css"
#define JS_FILE "swad19.239.6.js" #define JS_FILE "swad19.239.6.js"
/* /*
Version 19.242: May 23, 2020 Changes in exam log. (301911 lines)
1 change necessary in database:
ALTER TABLE exa_log CHANGE COLUMN Saved Open ENUM('N','Y') NOT NULL DEFAULT 'N';
Version 19.241.1: May 23, 2020 Question index added to exam log. (301756 lines) Version 19.241.1: May 23, 2020 Question index added to exam log. (301756 lines)
2 changes necessary in database: 2 changes necessary in database:
ALTER TABLE exa_log ADD COLUMN QstInd INT NOT NULL DEFAULT -1 AFTER ActCod; ALTER TABLE exa_log ADD COLUMN QstInd INT NOT NULL DEFAULT -1 AFTER ActCod;

View File

@ -1054,7 +1054,7 @@ mysql> DESCRIBE exa_log;
| PrnCod | int(11) | NO | MUL | NULL | | | PrnCod | int(11) | NO | MUL | NULL | |
| ActCod | int(11) | NO | | NULL | | | ActCod | int(11) | NO | | NULL | |
| QstInd | int(11) | NO | | -1 | | | QstInd | int(11) | NO | | -1 | |
| Saved | enum('N','Y') | NO | | N | | | Open | enum('N','Y') | NO | | N | |
| ClickTime | datetime | NO | MUL | NULL | | | ClickTime | datetime | NO | MUL | NULL | |
| IP | char(15) | NO | | NULL | | | IP | char(15) | NO | | NULL | |
| SessionId | char(43) | NO | | NULL | | | SessionId | char(43) | NO | | NULL | |
@ -1067,7 +1067,7 @@ mysql> DESCRIBE exa_log;
"PrnCod INT NOT NULL," "PrnCod INT NOT NULL,"
"ActCod INT NOT NULL," "ActCod INT NOT NULL,"
"QstInd INT NOT NULL DEFAULT -1," "QstInd INT NOT NULL DEFAULT -1,"
"Saved ENUM('N','Y') NOT NULL DEFAULT 'N'," "Open ENUM('N','Y') NOT NULL DEFAULT 'N',"
"ClickTime DATETIME NOT NULL," "ClickTime DATETIME NOT NULL,"
"IP CHAR(15) NOT NULL," // Cns_MAX_BYTES_IP "IP CHAR(15) NOT NULL," // Cns_MAX_BYTES_IP
"SessionId CHAR(43) NOT NULL," // Cns_BYTES_SESSION_ID "SessionId CHAR(43) NOT NULL," // Cns_BYTES_SESSION_ID

View File

@ -27,6 +27,7 @@
#include "swad_action.h" #include "swad_action.h"
#include "swad_database.h" #include "swad_database.h"
#include "swad_exam_log.h"
#include "swad_global.h" #include "swad_global.h"
/*****************************************************************************/ /*****************************************************************************/
@ -49,14 +50,16 @@ extern struct Globals Gbl;
static struct static struct
{ {
long PrnCod; long PrnCod; // Exam print code
int QstInd; int QstInd; // Exam print question index
bool AnswerIsSaved; ExaLog_Action_t Action; // Action performed by user
} ExaLog_CurrentPrint = bool Open; // Exam print is open and accesible to answer by the user
} ExaLog_Log =
{ {
.PrnCod = -1L, // -1 means no print code set .PrnCod = -1L, // -1 means no print code set
.QstInd = -1, // -1 means no question index set .QstInd = -1, // -1 means no question index set
.AnswerIsSaved = false, // By default, answer is not saved .Action = ExaLog_UNKNOWN_ACTION,
.Open = false,
}; };
/*****************************************************************************/ /*****************************************************************************/
@ -67,42 +70,56 @@ static struct
/************* Set and get current exam print code (used in log) *************/ /************* Set and get current exam print code (used in log) *************/
/*****************************************************************************/ /*****************************************************************************/
void ExaLog_SetCurrentPrnCod (long PrnCod) void ExaLog_SetAction (ExaLog_Action_t Action)
{ {
ExaLog_CurrentPrint.PrnCod = PrnCod; ExaLog_Log.Action = Action;
} }
long ExaLog_GetCurrentPrnCod (void) ExaLog_Action_t ExaLog_GetAction (void)
{ {
return ExaLog_CurrentPrint.PrnCod; return ExaLog_Log.Action;
}
/*****************************************************************************/
/************* Set and get current exam print code (used in log) *************/
/*****************************************************************************/
void ExaLog_SetPrnCod (long PrnCod)
{
ExaLog_Log.PrnCod = PrnCod;
}
long ExaLog_GetPrnCod (void)
{
return ExaLog_Log.PrnCod;
} }
/*****************************************************************************/ /*****************************************************************************/
/****** Set and get current question index in exam print (used in log) *******/ /****** Set and get current question index in exam print (used in log) *******/
/*****************************************************************************/ /*****************************************************************************/
void ExaLog_SetCurrentQstInd (unsigned QstInd) void ExaLog_SetQstInd (unsigned QstInd)
{ {
ExaLog_CurrentPrint.QstInd = (int) QstInd; ExaLog_Log.QstInd = (int) QstInd;
} }
int ExaLog_GetCurrentQstInd (void) int ExaLog_GetQstInd (void)
{ {
return ExaLog_CurrentPrint.QstInd; return ExaLog_Log.QstInd;
} }
/*****************************************************************************/ /*****************************************************************************/
/******** Set and get if answer is saved in exam print (used in log) *********/ /******** Set and get if answer is saved in exam print (used in log) *********/
/*****************************************************************************/ /*****************************************************************************/
void ExaLog_SetAnswerIsSaved (void) void ExaLog_SetOpen (bool Open)
{ {
ExaLog_CurrentPrint.AnswerIsSaved = true; ExaLog_Log.Open = Open;
} }
bool ExaLog_GetAnswerIsSaved (void) bool ExaLog_GetOpen (void)
{ {
return ExaLog_CurrentPrint.AnswerIsSaved; return ExaLog_Log.Open;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -111,15 +128,13 @@ bool ExaLog_GetAnswerIsSaved (void)
void ExaLog_LogAccess (long LogCod) void ExaLog_LogAccess (long LogCod)
{ {
ExaLog_Action_t Action;
long PrnCod; long PrnCod;
/* WARNING: Don't change the codes os the actions. Action = ExaLog_GetAction ();
If the codes of the actions change ==> change them in exam log table */ if (Action != ExaLog_UNKNOWN_ACTION)
if (Gbl.Action.Act == ActAnsExaPrn || // Answer question
Gbl.Action.Act == ActSeeExaPrn || // Create/resume print exam
Gbl.Action.Act == ActEndExaPrn) // End print exam
{ {
PrnCod = ExaLog_GetCurrentPrnCod (); PrnCod = ExaLog_GetPrnCod ();
if (PrnCod > 0) // Only if exam print is accesible (visible, open...) if (PrnCod > 0) // Only if exam print is accesible (visible, open...)
/***** Insert access into database *****/ /***** Insert access into database *****/
@ -127,17 +142,17 @@ void ExaLog_LogAccess (long LogCod)
Redundant data (also present in log table) are stored for speed */ Redundant data (also present in log table) are stored for speed */
DB_QueryINSERT ("can not log exam access", DB_QueryINSERT ("can not log exam access",
"INSERT INTO exa_log " "INSERT INTO exa_log "
"(LogCod,PrnCod,ActCod,QstInd,Saved,ClickTime,IP,SessionId)" "(LogCod,PrnCod,ActCod,QstInd,Open,ClickTime,IP,SessionId)"
" VALUES " " VALUES "
"(%ld,%ld,%ld,%d,'%c',NOW(),'%s','%s')", "(%ld,%ld,%ld,%d,'%c',NOW(),'%s','%s')",
LogCod, LogCod,
PrnCod, PrnCod,
Act_GetActCod (Gbl.Action.Act), // Redundant, for speed (unsigned) Action,
ExaLog_GetCurrentQstInd (), ExaLog_GetQstInd (),
ExaLog_GetAnswerIsSaved () ? 'Y' : ExaLog_GetOpen () ? 'Y' :
'N', 'N',
// NOW() Redundant, for speed // NOW() Redundant, for speed
Gbl.IP, // Redundant, for speed Gbl.IP, // Redundant, for speed
Gbl.Session.Id); Gbl.Session.Id);
} }
} }

View File

@ -31,16 +31,29 @@
/************************* Public types and constants ************************/ /************************* Public types and constants ************************/
/*****************************************************************************/ /*****************************************************************************/
#define ExaLog_NUM_ACTIONS 5
// Don't change the numbers! If change ==> update them in table exa_log
typedef enum
{
ExaLog_UNKNOWN_ACTION = 0,
ExaLog_START_EXAM = 1,
ExaLog_RESUME_EXAM = 2,
ExaLog_ANSWER_QUESTION = 3,
ExaLog_FINISH_EXAM = 4,
} ExaLog_Action_t;
/*****************************************************************************/ /*****************************************************************************/
/***************************** Public prototypes *****************************/ /***************************** Public prototypes *****************************/
/*****************************************************************************/ /*****************************************************************************/
void ExaLog_SetCurrentPrnCod (long PrnCod); void ExaLog_SetPrnCod (long PrnCod);
long ExaLog_GetCurrentPrnCod (void); long ExaLog_GetPrnCod (void);
void ExaLog_SetCurrentQstInd (unsigned QstInd); void ExaLog_SetAction (ExaLog_Action_t Action);
int ExaLog_GetCurrentQstInd (void); ExaLog_Action_t ExaLog_GetAction (void);
void ExaLog_SetAnswerIsSaved (void); void ExaLog_SetQstInd (unsigned QstInd);
bool ExaLog_GetAnswerIsSaved (void); int ExaLog_GetQstInd (void);
void ExaLog_SetOpen (bool Open);
bool ExaLog_GetOpen (void);
void ExaLog_LogAccess (long LogCod); void ExaLog_LogAccess (long LogCod);

View File

@ -198,26 +198,38 @@ void ExaPrn_ShowExamPrint (void)
Print.UsrCod = Gbl.Usrs.Me.UsrDat.UsrCod; Print.UsrCod = Gbl.Usrs.Me.UsrDat.UsrCod;
ExaPrn_GetPrintDataBySesCodAndUsrCod (&Print); ExaPrn_GetPrintDataBySesCodAndUsrCod (&Print);
if (Print.PrnCod > 0) // Print exists and I can access to it if (Print.PrnCod <= 0) // Print does not exists
/***** Get questions and user's answers of exam print from database *****/
ExaPrn_GetPrintQuestionsFromDB (&Print);
else
{ {
/***** Get questions from database *****/ /***** Get questions from database *****/
ExaPrn_GetQuestionsForNewPrintFromDB (&Print,Exam.ExaCod); ExaPrn_GetQuestionsForNewPrintFromDB (&Print,Exam.ExaCod);
if (Print.NumQsts) if (Print.NumQsts)
{
/***** Create/update new exam print in database *****/ /***** Create/update new exam print in database *****/
ExaPrn_CreatePrintInDB (&Print); ExaPrn_CreatePrintInDB (&Print);
}
/***** Set current print code (to be used in log) *****/ /***** Set log print code and action *****/
ExaLog_SetCurrentPrnCod (Print.PrnCod); ExaLog_SetPrnCod (Print.PrnCod);
ExaLog_SetAction (ExaLog_START_EXAM);
ExaLog_SetOpen (true);
}
}
else // Print exists
{
/***** Get questions and current user's answers from database *****/
ExaPrn_GetPrintQuestionsFromDB (&Print);
/***** Set log print code and action *****/
ExaLog_SetPrnCod (Print.PrnCod);
ExaLog_SetAction (ExaLog_RESUME_EXAM);
ExaLog_SetOpen (true);
}
/***** Show test exam to be answered *****/ /***** Show test exam to be answered *****/
ExaPrn_ShowExamPrintToFillIt (&Exams,&Exam,&Print); ExaPrn_ShowExamPrintToFillIt (&Exams,&Exam,&Print);
} }
else else // Session not open or accessible
/***** Show warning *****/
Ale_ShowAlert (Ale_INFO,Txt_You_dont_have_access_to_the_exam); Ale_ShowAlert (Ale_INFO,Txt_You_dont_have_access_to_the_exam);
} }
@ -983,21 +995,23 @@ void ExaPrn_ReceivePrintAnswer (void)
if (Print.PrnCod <= 0) if (Print.PrnCod <= 0)
Lay_WrongExamExit (); Lay_WrongExamExit ();
/***** Set current print code (to be used in log) *****/
ExaLog_SetCurrentPrnCod (Print.PrnCod);
/***** Get questions and current user's answers of exam print from database *****/ /***** Get questions and current user's answers of exam print from database *****/
ExaPrn_GetPrintQuestionsFromDB (&Print); ExaPrn_GetPrintQuestionsFromDB (&Print);
/***** Get question index from form *****/ /***** Get question index from form *****/
QstInd = ExaPrn_GetParamQstInd (); QstInd = ExaPrn_GetParamQstInd ();
/***** Set current question index (to be used in log) *****/ /***** Set log print code, action and question index *****/
ExaLog_SetCurrentQstInd (QstInd); ExaLog_SetPrnCod (Print.PrnCod);
ExaLog_SetAction (ExaLog_ANSWER_QUESTION);
ExaLog_SetQstInd (QstInd);
/***** Check if session if visible and open *****/ /***** Check if session if visible and open *****/
if (ExaSes_CheckIfSessionIsVisibleAndOpen (Print.SesCod)) if (ExaSes_CheckIfSessionIsVisibleAndOpen (Print.SesCod))
{ {
/***** Set log open ****/
ExaLog_SetOpen (true);
/***** Get answers from form to assess a test *****/ /***** Get answers from form to assess a test *****/
ExaPrn_GetAnswerFromForm (&Print,QstInd); ExaPrn_GetAnswerFromForm (&Print,QstInd);
@ -1010,14 +1024,17 @@ void ExaPrn_ReceivePrintAnswer (void)
ExaPrn_ComputeTotalScoreOfPrint (&Print); ExaPrn_ComputeTotalScoreOfPrint (&Print);
ExaPrn_UpdatePrintInDB (&Print); ExaPrn_UpdatePrintInDB (&Print);
/***** Set success saving answer (to be used in log) *****/
ExaLog_SetAnswerIsSaved ();
/***** Show table with questions to answer *****/ /***** Show table with questions to answer *****/
ExaPrn_ShowTableWithQstsToFill (&Print); ExaPrn_ShowTableWithQstsToFill (&Print);
} }
else else // Not accessible to answer
{
/***** Set log open ****/
ExaLog_SetOpen (true);
/***** Show warning *****/
Ale_ShowAlert (Ale_INFO,Txt_You_dont_have_access_to_the_exam); Ale_ShowAlert (Ale_INFO,Txt_You_dont_have_access_to_the_exam);
}
} }
/*****************************************************************************/ /*****************************************************************************/

View File

@ -1132,8 +1132,12 @@ void ExaRes_ShowOneExaResult (void)
Print.UsrCod = UsrDat->UsrCod; Print.UsrCod = UsrDat->UsrCod;
ExaPrn_GetPrintDataBySesCodAndUsrCod (&Print); ExaPrn_GetPrintDataBySesCodAndUsrCod (&Print);
/***** Set current print code (to be used in log) *****/ /***** Set log action and print code *****/
ExaLog_SetCurrentPrnCod (Print.PrnCod); if (Gbl.Action.Act == ActEndExaPrn)
{
ExaLog_SetAction (ExaLog_FINISH_EXAM);
ExaLog_SetPrnCod (Print.PrnCod);
}
/***** Check if I can view this print result *****/ /***** Check if I can view this print result *****/
switch (Gbl.Usrs.Me.Role.Logged) switch (Gbl.Usrs.Me.Role.Logged)

View File

@ -67,6 +67,7 @@
#include "swad_degree.h" #include "swad_degree.h"
#include "swad_degree_type.h" #include "swad_degree_type.h"
#include "swad_department.h" #include "swad_department.h"
#include "swad_exam_log.h"
#include "swad_figure.h" #include "swad_figure.h"
#include "swad_file_browser.h" #include "swad_file_browser.h"
#include "swad_forum.h" #include "swad_forum.h"
@ -11876,6 +11877,114 @@ const char *Txt_EXAM_ANNOUNCEMENT_Year_or_semester = // 1, 2, 3..., not 1984, 20
"Ano ou semestre"; "Ano ou semestre";
#endif #endif
const char *Txt_EXAM_LOG_ACTIONS[ExaLog_NUM_ACTIONS] =
{
[ExaLog_UNKNOWN_ACTION] =
#if L==1 // ca
"Acci&oacute; desconeguda"
#elif L==2 // de
"Unbekannte Aktion"
#elif L==3 // en
"Unknown action"
#elif L==4 // es
"Acci&oacute;n desconocida"
#elif L==5 // fr
"Action inconnue"
#elif L==6 // gn
"Acci&oacute;n desconocida" // Okoteve traducción
#elif L==7 // it
"Azione sconosciuta"
#elif L==8 // pl
"Nieznana akcja"
#elif L==9 // pt
"A&ccedil;&atilde;o desconhecida"
#endif
,
[ExaLog_START_EXAM] =
#if L==1 // ca
"Va comen&ccedil;ar l'examen"
#elif L==2 // de
"Begann die Pr&uacute;fung"
#elif L==3 // en
"Started the exam"
#elif L==4 // es
"Comenz&oacute; el examen"
#elif L==5 // fr
"A commenc&eacute; l'examen"
#elif L==6 // gn
"Comenz&oacute; el examen" // Okoteve traducción
#elif L==7 // it
"Ha iniziato l'esame"
#elif L==8 // pl
"Rozpocz&aogon;&lstrok; egzamin"
#elif L==9 // pt
"Iniciou o exame"
#endif
,
[ExaLog_RESUME_EXAM] =
#if L==1 // ca
"Va reprendre l'examen"
#elif L==2 // de
"Nahm die Pr&uuml;fung wieder auf"
#elif L==3 // en
"Resumed the exam"
#elif L==4 // es
"Reanud&oacute; el examen"
#elif L==5 // fr
"A repris l'examen"
#elif L==6 // gn
"Reanud&oacute; el examen" // Okoteve traducción
#elif L==7 // it
"Ha ripreso l'esame"
#elif L==8 // pl
"Wznowi&lstrok; egzamin"
#elif L==9 // pt
"Retomou o exame"
#endif
,
[ExaLog_ANSWER_QUESTION] =
#if L==1 // ca
"Va respondre una pregunta"
#elif L==2 // de
"Beantwortete eine Frage"
#elif L==3 // en
"Answer exam question"
#elif L==4 // es
"Respondi&oacute; una pregunta"
#elif L==5 // fr
"A r&eacute;pondu &agrave; une question"
#elif L==6 // gn
"Respondi&oacute; una pregunta" // Okoteve traducción
#elif L==7 // it
"Ha risposto a una domanda"
#elif L==8 // pl
"Odpowiedzia&lstrok; na pytanie"
#elif L==9 // pt
"Respondeu a uma pergunta"
#endif
,
[ExaLog_FINISH_EXAM] =
#if L==1 // ca
"Va acabar l'examen"
#elif L==2 // de
"Beendete die Pr&uuml;fung"
#elif L==3 // en
"Finished the exam"
#elif L==4 // es
"Termin&oacute; el examen"
#elif L==5 // fr
"A termin&eacute; l'examen"
#elif L==6 // gn
"Termin&oacute; el examen" // Okoteve traducción
#elif L==7 // it
"Ha terminato l'esame"
#elif L==8 // pl
"Zako&nacute;czy&lstrok; egzamin"
#elif L==9 // pt
"Terminou o exame"
#endif
};
const char *Txt_Exam_of_X = // Warning: it is very important to include %s in the following sentences const char *Txt_Exam_of_X = // Warning: it is very important to include %s in the following sentences
#if L==1 // ca #if L==1 // ca
"Examen de %s"; "Examen de %s";

View File

@ -10900,65 +10900,65 @@ const char *Txt_Actions[Act_NUM_ACTIONS] =
, ,
[ActSeeExaPrn] = [ActSeeExaPrn] =
#if L==1 // ca #if L==1 // ca
"" // Necessita traducció "Comen&ccedil;ar / reprendre examen"
#elif L==2 // de #elif L==2 // de
"" // Need Übersetzung "Pr&uacute;fung starten / fortsetzen"
#elif L==3 // en #elif L==3 // en
"Start / resume exam" "Start / resume exam"
#elif L==4 // es #elif L==4 // es
"Comenzar / reanudar examen" "Comenzar / reanudar examen"
#elif L==5 // fr #elif L==5 // fr
"" // Besoin de traduction "Commencer / reprendre examen"
#elif L==6 // gn #elif L==6 // gn
"" // Okoteve traducción "Comenzar / reanudar examen" // Okoteve traducción
#elif L==7 // it #elif L==7 // it
"" // Bisogno di traduzione "Avvia / riprendi esame"
#elif L==8 // pl #elif L==8 // pl
"" // Potrzebujesz tlumaczenie "Rozpocznij / wzn&oacute;w egzamin"
#elif L==9 // pt #elif L==9 // pt
"" // Precisa de tradução "Iniciar / retomar exame"
#endif #endif
, ,
[ActAnsExaPrn] = [ActAnsExaPrn] =
#if L==1 // ca #if L==1 // ca
"" // Necessita traducció "Respondre pregunta d'examen"
#elif L==2 // de #elif L==2 // de
"" // Need Übersetzung "Beantworten Sie die Pr&uuml;fungsfrage"
#elif L==3 // en #elif L==3 // en
"Answer exam question" "Answer exam question"
#elif L==4 // es #elif L==4 // es
"Responder pregunta de examen" "Responder pregunta de examen"
#elif L==5 // fr #elif L==5 // fr
"" // Besoin de traduction "R&eacute;pondre question d'examen"
#elif L==6 // gn #elif L==6 // gn
"" // Okoteve traducción "Responder pregunta de examen" // Okoteve traducción
#elif L==7 // it #elif L==7 // it
"" // Bisogno di traduzione "Rispondi domanda d'esame"
#elif L==8 // pl #elif L==8 // pl
"" // Potrzebujesz tlumaczenie "Odpowiedz pytanie egzaminacyjne"
#elif L==9 // pt #elif L==9 // pt
"" // Precisa de tradução "Responda pergunta do exame"
#endif #endif
, ,
[ActEndExaPrn] = [ActEndExaPrn] =
#if L==1 // ca #if L==1 // ca
"" // Necessita traducció "Finalitzar examen"
#elif L==2 // de #elif L==2 // de
"" // Need Übersetzung "Pr&uuml;fung beenden"
#elif L==3 // en #elif L==3 // en
"End exam" "End exam"
#elif L==4 // es #elif L==4 // es
"Finalizar examen" "Finalizar examen"
#elif L==5 // fr #elif L==5 // fr
"" // Besoin de traduction "Terminer examen"
#elif L==6 // gn #elif L==6 // gn
"" // Okoteve traducción "Finalizar examen" // Okoteve traducción
#elif L==7 // it #elif L==7 // it
"" // Bisogno di traduzione "Finire esame"
#elif L==8 // pl #elif L==8 // pl
"" // Potrzebujesz tlumaczenie "Zako&nacute;czy&cacute; egzamin"
#elif L==9 // pt #elif L==9 // pt
"" // Precisa de tradução "Terminar exame"
#endif #endif
, ,
[ActSeeMyExaResCrs] = [ActSeeMyExaResCrs] =