/**
  *
  *
  * @return bool
  * @access public
  */
 public function do_test()
 {
     if ('' == trim($this->sanskey)) {
         $this->aterror = stack_string('TEST_FAILED', array('errors' => stack_string("AT_EmptySA")));
         $this->atfeedback = stack_string('TEST_FAILED', array('errors' => stack_string("AT_EmptySA")));
         $this->atansnote = $this->casfunction . 'TEST_FAILED:Empty SA.';
         $this->atmark = 0;
         $this->atvalid = false;
         return null;
     }
     if ('' == trim($this->tanskey)) {
         $this->aterror = stack_string('TEST_FAILED', array('errors' => stack_string("AT_EmptyTA")));
         $this->atfeedback = stack_string('TEST_FAILED', array('errors' => stack_string("AT_EmptyTA")));
         $this->atansnote = $this->casfunction . 'TEST_FAILED:Empty TA.';
         $this->atmark = 0;
         $this->atvalid = false;
         return null;
     }
     if ($this->processcasoptions) {
         if (null == $this->atoption or '' == $this->atoption) {
             $this->aterror = 'TEST_FAILED';
             $this->atfeedback = stack_string('TEST_FAILED', array('errors' => stack_string("AT_MissingOptions")));
             $this->atansnote = 'STACKERROR_OPTION.';
             $this->atmark = 0;
             $this->atvalid = false;
             return null;
         } else {
             // Validate with teacher privileges, strict syntax & no automatically adding stars.
             $ct = new stack_cas_casstring($this->atoption);
             if (!$ct->get_valid('t', true, 1)) {
                 $this->aterror = 'TEST_FAILED';
                 $this->atfeedback = stack_string('TEST_FAILED', array('errors' => ''));
                 $this->atfeedback .= stack_string('AT_InvalidOptions', array('errors' => $ct->get_errors()));
                 $this->atansnote = 'STACKERROR_OPTION.';
                 $this->atmark = 0;
                 $this->atvalid = false;
                 return null;
             }
         }
         $atopt = $this->atoption;
         $ta = "[{$this->tanskey},{$atopt}]";
     } else {
         $ta = $this->tanskey;
     }
     // Sort out options.
     if (null === $this->options) {
         $this->options = new stack_options();
     }
     if (!(null === $this->simp)) {
         $this->options->set_option('simplify', $this->simp);
     }
     $cascommands = array();
     $cascommands[] = "STACKSA:{$this->sanskey}";
     $cascommands[] = "STACKTA:{$ta}";
     $cascommands[] = "result:StackReturn({$this->casfunction}(STACKSA,STACKTA))";
     $cts = array();
     foreach ($cascommands as $com) {
         $cs = new stack_cas_casstring($com);
         $cs->get_valid('t', true, 0);
         $cts[] = $cs;
     }
     $session = new stack_cas_session($cts, $this->options, 0);
     $session->instantiate();
     $this->debuginfo = $session->get_debuginfo();
     if ('' != $session->get_errors_key('STACKSA')) {
         $this->aterror = 'TEST_FAILED';
         $this->atfeedback = stack_string('TEST_FAILED', array('errors' => $session->get_errors_key('STACKSA')));
         $this->atansnote = $this->casfunction . '_STACKERROR_SAns.';
         $this->atmark = 0;
         $this->atvalid = false;
         return null;
     }
     if ('' != $session->get_errors_key('STACKTA')) {
         $this->aterror = 'TEST_FAILED';
         $this->atfeedback = stack_string('TEST_FAILED', array('errors' => $session->get_errors_key('STACKTA')));
         $this->atansnote = $this->casfunction . '_STACKERROR_TAns.';
         $this->atmark = 0;
         $this->atvalid = false;
         return null;
     }
     $sessionvars = $session->get_session();
     $result = $sessionvars[2];
     if ('' != $result->get_errors()) {
         $this->aterror = 'TEST_FAILED';
         if ('' != trim($result->get_feedback())) {
             $this->atfeedback = $result->get_feedback();
         } else {
             $this->atfeedback = stack_string('TEST_FAILED', array('errors' => $result->get_errors()));
         }
         $this->atansnote = trim($result->get_answernote());
         $this->atmark = 0;
         $this->atvalid = false;
         return null;
     }
     $this->atansnote = trim($result->get_answernote());
     // Convert the Maxima string 'true' to PHP true.
     if ('true' == $result->get_value()) {
         $this->atmark = 1;
     } else {
         $this->atmark = 0;
     }
     $this->atfeedback = $result->get_feedback();
     $this->atvalid = $result->get_valid();
     if ($this->atmark) {
         return true;
     } else {
         return false;
     }
 }
 /**
  * Traverse this node, updating the results array that is used by
  * {@link stack_potentialresponse_tree::evaluate_response()}.
  *
  * @param stack_potentialresponse_tree_state $results to be updated.
  * @param int $key the index of this node.
  * @param stack_cas_session $cascontext the CAS context that holds all the relevant variables.
  * @param stack_options $options
  * @return array with two elements, the updated $results and the index of the next node.
  */
 public function traverse($results, $key, $cascontext, $options)
 {
     $errorfree = true;
     if ($cascontext->get_errors_key('PRSANS' . $key)) {
         $results->_errors .= $cascontext->get_errors_key('PRSANS' . $key);
         $results->add_feedback(' ' . stack_string('prtruntimeerror', array('node' => 'PRSANS' . ($key + 1), 'error' => $cascontext->get_errors_key('PRSANS' . $key))));
         $errorfree = false;
     }
     if ($cascontext->get_errors_key('PRTANS' . $key)) {
         $results->_errors .= $cascontext->get_errors_key('PRTANS' . $key);
         $results->add_feedback(' ' . stack_string('prtruntimeerror', array('node' => 'PRTANS' . ($key + 1), 'error' => $cascontext->get_errors_key('PRTANS' . $key))));
         $errorfree = false;
     }
     if ($cascontext->get_errors_key('PRATOPT' . $key)) {
         $results->_errors .= $cascontext->get_errors_key('PRATOPT' . $key);
         $results->add_feedback(' ' . stack_string('prtruntimeerror', array('node' => 'PRATOPT' . ($key + 1), 'error' => $cascontext->get_errors_key('PRATOPT' . $key))));
         $errorfree = false;
     }
     if (!$errorfree) {
         return -1;
     }
     $sans = $cascontext->get_value_key('PRSANS' . $key);
     $tans = $cascontext->get_value_key('PRTANS' . $key);
     $atopts = $cascontext->get_value_key('PRATOPT' . $key);
     // If we can't find atopts then they were not processed by the CAS.
     // They might still be some in the potential response which do not
     // need to be processed.
     if (false === $atopts) {
         $atopts = null;
     }
     $nextnode = $this->do_test($sans, $tans, $atopts, $options, $results);
     return $nextnode;
 }
 public function do_test()
 {
     $this->atmark = 1;
     $anotes = array();
     // Note that in casting to an integer we are lucky here.
     // Non-integer strings get cast to zero, which is invalid anyway....
     $atestops = (int) $this->atoption;
     if (!is_int($atestops) or $atestops <= 0) {
         $this->aterror = 'TEST_FAILED';
         $this->atfeedback = stack_string('TEST_FAILED', array('errors' => ''));
         $this->atfeedback .= stack_string('ATNumDecPlaces_OptNotInt', array('opt' => $this->atoption));
         $this->atansnote = 'ATNumDecPlaces_STACKERROR_Option.';
         $this->atmark = 0;
         $this->atvalid = false;
         return null;
     }
     $commands = array($this->sanskey, $this->tanskey, (string) $this->atoption);
     foreach ($commands as $com) {
         $cs = new stack_cas_casstring($com);
         if (!$cs->get_valid('t', true, 0)) {
             $this->aterror = 'TEST_FAILED';
             $this->atfeedback = stack_string('TEST_FAILED', array('errors' => ''));
             $this->atfeedback .= stack_string('AT_InvalidOptions', array('errors' => $cs->get_errors()));
             $this->atansnote = 'ATNumDecPlaces_STACKERROR_Option.';
             $this->atmark = 0;
             $this->atvalid = false;
             return null;
         }
     }
     // Check that the first expression is a floating point number,
     // with the right number of decimal places.
     $sans = explode('.', $this->sanskey);
     if (2 === count($sans)) {
         if ($atestops != strlen($sans[1])) {
             $this->atfeedback .= stack_string('ATNumDecPlaces_Wrong_DPs');
             $anotes[] = 'ATNumDecPlaces_Wrong_DPs (' . strlen($sans[1]) . ' <> ' . $atestops . ')';
             $this->atmark = 0;
         } else {
             $anotes[] = 'ATNumDecPlaces_Correct';
         }
     } else {
         // No '.' found.
         $this->atfeedback .= stack_string('ATNumDecPlaces_NoDP');
         $anotes[] = 'ATNumDecPlaces_NoDP';
         $this->atmark = 0;
     }
     // Check that the two numbers evaluate to the same value.
     $cascommands = array();
     $cascommands[] = "caschat2:ev({$this->atoption},simp)";
     $cascommands[] = "caschat0:ev(float(round(10^caschat2*{$this->sanskey})/10^caschat2),simp)";
     $cascommands[] = "caschat1:ev(float(round(10^caschat2*{$this->tanskey})/10^caschat2),simp)";
     $cascommands[] = "caschat3:ev(second(ATAlgEquiv(caschat0,caschat1)),simp)";
     $cts = array();
     foreach ($cascommands as $com) {
         $cs = new stack_cas_casstring($com);
         $cs->get_valid('t', true, 0);
         $cts[] = $cs;
     }
     $session = new stack_cas_session($cts, null, 0);
     $session->instantiate();
     if ('' != $session->get_errors_key('caschat0')) {
         $this->aterror = 'TEST_FAILED';
         $this->atfeedback = stack_string('TEST_FAILED', array('errors' => $session->get_errors_key('caschat0')));
         $anotes[] = 'ATNumDecPlaces_STACKERROR_SAns';
         $this->atansnote = implode('. ', $anotes) . '.';
         $this->atmark = 0;
         $this->atvalid = false;
         return null;
     }
     if ('' != $session->get_errors_key('caschat1')) {
         $this->aterror = 'TEST_FAILED';
         $this->atfeedback = stack_string('TEST_FAILED', array('errors' => $session->get_errors_key('caschat1')));
         $anotes[] = 'ATNumDecPlaces_STACKERROR_TAns';
         $this->atansnote = implode('. ', $anotes) . '.';
         $this->atmark = 0;
         $this->atvalid = false;
         return null;
     }
     if ('' != $session->get_errors_key('caschat2')) {
         $this->aterror = 'TEST_FAILED';
         $this->atfeedback = stack_string('TEST_FAILED', array('errors' => ''));
         $this->atfeedback .= stack_string('AT_InvalidOptions', array('errors' => $session->get_errors_key('caschat2')));
         $anotes[] = 'ATNumDecPlaces_STACKERROR_Options.';
         $this->atansnote = implode('. ', $anotes) . '.';
         $this->atmark = 0;
         $this->atvalid = false;
         return null;
     }
     if ($session->get_value_key('caschat3') == 'true') {
         // Note, we only want the mark to *stay* at 1.
         $this->atmark *= 1;
         $anotes[] = 'ATNumDecPlaces_Equiv';
     } else {
         $this->atmark = 0;
         $anotes[] = 'ATNumDecPlaces_Not_equiv';
     }
     $this->atansnote = implode('. ', $anotes) . '.';
     if ($this->atmark) {
         return true;
     }
     return false;
 }
 public function test_plot_fail()
 {
     $cs = array('a:0', 'p:plot(a*x/0,[x,-2,2],[y,-2,2])');
     foreach ($cs as $s) {
         $cs = new stack_cas_casstring($s);
         $cs->get_valid('t');
         $s1[] = $cs;
     }
     $at1 = new stack_cas_session($s1, null, 0);
     $at1->instantiate();
     $this->assertEquals('0', $at1->get_value_key('a'));
     $this->assertEquals('Division by zero.', trim($at1->get_errors_key('p')));
     $this->assertFalse(strpos($at1->get_value_key('p'), 'STACK auto-generated plot of 0 with parameters'));
 }