Add calculated answers feature. Doesn't include icons. - refs #7212

1.9.x
Imanol Losada 11 years ago
parent 444dfd9519
commit a2ff44cf69
  1. 228
      main/exercice/calculated_answer.class.php
  2. 110
      main/exercice/exercise.class.php
  3. 94
      main/exercice/exercise.lib.php
  4. 8
      main/exercice/exercise_submit.php
  5. 2
      main/exercice/question.class.php
  6. 6
      main/inc/ajax/exercise.ajax.php
  7. 390
      main/inc/lib/evalmath.class.php
  8. 33
      main/inc/lib/exercise_show_functions.lib.php
  9. 36
      main/lang/english/trad4all.inc.php
  10. 61
      main/lang/spanish/trad4all.inc.php

@ -0,0 +1,228 @@
<?php
/* For licensing terms, see /license.txt */
/**
*
* Class CalculatedAnswer
*
* @author Imanol Losada
* @package chamilo.exercise
**/
class CalculatedAnswer extends Question
{
static $typePicture = 'calculated_answer.png';
static $explanationLangVar = 'CalculatedAnswer';
/**
* Constructor
*/
public function CalculatedAnswer()
{
parent::question();
$this -> type = CALCULATED_ANSWER;
$this -> isContent = $this-> getIsContent();
}
/**
* function which redefines Question::createAnswersForm
* @param the formvalidator instance
*/
function createAnswersForm($form)
{
$defaults = array();
if (!empty($this->id)) {
$objAnswer = new answer($this->id);
$preArray = explode('@@', $objAnswer->selectAnswer(1));
$defaults['formula'] = array_pop($preArray);
$defaults['answer'] = array_shift($preArray);
$defaults['answer'] = preg_replace("/\[.*\]/", "", $defaults['answer']);
$defaults['weighting'] = $this->weighting;
} else {
$defaults['answer'] = get_lang('DefaultTextInBlanks');
}
$lowestValue = "1.00";
$highestValue = "20.00";
// javascript //
echo '<script>
function parseTextNumber(textNumber, floatValue) {
if (textNumber.indexOf(".") > -1) {
textNumber = parseFloat(textNumber);
floatValue.exists = "true";
} else {
textNumber = parseInt(textNumber);
}
return textNumber;
}
function updateRandomValue(element) {
// "floatValue" helps to distinguish between an integer (10) and a float with all 0 decimals (10.00)
var floatValue = { exists: "false" };
var index = (element.name).match(/\[[^\]]*\]/g);
var lowestValue = parseTextNumber(document.getElementById("lowestValue"+index).value, floatValue);
var highestValue = parseTextNumber(document.getElementById("highestValue"+index).value, floatValue);
var result = Math.random() * (highestValue - lowestValue) + lowestValue;
if (floatValue.exists == "true") {
result = parseFloat(result).toFixed(2);
} else {
result = parseInt(result);
}
document.getElementById("randomValue"+index).innerHTML = "'.get_lang("ExampleValue").': " + result;
}
function FCKeditor_OnComplete(editorInstance) {
if (window.attachEvent) {
editorInstance.EditorDocument.attachEvent("onkeyup", updateBlanks) ;
} else {
editorInstance.EditorDocument.addEventListener("keyup", updateBlanks, true);
}
}
var firstTime = true;
function updateBlanks() {
if (firstTime) {
field = document.getElementById("answer");
var answer = field.value;
} else {
var oEditor = FCKeditorAPI.GetInstance("answer");
//var answer = oEditor.GetXHTML(true);
var answer = oEditor.EditorDocument.body.innerHTML;
}
var blanks = answer.match(/\[[^\]]*\]/g);
var fields = "<div class=\"control-group\"><label class=\"control-label\">'.get_lang('VariableRanges').'</label><div class=\"controls\"><table>";
if (blanks!=null) {
if (typeof updateBlanks.randomValues === "undefined") {
updateBlanks.randomValues = [];
}
for (i=0 ; i<blanks.length ; i++){
if (document.getElementById("lowestValue["+i+"]") && document.getElementById("highestValue["+i+"]")) {
lowestValue = document.getElementById("lowestValue["+i+"]").value;
highestValue = document.getElementById("highestValue["+i+"]").value;
} else {
lowestValue = '.$lowestValue.'.toFixed(2);
highestValue = '.$highestValue.'.toFixed(2);
for (j=0; j<blanks.length; j++) {
updateBlanks.randomValues[j] = parseFloat(Math.random() * (highestValue - lowestValue) + lowestValue).toFixed(2);
}
}
fields += "<tr><td><label>"+blanks[i]+"</label></td><td><input class=\"span1\" style=\"margin-left: 0em;\" size=\"5\" value=\""+lowestValue+"\" type=\"text\" id=\"lowestValue["+i+"]\" name=\"lowestValue["+i+"]\" onblur=\"updateRandomValue(this)\"/></td><td><input class=\"span1\" style=\"margin-left: 0em; width:80px;\" size=\"5\" value=\""+highestValue+"\" type=\"text\" id=\"highestValue["+i+"]\" name=\"highestValue["+i+"]\" onblur=\"updateRandomValue(this)\"/></td><td><label class=\"span3\" id=\"randomValue["+i+"]\"/>'.get_lang('ExampleValue').': "+updateBlanks.randomValues[i]+"</label></td></tr>";
}
}
document.getElementById("blanks_weighting").innerHTML = fields + "</table></div></div>";
if (firstTime) {
firstTime = false;
}
}
window.onload = updateBlanks;
</script>';
// answer
$form->addElement('label', null, '<br /><br />'.get_lang('TypeTextBelow').', '.get_lang('And').' '.get_lang('UseTagForBlank'));
$form->addElement('html_editor', 'answer', '<img src="../img/fill_field.png">','id="answer" cols="122" rows="6" onkeyup="javascript: updateBlanks(this);"', array('ToolbarSet' => 'TestQuestionDescription', 'Width' => '100%', 'Height' => '350'));
$form->addRule('answer', get_lang('GiveText'),'required');
$form->addRule('answer', get_lang('DefineBlanks'),'regex','/\[.*\]/');
$form->addElement('label', null, get_lang('IfYouWantOnlyIntegerValuesWriteBothLimitsWithoutDecimals'));
$form->addElement('html', '<div id="blanks_weighting"></div>');
$form->addElement('label', null, get_lang('FormulaExample').': &radic;<span style="text-decoration:overline;">&nbsp;x &divide y&nbsp;</span> &times e <sup>(ln(pi))</sup> = sqrt([x]/[y])*(e^(ln(pi)))');
$form->addElement('text', 'formula', get_lang('Formula'), array('id' => 'formula', 'class' => 'span4'));
$form->addRule('formula', get_lang('GiveFormula'), 'required');
$form->addElement('text', 'weighting', get_lang('Weighting'), array('id' => 'weighting', 'class' => 'span1'));
$form->setDefaults(array('weighting' => '10'));
$form->addElement('text', 'answerVariations', get_lang('AnswerVariations'), array('class' => 'span1'));
$form->addRule('answerVariations', get_lang('GiveAnswerVariations'),'required');
$form->setDefaults(array('answerVariations' => '1'));
global $text, $class;
// setting the save button here and not in the question class.php
$form->addElement('style_submit_button', 'submitQuestion', $text, 'class="'.$class.'"');
if (!empty($this->id)) {
$form -> setDefaults($defaults);
} else {
if ($this->isContent == 1) {
$form->setDefaults($defaults);
}
}
}
/**
* abstract function which creates the form to create / edit the answers of the question
* @param FormValidator $form
*/
function processAnswersCreation($form)
{
global $charset;
$answer = $form->getSubmitValue('answer');
$formula = $form->getSubmitValue('formula');
$lowestValues = $form->getSubmitValue('lowestValue');
$highestValues = $form->getSubmitValue('highestValue');
$answerVariations = $form->getSubmitValue('answerVariations');
$this->weighting = $form->getSubmitValue('weighting');
//Remove previous answers
Database::delete("c_quiz_answer", array('question_id = ?' => $this->id));
// Create as many answers as $answerVariations
for ($j=0 ; $j < $answerVariations; $j++) {
$auxAnswer = $answer;
$auxFormula = $formula;
$nb = preg_match_all('/\[[^\]]*\]/', $auxAnswer, $blanks);
if ($nb > 0) {
for ($i=0 ; $i < $nb; ++$i) {
$blankItem = $blanks[0][$i];
$replace = array("[", "]");
$newBlankItem = str_replace($replace, "", $blankItem);
$newBlankItem = "[".trim($newBlankItem)."]";
$randomValue = mt_rand($lowestValues[$i],$highestValues[$i]);
//$randomValue = mt_rand($lowestValues[$i]*100,$highestValues[$i]*100)/100;
$auxAnswer = str_replace($blankItem, $randomValue, $auxAnswer);
$auxFormula = str_replace($blankItem, $randomValue, $auxFormula);
}
require_once(api_get_path(LIBRARY_PATH).'evalmath.class.php');
$math = new EvalMath();
$result = $math->evaluate($auxFormula);
$result = number_format($result, 2, ".", "");
// Remove decimal trailing zeros
$result = rtrim($result, "0");
// If it is an integer (ends in .00) remove the decimal point
if (mb_substr($result, -1) === ".") {
$result = str_replace(".", "", $result);
}
// Attach formula
$auxAnswer .= " [".$result."]@@".$formula;
}
$this->save();
$objAnswer = new answer($this->id);
$objAnswer->createAnswer($auxAnswer, 1, '', $this->weighting, array());
$objAnswer->position = array();
$objAnswer->save();
}
}
/**
* @param null $feedback_type
* @param null $counter
* @param null $score
* @return null|string
*/
function return_header($feedback_type = null, $counter = null, $score = null)
{
$header = parent::return_header($feedback_type, $counter, $score);
$header .= '<table class="'.$this->question_table_class .'">
<tr>
<th>'.get_lang("Answer").'</th>
</tr>';
return $header;
}
}

@ -1736,7 +1736,7 @@ class Exercise
return $id;
}
public function show_button($question_id, $questionNum, $questions_in_media = array()) {
public function show_button($question_id, $questionNum, $questions_in_media = array(), $currentAnswer = '') {
global $origin, $safe_lp_id, $safe_lp_item_id, $safe_lp_item_view_id;
$nbrQuestions = $this->get_count_question_list();
@ -1779,7 +1779,7 @@ class Exercise
$questions_in_media = "['".implode("','",$questions_in_media)."']";
$all_button .= '&nbsp;<a href="javascript://" class="'.$class.'" onclick="save_question_list('.$questions_in_media.'); ">'.$label.'</a>';
} else {
$all_button .= '&nbsp;<a href="javascript://" class="'.$class.'" onclick="save_now('.$question_id.'); ">'.$label.'</a>';
$all_button .= '&nbsp;<a href="javascript://" class="'.$class.'" onclick="save_now('.$question_id.', \'\', \''.$currentAnswer.'\'); ">'.$label.'</a>';
}
$all_button .= '<span id="save_for_now_'.$question_id.'" class="exercise_save_mini_message"></span>&nbsp;';
@ -2123,7 +2123,7 @@ class Exercise
error_log('$answerType: '.$answerType);
}
if ($answerType == FREE_ANSWER || $answerType == ORAL_EXPRESSION) {
if ($answerType == FREE_ANSWER || $answerType == ORAL_EXPRESSION || $answerType == CALCULATED_ANSWER) {
$nbrAnswers = 1;
}
@ -2521,6 +2521,102 @@ class Exercise
}
}
break;
// for calculated answer
case CALCULATED_ANSWER:
$answer = $objAnswerTmp->selectAnswer($_SESSION['calculatedAnswerId'][$questionId]);
$preArray = explode('@@', $answer);
$last = count($preArray) - 1;
$answer = '';
for ($k = 0; $k < $last; $k++) {
$answer .= $preArray[$k];
}
$answerWeighting = array($answerWeighting);
// we save the answer because it will be modified
$temp = $answer;
$answer = '';
$j = 0;
//initialise answer tags
$userTags = $correctTags = $realText = array();
// the loop will stop at the end of the text
while (1) {
// quits the loop if there are no more blanks (detect '[')
if (($pos = api_strpos($temp, '[')) === false) {
// adds the end of the text
$answer = $temp;
$realText[] = $answer;
break; //no more "blanks", quit the loop
}
// adds the piece of text that is before the blank
//and ends with '[' into a general storage array
$realText[] = api_substr($temp, 0, $pos +1);
$answer .= api_substr($temp, 0, $pos +1);
//take the string remaining (after the last "[" we found)
$temp = api_substr($temp, $pos +1);
// quit the loop if there are no more blanks, and update $pos to the position of next ']'
if (($pos = api_strpos($temp, ']')) === false) {
// adds the end of the text
$answer .= $temp;
break;
}
if ($from_database) {
$queryfill = "SELECT answer FROM ".$TBL_TRACK_ATTEMPT."
WHERE
exe_id = '".$exeId."' AND
question_id= '".Database::escape_string($questionId)."'";
$resfill = Database::query($queryfill);
$str = Database::result($resfill, 0, 'answer');
api_preg_match_all('#\[([^[]*)\]#', $str, $arr);
$str = str_replace('\r\n', '', $str);
$choice = $arr[1];
if (isset($choice[$j])) {
$tmp = api_strrpos($choice[$j], ' / ');
$choice[$j] = api_substr($choice[$j], 0, $tmp);
$choice[$j] = trim($choice[$j]);
// Needed to let characters ' and " to work as part of an answer
$choice[$j] = stripslashes($choice[$j]);
} else {
$choice[$j] = null;
}
} else {
// This value is the user input, not escaped while correct answer is escaped by fckeditor
$choice[$j] = api_htmlentities(trim($choice[$j]));
}
$userTags[] = $choice[$j];
//put the contents of the [] answer tag into correct_tags[]
$correctTags[] = api_substr($temp, 0, $pos);
$j++;
$temp = api_substr($temp, $pos +1);
}
$answer = '';
$realCorrectTags = $correctTags;
for ($i = 0; $i < count($realCorrectTags); $i++) {
if ($i == 0) {
$answer .= $realText[0];
}
// Needed to parse ' and " characters
$userTags[$i] = stripslashes($userTags[$i]);
if ($correctTags[$i] == $userTags[$i]) {
// gives the related weighting to the student
$questionScore += $answerWeighting[$i];
// increments total score
$totalScore += $answerWeighting[$i];
// adds the word in green at the end of the string
$answer .= $correctTags[$i];
} elseif (!empty($userTags[$i])) {
// else if the word entered by the student IS NOT the same as the one defined by the professor
// adds the word in red at the end of the string, and strikes it
$answer .= '<font color="red"><s>' . $userTags[$i] . '</s></font>';
} else {
// adds a tabulation if no word has been typed by the student
$answer .= ''; // remove &nbsp; that causes issue
}
// adds the correct word, followed by ] to close the blank
$answer .= ' / <font color="green"><b>' . $realCorrectTags[$i] . '</b></font>]';
if (isset($realText[$i +1])) {
$answer .= $realText[$i +1];
}
}
break;
// for free answer
case FREE_ANSWER:
if ($from_database) {
@ -2757,6 +2853,10 @@ class Exercise
//if ($origin!='learnpath') {
ExerciseShowFunctions::display_fill_in_blanks_answer($feedback_type, $answer,0,0);
// }
} elseif($answerType == CALCULATED_ANSWER) {
//if ($origin!='learnpath') {
ExerciseShowFunctions::display_calculated_answer($feedback_type, $answer,0,0);
// }
} elseif($answerType == FREE_ANSWER) {
//if($origin != 'learnpath') {
ExerciseShowFunctions::display_free_answer($feedback_type, $choice, $exeId, $questionId, $questionScore);
@ -2964,6 +3064,9 @@ class Exercise
case FILL_IN_BLANKS:
ExerciseShowFunctions::display_fill_in_blanks_answer($feedback_type, $answer,$exeId,$questionId);
break;
case CALCULATED_ANSWER:
ExerciseShowFunctions::display_calculated_answer($feedback_type, $answer, $exeId, $questionId);
break;
case FREE_ANSWER:
echo ExerciseShowFunctions::display_free_answer($feedback_type, $choice, $exeId, $questionId, $questionScore);
break;
@ -3197,7 +3300,6 @@ class Exercise
'threadhold2'=>$threadhold2,
'threadhold3'=> $threadhold3,
);
if ($from == 'exercise_result') {
// if answer is hotspot. To the difference of exercise_show.php, we use the results from the session (from_db=0)
// TODO Change this, because it is wrong to show the user some results that haven't been stored in the database yet

@ -534,8 +534,100 @@ function showQuestion(
$attributes
), $answer);*/
}
$s .= $answer;
$s .= $answer;
} elseif ($answerType == CALCULATED_ANSWER) {
/*
* In the CALCULATED_ANSWER test
* you mustn't have [ and ] in the textarea
* you mustn't have @@ in the textarea
* the text to find mustn't be empty or contains only spaces
* the text to find mustn't contains HTML tags
* the text to find mustn't contains char "
*/
if ($origin !== null) {
global $exe_id;
$trackAttempts = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
$sqlTrackAttempt = 'SELECT answer FROM '.$trackAttempts.' WHERE exe_id='.$exe_id.' AND question_id='.$questionId;
$rsLastAttempt = Database::query($sqlTrackAttempt);
$rowLastAttempt = Database::fetch_array($rsLastAttempt);
$answer = $rowLastAttempt['answer'];
if (empty($answer)) {
$_SESSION['calculatedAnswerId'][$questionId] = mt_rand(1, $nbrAnswers);
$answer = $objAnswerTmp->selectAnswer($_SESSION['calculatedAnswerId'][$questionId]);
}
}
list($answer) = explode('@@', $answer);
// $correctAnswerList array of array with correct anwsers 0=> [0=>[\p] 1=>[plop]]
api_preg_match_all('/\[[^]]+\]/', $answer, $correctAnswerList);
// get student answer to display it if student go back to previous calculated answer question in a test
if (isset($user_choice[0]['answer'])) {
api_preg_match_all('/\[[^]]+\]/', $answer, $studentAnswerList);
$studentAnswerListTobecleaned = $studentAnswerList[0];
$studentAnswerList = array();
for ($i=0; $i < count($studentAnswerListTobecleaned); $i++) {
$answerCorrected = $studentAnswerListTobecleaned[$i];
$answerCorrected = api_preg_replace('| / <font color="green"><b>.*$|', '', $answerCorrected);
$answerCorrected = api_preg_replace('/^\[/', '', $answerCorrected);
$answerCorrected = api_preg_replace('|^<font color="red"><s>|', '', $answerCorrected);
$answerCorrected = api_preg_replace('|</s></font>$|', '', $answerCorrected);
$answerCorrected = '['.$answerCorrected.']';
$studentAnswerList[] = $answerCorrected;
}
}
// If display preview of answer in test view for exemple, set the student answer to the correct answers
if ($debug_mark_answer) {
// contain the rights answers surronded with brackets
$studentAnswerList = $correctAnswerList[0];
}
/*
Split the response by bracket
tabComments is an array with text surrounding the text to find
we add a space before and after the answerQuestion to be sure to
have a block of text before and after [xxx] patterns
so we have n text to find ([xxx]) and n+1 block of texts before,
between and after the text to find
*/
$tabComments = api_preg_split('/\[[^]]+\]/', ' '.$answer.' ');
if (!empty($correctAnswerList) && !empty($studentAnswerList)) {
$answer = "";
$i = 0;
foreach ($studentAnswerList as $studentItem) {
// remove surronding brackets
$studentResponse = api_substr($studentItem, 1, api_strlen($studentItem) - 2);
$size = strlen($studentItem);
$attributes['class'] = detectInputAppropriateClass($size);
$answer .= $tabComments[$i].
Display::input(
'text',
"choice[$questionId][]",
$studentResponse,
$attributes
);
$i++;
}
$answer .= $tabComments[$i];
} else {
// display exercise with empty input fields
// every [xxx] are replaced with an empty input field
foreach ($correctAnswerList[0] as $item) {
$size = strlen($item);
$attributes['class'] = detectInputAppropriateClass($size);
$answer = str_replace(
$item,
Display::input('text', "choice[$questionId][]", '', $attributes),
$answer
);
}
}
if ($origin !== null) {
$s = $answer;
break;
} else {
$s .= $answer;
}
} elseif ($answerType == MATCHING) {
// matching type, showing suggestions and answers
// TODO: replace $answerId by $numAnswer

@ -82,6 +82,7 @@ $choice = empty($choice) ? isset($_REQUEST['choice2']) ? $_REQUEST['choice2'] :
//From submit modal
$current_question = isset($_REQUEST['num']) ? intval($_REQUEST['num']) : null;
$currentAnswer = isset($_REQUEST['num_answer']) ? intval($_REQUEST['num_answer']) : null;
//Error message
$error = '';
@ -415,7 +416,7 @@ if ($formSent && isset($_POST)) {
if (isset($exe_id)) {
//Manage the question and answer attempts
if ($debug) { error_log('8.3. manage_answer exe_id: '.$exe_id.' - $questionId: '.$questionId.' Choice'.print_r($choice,1)); }
$objExercise->manage_answer(
$objExercise->manage_answer(
$exe_id,
$questionId,
$choice,
@ -424,7 +425,8 @@ if ($formSent && isset($_POST)) {
true,
false,
false,
$objExercise->propagate_neg
$objExercise->propagate_neg,
array()
);
}
//END of saving and qualifying
@ -442,7 +444,6 @@ if ($formSent && isset($_POST)) {
Session::write('exerciseResultCoordinates',$exerciseResultCoordinates);
// if all questions on one page OR if it is the last question (only for an exercise with one question per page)
if ($objExercise->type == ALL_ON_ONE_PAGE || $current_question >= $question_count) {
if (api_is_allowed_to_session_edit()) {
// goes to the script that will show the result of the exercise
@ -973,6 +974,7 @@ if (!empty($error)) {
<input type="hidden" name="formSent" value="1" />
<input type="hidden" name="exerciseId" value="'.$exerciseId . '" />
<input type="hidden" name="num" value="'.$current_question.'" id="num_current_id" />
<input type="hidden" name="num_answer" value="'.$currentAnswer.'" id="num_current_answer_id" />
<input type="hidden" name="exe_id" value="'.$exe_id . '" />
<input type="hidden" name="origin" value="'.$origin . '" />
<input type="hidden" name="learnpath_id" value="'.$learnpath_id . '" />

@ -17,6 +17,7 @@ define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
define('ORAL_EXPRESSION', 13);
define('GLOBAL_MULTIPLE_ANSWER', 14);
define('MEDIA_QUESTION', 15);
define('CALCULATED_ANSWER', 16);
//Some alias used in the QTI exports
define('MCUA', 1);
@ -68,6 +69,7 @@ abstract class Question
MULTIPLE_ANSWER_TRUE_FALSE => array('multiple_answer_true_false.class.php', 'MultipleAnswerTrueFalse'),
MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE => array('multiple_answer_combination_true_false.class.php', 'MultipleAnswerCombinationTrueFalse'),
GLOBAL_MULTIPLE_ANSWER => array('global_multiple_answer.class.php' , 'GlobalMultipleAnswer'),
CALCULATED_ANSWER => array('calculated_answer.class.php' , 'CalculatedAnswer')
//MEDIA_QUESTION => array('media_question.class.php' , 'MediaQuestion')
);

@ -389,7 +389,8 @@ switch ($action) {
false,
true,
false,
$objExercise->selectPropagateNeg()
$objExercise->selectPropagateNeg(),
array()
);
// Removing old score.
@ -422,8 +423,7 @@ switch ($action) {
false,
false,
$objExercise->selectPropagateNeg(),
$hotspot_delineation_result,
true
$hotspot_delineation_result
);
// Adding the new score.

@ -0,0 +1,390 @@
<?php
/*
================================================================================
EvalMath - PHP Class to safely evaluate math expressions
Copyright (C) 2005 Miles Kaufmann <http://www.twmagic.com/>
================================================================================
NAME
EvalMath - safely evaluate math expressions
SYNOPSIS
<?
include('evalmath.class.php');
$m = new EvalMath;
// basic evaluation:
$result = $m->evaluate('2+2');
// supports: order of operation; parentheses; negation; built-in functions
$result = $m->evaluate('-8(5/2)^2*(1-sqrt(4))-8');
// create your own variables
$m->evaluate('a = e^(ln(pi))');
// or functions
$m->evaluate('f(x,y) = x^2 + y^2 - 2x*y + 1');
// and then use them
$result = $m->evaluate('3*f(42,a)');
?>
DESCRIPTION
Use the EvalMath class when you want to evaluate mathematical expressions
from untrusted sources. You can define your own variables and functions,
which are stored in the object. Try it, it's fun!
METHODS
$m->evalute($expr)
Evaluates the expression and returns the result. If an error occurs,
prints a warning and returns false. If $expr is a function assignment,
returns true on success.
$m->e($expr)
A synonym for $m->evaluate().
$m->vars()
Returns an associative array of all user-defined variables and values.
$m->funcs()
Returns an array of all user-defined functions.
PARAMETERS
$m->suppress_errors
Set to true to turn off warnings when evaluating expressions
$m->last_error
If the last evaluation failed, contains a string describing the error.
(Useful when suppress_errors is on).
AUTHOR INFORMATION
Copyright 2005, Miles Kaufmann.
LICENSE
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1 Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
class EvalMath {
var $suppress_errors = false;
var $last_error = null;
var $v = array('e'=>2.71,'pi'=>3.14); // variables (and constants)
var $f = array(); // user-defined functions
var $vb = array('e', 'pi'); // constants
var $fb = array( // built-in functions
'sin','sinh','arcsin','asin','arcsinh','asinh',
'cos','cosh','arccos','acos','arccosh','acosh',
'tan','tanh','arctan','atan','arctanh','atanh',
'sqrt','abs','ln','log');
function EvalMath() {
// make the variables a little more accurate
$this->v['pi'] = pi();
$this->v['e'] = exp(1);
}
function e($expr) {
return $this->evaluate($expr);
}
function evaluate($expr) {
$this->last_error = null;
$expr = trim($expr);
if (substr($expr, -1, 1) == ';') $expr = substr($expr, 0, strlen($expr)-1); // strip semicolons at the end
//===============
// is it a variable assignment?
if (preg_match('/^\s*([a-z]\w*)\s*=\s*(.+)$/', $expr, $matches)) {
if (in_array($matches[1], $this->vb)) { // make sure we're not assigning to a constant
return $this->trigger("cannot assign to constant '$matches[1]'");
}
if (($tmp = $this->pfx($this->nfx($matches[2]))) === false) return false; // get the result and make sure it's good
$this->v[$matches[1]] = $tmp; // if so, stick it in the variable array
return $this->v[$matches[1]]; // and return the resulting value
//===============
// is it a function assignment?
} elseif (preg_match('/^\s*([a-z]\w*)\s*\(\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
$fnn = $matches[1]; // get the function name
if (in_array($matches[1], $this->fb)) { // make sure it isn't built in
return $this->trigger("cannot redefine built-in function '$matches[1]()'");
}
$args = explode(",", preg_replace("/\s+/", "", $matches[2])); // get the arguments
if (($stack = $this->nfx($matches[3])) === false) return false; // see if it can be converted to postfix
for ($i = 0; $i<count($stack); $i++) { // freeze the state of the non-argument variables
$token = $stack[$i];
if (preg_match('/^[a-z]\w*$/', $token) and !in_array($token, $args)) {
if (array_key_exists($token, $this->v)) {
$stack[$i] = $this->v[$token];
} else {
return $this->trigger("undefined variable '$token' in function definition");
}
}
}
$this->f[$fnn] = array('args'=>$args, 'func'=>$stack);
return true;
//===============
} else {
return $this->pfx($this->nfx($expr)); // straight up evaluation, woo
}
}
function vars() {
$output = $this->v;
unset($output['pi']);
unset($output['e']);
return $output;
}
function funcs() {
$output = array();
foreach ($this->f as $fnn=>$dat)
$output[] = $fnn . '(' . implode(',', $dat['args']) . ')';
return $output;
}
//===================== HERE BE INTERNAL METHODS ====================\\
// Convert infix to postfix notation
function nfx($expr) {
$index = 0;
$stack = new EvalMathStack;
$output = array(); // postfix form of expression, to be passed to pfx()
$expr = trim(strtolower($expr));
$ops = array('+', '-', '*', '/', '^', '_');
$ops_r = array('+'=>0,'-'=>0,'*'=>0,'/'=>0,'^'=>1); // right-associative operator?
$ops_p = array('+'=>0,'-'=>0,'*'=>1,'/'=>1,'_'=>1,'^'=>2); // operator precedence
$expecting_op = false; // we use this in syntax-checking the expression
// and determining when a - is a negation
if (preg_match("/[^\w\s+*^\/()\.,-]/", $expr, $matches)) { // make sure the characters are all good
return $this->trigger("illegal character '{$matches[0]}'");
}
while(1) { // 1 Infinite Loop ;)
$op = substr($expr, $index, 1); // get the first character at the current index
// find out if we're currently at the beginning of a number/variable/function/parenthesis/operand
$ex = preg_match('/^([a-z]\w*\(?|\d+(?:\.\d*)?|\.\d+|\()/', substr($expr, $index), $match);
//===============
if ($op == '-' and !$expecting_op) { // is it a negation instead of a minus?
$stack->push('_'); // put a negation on the stack
$index++;
} elseif ($op == '_') { // we have to explicitly deny this, because it's legal on the stack
return $this->trigger("illegal character '_'"); // but not in the input expression
//===============
} elseif ((in_array($op, $ops) or $ex) and $expecting_op) { // are we putting an operator on the stack?
if ($ex) { // are we expecting an operator but have a number/variable/function/opening parethesis?
$op = '*'; $index--; // it's an implicit multiplication
}
// heart of the algorithm:
while($stack->count > 0 and ($o2 = $stack->last()) and in_array($o2, $ops) and ($ops_r[$op] ? $ops_p[$op] < $ops_p[$o2] : $ops_p[$op] <= $ops_p[$o2])) {
$output[] = $stack->pop(); // pop stuff off the stack into the output
}
// many thanks: http://en.wikipedia.org/wiki/Reverse_Polish_notation#The_algorithm_in_detail
$stack->push($op); // finally put OUR operator onto the stack
$index++;
$expecting_op = false;
//===============
} elseif ($op == ')' and $expecting_op) { // ready to close a parenthesis?
while (($o2 = $stack->pop()) != '(') { // pop off the stack back to the last (
if (is_null($o2)) return $this->trigger("unexpected ')'");
else $output[] = $o2;
}
if (preg_match("/^([a-z]\w*)\($/", $stack->last(2), $matches)) { // did we just close a function?
$fnn = $matches[1]; // get the function name
$arg_count = $stack->pop(); // see how many arguments there were (cleverly stored on the stack, thank you)
$output[] = $stack->pop(); // pop the function and push onto the output
if (in_array($fnn, $this->fb)) { // check the argument count
if($arg_count > 1)
return $this->trigger("too many arguments ($arg_count given, 1 expected)");
} elseif (array_key_exists($fnn, $this->f)) {
if ($arg_count != count($this->f[$fnn]['args']))
return $this->trigger("wrong number of arguments ($arg_count given, " . count($this->f[$fnn]['args']) . " expected)");
} else { // did we somehow push a non-function on the stack? this should never happen
return $this->trigger("internal error");
}
}
$index++;
//===============
} elseif ($op == ',' and $expecting_op) { // did we just finish a function argument?
while (($o2 = $stack->pop()) != '(') {
if (is_null($o2)) return $this->trigger("unexpected ','"); // oops, never had a (
else $output[] = $o2; // pop the argument expression stuff and push onto the output
}
// make sure there was a function
if (!preg_match("/^([a-z]\w*)\($/", $stack->last(2), $matches))
return $this->trigger("unexpected ','");
$stack->push($stack->pop()+1); // increment the argument count
$stack->push('('); // put the ( back on, we'll need to pop back to it again
$index++;
$expecting_op = false;
//===============
} elseif ($op == '(' and !$expecting_op) {
$stack->push('('); // that was easy
$index++;
$allow_neg = true;
//===============
} elseif ($ex and !$expecting_op) { // do we now have a function/variable/number?
$expecting_op = true;
$val = $match[1];
if (preg_match("/^([a-z]\w*)\($/", $val, $matches)) { // may be func, or variable w/ implicit multiplication against parentheses...
if (in_array($matches[1], $this->fb) or array_key_exists($matches[1], $this->f)) { // it's a func
$stack->push($val);
$stack->push(1);
$stack->push('(');
$expecting_op = false;
} else { // it's a var w/ implicit multiplication
$val = $matches[1];
$output[] = $val;
}
} else { // it's a plain old var or num
$output[] = $val;
}
$index += strlen($val);
//===============
} elseif ($op == ')') { // miscellaneous error checking
return $this->trigger("unexpected ')'");
} elseif (in_array($op, $ops) and !$expecting_op) {
return $this->trigger("unexpected operator '$op'");
} else { // I don't even want to know what you did to get here
return $this->trigger("an unexpected error occured");
}
if ($index == strlen($expr)) {
if (in_array($op, $ops)) { // did we end with an operator? bad.
return $this->trigger("operator '$op' lacks operand");
} else {
break;
}
}
while (substr($expr, $index, 1) == ' ') { // step the index past whitespace (pretty much turns whitespace
$index++; // into implicit multiplication if no operator is there)
}
}
while (!is_null($op = $stack->pop())) { // pop everything off the stack and push onto output
if ($op == '(') return $this->trigger("expecting ')'"); // if there are (s on the stack, ()s were unbalanced
$output[] = $op;
}
return $output;
}
// evaluate postfix notation
function pfx($tokens, $vars = array()) {
if ($tokens == false) return false;
$stack = new EvalMathStack;
foreach ($tokens as $token) { // nice and easy
// if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
if (in_array($token, array('+', '-', '*', '/', '^'))) {
if (is_null($op2 = $stack->pop())) return $this->trigger("internal error");
if (is_null($op1 = $stack->pop())) return $this->trigger("internal error");
switch ($token) {
case '+':
$stack->push($op1+$op2); break;
case '-':
$stack->push($op1-$op2); break;
case '*':
$stack->push($op1*$op2); break;
case '/':
if ($op2 == 0) return $this->trigger("division by zero");
$stack->push($op1/$op2); break;
case '^':
$stack->push(pow($op1, $op2)); break;
}
// if the token is a unary operator, pop one value off the stack, do the operation, and push it back on
} elseif ($token == "_") {
$stack->push(-1*$stack->pop());
// if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
} elseif (preg_match("/^([a-z]\w*)\($/", $token, $matches)) { // it's a function!
$fnn = $matches[1];
if (in_array($fnn, $this->fb)) { // built-in function:
if (is_null($op1 = $stack->pop())) return $this->trigger("internal error");
$fnn = preg_replace("/^arc/", "a", $fnn); // for the 'arc' trig synonyms
if ($fnn == 'ln') $fnn = 'log';
eval('$stack->push(' . $fnn . '($op1));'); // perfectly safe eval()
} elseif (array_key_exists($fnn, $this->f)) { // user function
// get args
$args = array();
for ($i = count($this->f[$fnn]['args'])-1; $i >= 0; $i--) {
if (is_null($args[$this->f[$fnn]['args'][$i]] = $stack->pop())) return $this->trigger("internal error");
}
$stack->push($this->pfx($this->f[$fnn]['func'], $args)); // yay... recursion!!!!
}
// if the token is a number or variable, push it on the stack
} else {
if (is_numeric($token)) {
$stack->push($token);
} elseif (array_key_exists($token, $this->v)) {
$stack->push($this->v[$token]);
} elseif (array_key_exists($token, $vars)) {
$stack->push($vars[$token]);
} else {
return $this->trigger("undefined variable '$token'");
}
}
}
// when we're out of tokens, the stack should have a single element, the final result
if ($stack->count != 1) return $this->trigger("internal error");
return $stack->pop();
}
// trigger an error, but nicely, if need be
function trigger($msg) {
$this->last_error = $msg;
if (!$this->suppress_errors) trigger_error($msg, E_USER_WARNING);
return false;
}
}
// for internal use
class EvalMathStack {
var $stack = array();
var $count = 0;
function push($val) {
$this->stack[$this->count] = $val;
$this->count++;
}
function pop() {
if ($this->count > 0) {
$this->count--;
return $this->stack[$this->count];
}
return null;
}
function last($n=1) {
if (isset($this->stack[$this->count-$n])) {
return $this->stack[$this->count-$n];
}
return;
}
}

@ -50,6 +50,39 @@ class ExerciseShowFunctions
}
}
/**
* Shows the answer to a calculated question, as HTML
* @param string Answer text
* @param int Exercise ID
* @param int Question ID
* @return void
*/
static function display_calculated_answer($feedback_type, $answer, $id, $questionId)
{
if (empty($id)) {
echo '<tr><td>'. (Security::remove_XSS($answer)).'</td></tr>';
} else {
?>
<tr>
<td>
<?php
echo (Security::remove_XSS($answer));
?>
</td>
<?php
if (!api_is_allowed_to_edit(null,true) && $feedback_type != EXERCISE_FEEDBACK_TYPE_EXAM) { ?>
<td>
<?php
$comm = get_comments($id,$questionId);
?>
</td>
<?php } ?>
</tr>
<?php
}
}
/**
* Shows the answer to a free-answer question, as HTML
* @param string Answer text

@ -2,6 +2,23 @@
/*
for more information: see languages.txt in the lang folder.
*/
$UserNameHasDash = "The username cannot contain the '-' character";
$IfYouWantOnlyIntegerValuesWriteBothLimitsWithoutDecimals = "If you want only integer values write both limits without decimals";
$GiveAnswerVariations = "Please, write how many question variations you want";
$AnswerVariations = "Question variations";
$GiveFormula = "Please, write the formula";
$Formula = "Formula";
$FormulaExample = "Formula sample";
$VariableRanges = "Variable ranges";
$ExampleValue = "Range value";
$CalculatedAnswer = "Calculated question";
$UserIsCurrentlySubscribed = "The user is currently subscribed";
$OnlyBestAttempts = "Only best attempts";
$IncludeAllUsers = "Include all users";
$HostingWarningReached = "Hosting warning reached";
$SessionName = "Session name";
$MobilePhoneNumberWrong = "Mobile phone number is incomplete or contains not valid characters";
$CountryDialCode = "Include the country dial code";
$FieldTypeMobilePhoneNumber = "Mobile phone number";
$CheckUniqueEmail = "Check unique email";
$EmailUsedTwice = "This email is not available";
@ -1242,13 +1259,13 @@ $YouMustAcceptLicence = "You must accept the licence";
$SelectOne = "Select one";
$ContactInformationHasBeenSent = "Contact information has been sent";
$UserInactivedSinceX = "User inactive since %s";
$ContactInformationDescription = "Dear user,<br />
<br />You are about to start using one of the best open-source e-learning platform on the market. Like many other open-source project, this project is backed up by a large community of students, teachers, developers and content creators who would like to promote the project better.<br />
<br />
By knowing a little bit more about you, one of our most important users, who will manage this e-learning system, we will be able to let people know that our software is used and let you know when we organize events that might be relevant to you.<br />
<br />
By filling this form, you accept that the Chamilo association or its members might send you information by e-mail about important events or updates in the Chamilo software or community. This will help the community grow as an organized entity where information flow, with a permanent respect of your time and your privacy.<br />
<br />
$ContactInformationDescription = "Dear user,<br />
<br />You are about to start using one of the best open-source e-learning platform on the market. Like many other open-source project, this project is backed up by a large community of students, teachers, developers and content creators who would like to promote the project better.<br />
<br />
By knowing a little bit more about you, one of our most important users, who will manage this e-learning system, we will be able to let people know that our software is used and let you know when we organize events that might be relevant to you.<br />
<br />
By filling this form, you accept that the Chamilo association or its members might send you information by e-mail about important events or updates in the Chamilo software or community. This will help the community grow as an organized entity where information flow, with a permanent respect of your time and your privacy.<br />
<br />
Please note that you are <b>not required</b> to fill this form. If you want to remain anonymous, we will loose the opportunity to offer you all the privileges of being a registered portal administrator, but we will respect your decision. Simply leave this form empty and click \"Next\".<br /><br />";
$CompanyActivity = "Your company's activity";
$DateUnLock = "Unlock date";
@ -1456,7 +1473,7 @@ $SaveForNow = "Save and continue later";
$NoQuicktime = "Your browser does not have the QuickTime plugin installed. You can still use the platform, but to run a larger number of media file types, we suggest you might want to install it.";
$NoJavaSun = "Your browser doesn't seem to have the Sun Java plugin installed. You can still use the platform, but you will lose a few of its capabilities.";
$NoJava = "Your browser does not support Java";
$JavaSun24 = "Your browser has a Java version not supported by this tool.
$JavaSun24 = "Your browser has a Java version not supported by this tool.
To use it you have to install a Java Sun version higher than 24";
$NoMessageAnywere = "If you do not want to see this message again during this session, click here";
$Attempts = "Attempts";
@ -1621,7 +1638,4 @@ $DataTableSearch = "Search";
$HideColumn = "Hide column";
$DisplayColumn = "Show column";
$LegalAgreementAccepted = "Legal agreement accepted";
$FieldTypeMobilePhoneNumber = "Mobile phone";
$CountryDialCode = "Include the country dial code";
$MobilePhoneNumberWrong = "Mobile phone number is incomplete or contains not valid characters";
?>

@ -2,10 +2,40 @@
/*
for more information: see languages.txt in the lang folder.
*/
$UserNameHasDash = "El nombre de usuario no puede contener el caracter '-'";
$IfYouWantOnlyIntegerValuesWriteBothLimitsWithoutDecimals = "Si desea sólo números enteros escriba ambos límites sin decimales";
$GiveAnswerVariations = "Por favor, escriba cuántos problemas desea generar";
$AnswerVariations = "Problemas a generar";
$GiveFormula = "Por favor, escriba la fórmula";
$Formula = "Fórmula";
$FormulaExample = "Ejemplo de fórmula";
$VariableRanges = "Rangos de las variables";
$ExampleValue = "Valor del rango";
$CalculatedAnswer = "Pregunta calculada";
$UserIsCurrentlySubscribed = "El usuario está actualmente suscrito";
$OnlyBestAttempts = "Solo los mejores intentos";
$IncludeAllUsers = "Incluir todos los usuarios";
$HostingWarningReached = "Limite de alojamiento alcanzado";
$SessionName = "Nombre de la sesión";
$MobilePhoneNumberWrong = "El número de móvil que ha escrito está incompleto o contiene caracteres no válidos";
$CountryDialCode = "Incluya el prefijo de llamada del país";
$FieldTypeMobilePhoneNumber = "Número de móvil";
$CheckUniqueEmail = "Verificar que los correos sean únicos.";
$EmailUsedTwice = "El correo electrónico ya esta registrado en el sistema.";
$EmailUsedTwice = "Este correo electrónico ya está registrado en el sistema.";
$TotalPostsInAllForums = "Total de posts en todos los foros";
$AddMeAsCoach = "Agregarme como tutor";
$AddMeAsTeacherInCourses = "Agregarme como profesor en los cursos importados.";
$ExerciseProgressInfo = "Progreso de los ejercicios llevados por el alumno";
$CourseTimeInfo = "Tiempo pasado en el curso";
$ExerciseAverageInfo = "Media del mejor resultado para cada intento de ejercicio.";
$ExtraDurationForUser = "Días de acceso adicionales para este usuario.";
$UserXSessionY = "Usuario: %s - Sesión: %s";
$DurationIsSameAsDefault = "La duración de la sesión es la misma que el valor por defecto. Ignorando.";
$FirstAccessWasXSessionDurationYEndDateWasZ = "El primer acceso de este usuario a la sesión fue el %s. Con una duración de %s días, el acceso a esta sesión expiró el %s.";
$FirstAccessWasXSessionDurationYEndDateInZDays = "El primer acceso de este usuario a esta sesión fue el %s. Con una duración de %s días, la fecha de fin está configurada dentro de %s días.";
$UserNeverAccessedSessionDefaultDurationIsX = "Este usuario nunca ha accedido a esta sesión antes. La duración está configurada a %s días (desde la fecha de primer acceso).";
$SessionDurationEdit = "Editar duración de sesión";
$EditUserSessionDuration = "Editar la duración de la sesión del usuario";
$SessionDurationXDaysLeft = "Esta sesión tiene una duración máxima. Solo quedan %s días.";
$NextTopic = "Próximo tema";
$CurrentTopic = "Tema actual";
@ -1052,7 +1082,7 @@ $YouCanAccessTheExercise = "Ir a la prueba";
$YouHaveBeenRegisteredToCourseX = "Ha sido inscrito en el curso %s";
$DashboardPluginsHaveBeenUpdatedSucesslly = "Los plugins del panel de control han sido actualizados correctamente";
$LoginEnter = "Entrar";
$AttendanceSheetDescription = "Las listas de asistencia permiten registrar las faltas de asistencia de los estudiantes. En caso de ausencia de un estudiante, el profesor deberá registrarlo manualmente en la casilla correspondiente.
$AttendanceSheetDescription = "Las listas de asistencia permiten registrar las faltas de asistencia de los estudiantes. En caso de ausencia de un estudiante, el profesor deberá registrarlo manualmente en la casilla correspondiente.
Es posible crear más de una lista de asistencia por cada curso; así por ejemplo, podrá registrar separadamente la asistencia a las clases teóricas y prácticas.";
$ThereAreNoRegisteredLearnersInsidetheCourse = "No hay estudiantes inscritos en este curso";
$GoToAttendanceCalendarList = "Ir al calendario de asistencia";
@ -1230,14 +1260,14 @@ $YouMustAcceptLicence = "Debe aceptar la licencia para poder usar este software"
$SelectOne = "Seleccione uno";
$ContactInformationHasBeenSent = "Información de contacto enviada";
$UserInactivedSinceX = "Usuario inactivo desde %s";
$ContactInformationDescription = "Estimado usuario,
está a punto de instalar una de las mejores plataformas e-learning de código abierto que existen en el mercado. Al igual de muchos otros proyectos de código abierto, Chamilo está respaldado por una amplia comunidad de profesores, estudiantes, desarrolladores y creadores de contenido.
Si sabemos algo más de quien va a gestionar este sistema e-learning, podremos dar a conocer a otros que nuestro software lo utiliza y a usted podremos informarle sobre eventos que pueden ser de su interés.
Cumplimentar este formulario, implica la aceptación de que la asociación Chamilo o sus miembros puedan enviarle información por correo electrónico sobre eventos importantes o actualizaciones en el software Chamilo. Esto ayudará a crecer a la comunidad como una entidad organizada, donde el flujo de información, se haga con respeto permanente a su tiempo y su privacidad.
$ContactInformationDescription = "Estimado usuario,
está a punto de instalar una de las mejores plataformas e-learning de código abierto que existen en el mercado. Al igual de muchos otros proyectos de código abierto, Chamilo está respaldado por una amplia comunidad de profesores, estudiantes, desarrolladores y creadores de contenido.
Si sabemos algo más de quien va a gestionar este sistema e-learning, podremos dar a conocer a otros que nuestro software lo utiliza y a usted podremos informarle sobre eventos que pueden ser de su interés.
Cumplimentar este formulario, implica la aceptación de que la asociación Chamilo o sus miembros puedan enviarle información por correo electrónico sobre eventos importantes o actualizaciones en el software Chamilo. Esto ayudará a crecer a la comunidad como una entidad organizada, donde el flujo de información, se haga con respeto permanente a su tiempo y su privacidad.
De cualquier forma, tenga en cuenta que no tiene la obligación de rellenar este formulario. Si desea permanecer en el anonimato, perderemos la oportunidad de ofrecerle todos los privilegios de ser un administrador de portal registrado, pero respetaremos su decisión. Basta con dejar vacío este formulario y hacer clic en \"Siguiente\" para seguir instalando Chamilo.";
$CompanyActivity = "Sector";
$DateUnLock = "Desbloquear fecha";
@ -1437,11 +1467,11 @@ $CertificateOnlineLink = "Vínculo al certificado en línea";
$NewExercises = "Nuevo ejercicio";
$MyAverage = "Mi promedio";
$AllAttempts = "Todos los intentos";
$NoCookies = "Las cookies no están activadas en su navegador.
$NoCookies = "Las cookies no están activadas en su navegador.
Chamilo utiliza \"cookies\" para almacenar sus datos de conexión, por lo que no le será posible entrar si las cookies no están habilitadas. Por favor, cambie la configuración de su navegador y recargue esta página.";
$NoJavascript = "Su navegador no tiene activado JavaScript.
$NoJavascript = "Su navegador no tiene activado JavaScript.
Chamilo se sirve de JavaScript para proporcionar un interfaz más dinámico. Es probable que muchas prestaciones sigan funcionando pero otras no lo harán, especialmente las relacionadas con la usabilidad. Le recomendamos que cambie la configuración de su navegador y recargue esta página.";
$NoFlash = "Su navegador no tiene activado el soporte de Flash.
$NoFlash = "Su navegador no tiene activado el soporte de Flash.
Chamilo sólo se apoya en Flash para algunas de sus funciones por lo que su ausencia no le impedirá continuar. Pero si quiere beneficiarse del conjunto de las herramientas de Chamilo, le recomendamos que instale-active el plugin de Flash y reinicialice su navegador.";
$Attempt = "Intento";
$SaveForNow = "Guardar y continuar más tarde";
@ -1522,7 +1552,7 @@ $LoginX = "Nombre de usuario: %s";
$ChatConnected = "Chat (Conectado)";
$ChatDisconnected = "Chat (Desconectado)";
$ThingsToDo = "Primeras actividades sugeridas";
$WamiFlashDialog = "Se mostrará un cuadro de diálogo en el que se le pedirá permiso para poder acceder al micrófono, responda afirmativamente y cierre el cuadro de diálogo (si no desea que vuelva a aparecer, antes de cerrar marque la opción
$WamiFlashDialog = "Se mostrará un cuadro de diálogo en el que se le pedirá permiso para poder acceder al micrófono, responda afirmativamente y cierre el cuadro de diálogo (si no desea que vuelva a aparecer, antes de cerrar marque la opción
recordar)";
$WamiStartRecorder = "Inicie la grabación pulsando el micrófono y deténgala pulsándolo de nuevo. Cada vez que haga esto se generará un archivo.";
$InputNameHere = "Escriba el nombre aquí";
@ -1613,7 +1643,4 @@ $DataTableSearch = "Buscar";
$HideColumn = "Ocultar columna";
$DisplayColumn = "Mostrar columna";
$LegalAgreementAccepted = "Condiciones legales aceptadas";
$FieldTypeMobilePhoneNumber = "Número de móvil";
$CountryDialCode = "Incluya el prefijo de llamada del país";
$MobilePhoneNumberWrong = "El número de móvil que ha escrito está incompleto o contiene caracteres no válidos.";
?>
Loading…
Cancel
Save