function neighbourhood(AssessmentTestSession $session, array &$average = null)
{
    $start = microtime();
    $neighbourhood = $session->getPossibleJumps();
    if (is_null($average) === false) {
        spentTime($start, microtime(), $average);
    }
}
 /**
  * Persist the binary stream $stream which contains the binary equivalent of $assessmentTestSession in
  * the temporary directory of the file system.
  *
  * @param \qtism\runtime\tests\AssessmentTestSession $assessmentTestSession The AssessmentTestSession to be persisted.
  * @param \qtism\common\storage\MemoryStream $stream The MemoryStream to be stored in the temporary directory of the host file system.
  * @throws \RuntimeException If the binary stream cannot be persisted.
  */
 protected function persistStream(AssessmentTestSession $assessmentTestSession, MemoryStream $stream)
 {
     $sessionId = $assessmentTestSession->getSessionId();
     $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . md5($sessionId) . '.bin';
     $written = @file_put_contents($path, $stream->getBinary());
     if ($written === false || $written === 0) {
         $msg = "An error occured while persisting the binary stream at '{$path}'.";
         throw new RuntimeException($msg);
     }
 }
 /**
  * Save session metadata.
  * 
  * @param array $metaData Meta data array to be saved.
  * @param RouteItem $routeItem item for which data will be saved
  * @param string $assessmentSectionId section id for which data will be saved
  * Example:
  * array(
  *   'TEST' => array('TEST_EXIT_CODE' => 'IC'),
  *   'SECTION' => array('SECTION_EXIT_CODE' => 701),
  * )
  */
 public function save(array $metaData, RouteItem $routeItem = null, $assessmentSectionId = null)
 {
     $testUri = $this->session->getTest()->getUri();
     $resultServer = \taoResultServer_models_classes_ResultServerStateFull::singleton();
     foreach ($metaData as $type => $data) {
         foreach ($data as $key => $value) {
             $metaVariable = $this->getVariable($key, $value);
             if (strcasecmp($type, 'ITEM') === 0) {
                 if ($routeItem === null) {
                     $itemRef = $this->session->getCurrentAssessmentItemRef();
                     $occurence = $this->session->getCurrentAssessmentItemRefOccurence();
                 } else {
                     $itemRef = $routeItem->getAssessmentItemRef();
                     $occurence = $routeItem->getOccurence();
                 }
                 $itemUri = $this->getItemUri($itemRef);
                 $sessionId = $this->session->getSessionId();
                 $transmissionId = "{$sessionId}.{$itemRef}.{$occurence}";
                 $resultServer->storeItemVariable($testUri, $itemUri, $metaVariable, $transmissionId);
             } elseif (strcasecmp($type, 'TEST') === 0) {
                 $resultServer->storeTestVariable($testUri, $metaVariable, $this->session->getSessionId());
             } elseif (strcasecmp($type, 'SECTION') === 0) {
                 //suffix section variables with _{SECTION_IDENTIFIER}
                 if ($assessmentSectionId === null) {
                     $assessmentSectionId = $this->session->getCurrentAssessmentSection()->getIdentifier();
                 }
                 $metaVariable->setIdentifier($key . '_' . $assessmentSectionId);
                 $resultServer->storeTestVariable($testUri, $metaVariable, $this->session->getSessionId());
             }
         }
     }
 }
 /**
  * Checks if the current session can be exited
  *
  * @param AssessmentTestSession $session
  * @return bool
  */
 public static function doesAllowExit(AssessmentTestSession $session)
 {
     $categories = $session->getCurrentAssessmentItemRef()->getCategories();
     $config = common_ext_ExtensionsManager::singleton()->getExtensionById('taoQtiTest')->getConfig('testRunner');
     $exitButton = isset($config['exitButton']) && $config['exitButton'];
     return $exitButton && $categories->contains('x-tao-option-exit');
 }
 /**
  * Persist an AssessmentTestSession into binary data.
  *
  * @param \qtism\runtime\tests\AssessmentTestSession $assessmentTestSession
  * @throws \qtism\runtime\storage\common\StorageException
  */
 public function persist(AssessmentTestSession $assessmentTestSession)
 {
     try {
         $stream = new MemoryStream();
         $stream->open();
         $access = $this->createBinaryStreamAccess($stream);
         // -- Deal with intrinsic values of the Test Session.
         $access->writeTinyInt($assessmentTestSession->getState());
         // Write the current position in the route.
         $route = $assessmentTestSession->getRoute();
         $access->writeTinyInt($route->getPosition());
         // persist time reference.
         $timeReference = $assessmentTestSession->getTimeReference();
         if (is_null($timeReference) === true) {
             $access->writeBoolean(false);
         } else {
             $access->writeBoolean(true);
             $access->writeDateTime($timeReference);
         }
         // -- Persist the Route of the AssessmentTestSession and the related item sessions.
         $access->writeTinyInt($route->count());
         $itemSessionStore = $assessmentTestSession->getAssessmentItemSessionStore();
         $pendingResponseStore = $assessmentTestSession->getPendingResponseStore();
         $oldRoutePosition = $route->getPosition();
         foreach ($route as $routeItem) {
             $item = $routeItem->getAssessmentItemRef();
             $occurence = $routeItem->getOccurence();
             // Deal with RouteItem
             $access->writeRouteItem($this->getSeeker(), $routeItem);
             // Deal with ItemSession related to the previously written RouteItem.
             try {
                 $itemSession = $itemSessionStore->getAssessmentItemSession($item, $occurence);
                 $access->writeBoolean(true);
                 $access->writeAssessmentItemSession($this->getSeeker(), $itemSession);
                 // Deal with last occurence update.
                 $access->writeBoolean($assessmentTestSession->isLastOccurenceUpdate($item, $occurence));
                 // Deal with PendingResponses
                 if (($pendingResponses = $pendingResponseStore->getPendingResponses($item, $occurence)) !== false) {
                     $access->writeBoolean(true);
                     $access->writePendingResponses($this->getSeeker(), $pendingResponses);
                 } else {
                     $access->writeBoolean(false);
                 }
             } catch (OutOfBoundsException $e) {
                 $access->writeBoolean(false);
                 // No assessmentItemSession for this route item.
                 continue;
             }
         }
         $route->setPosition($oldRoutePosition);
         // Deal with test session configuration.
         // !!! AutoForward (not in use anymore, fake it).
         $access->writeBoolean(false);
         // Persist the test-level global scope.
         foreach ($assessmentTestSession->getKeys() as $outcomeIdentifier) {
             $outcomeVariable = $assessmentTestSession->getVariable($outcomeIdentifier);
             $access->writeVariableValue($outcomeVariable);
         }
         $durationStore = $assessmentTestSession->getDurationStore();
         $access->writeShort(count($durationStore));
         foreach ($durationStore->getKeys() as $k) {
             $access->writeString($k);
             $access->writeVariableValue($durationStore->getVariable($k));
         }
         $this->persistStream($assessmentTestSession, $stream);
         $stream->close();
     } catch (Exception $e) {
         $sessionId = $assessmentTestSession->getSessionId();
         $msg = "An error occured while persisting AssessmentTestSession with ID '{$sessionId}': " . $e->getMessage();
         throw new StorageException($msg, StorageException::PERSITANCE, $e);
     }
 }
 /**
  * @inheritdoc
  * @param int $state
  */
 public function setState($state)
 {
     $previousState = $this->getState();
     $sessionMemento = $this->getSessionMemento();
     parent::setState($state);
     if ($previousState !== null && $previousState !== $state) {
         $this->triggerStateChanged($sessionMemento);
     }
 }
 /**
  * Extra configuration for newly instantiated AssessmentTestSession objects. This implementation
  * forces test results to be sent at the end of the candidate session, and get the acceptable
  * latency time from the taoQtiTest extension's configuration.
  * 
  * @param AssessmentTestSession $assessmentTestSession
  */
 protected function configureAssessmentTestSession(AssessmentTestSession $assessmentTestSession)
 {
     $assessmentTestSession->setTestResultsSubmission(TestResultsSubmission::END);
 }
 protected function persistStream(AssessmentTestSession $assessmentTestSession, MemoryStream $stream)
 {
     $storageService = tao_models_classes_service_StateStorage::singleton();
     $userUri = common_session_SessionManager::getSession()->getUserUri();
     if (is_null($userUri) === true) {
         $msg = "Could not retrieve current user URI.";
         throw new StorageException($msg, StorageException::RETRIEVAL);
     }
     $data = $this->getLastError() . $stream->getBinary();
     $storageService->set($userUri, $assessmentTestSession->getSessionId(), $data);
 }
 /**
  * @param AssessmentTestSession $session
  * @return \taoDelivery_models_classes_execution_DeliveryExecution
  */
 private function getDeliveryExecution(AssessmentTestSession $session)
 {
     return $this->deliveryExecutionService->getDeliveryExecution($session->getSessionId());
 }
 /**
  * Compute the the number of completed items during a given
  * candidate test $session.
  * 
  * @param AssessmentTestSession $session
  * @return integer
  */
 public static function testCompletion(AssessmentTestSession $session)
 {
     $completed = $session->numberCompleted();
     if ($session->getCurrentNavigationMode() === NavigationMode::LINEAR && $completed > 0) {
         $completed--;
     }
     return $completed;
 }
 /**
  * QTISM endTestSession method overriding.
  * 
  * It consists of including an additional processing when the test ends,
  * in order to send the LtiOutcome 
  * 
  * @see http://www.imsglobal.org/lis/ Outcome Management Service
  * @throws taoQtiTest_helpers_TestSessionException If the session is already ended or if an error occurs whil transmitting/processing the result.
  */
 public function endTestSession()
 {
     parent::endTestSession();
     common_Logger::i('Ending test session.');
     try {
         // Compute the LtiOutcome variable for LTI support.
         $this->setVariable(new OutcomeVariable('LtiOutcome', Cardinality::SINGLE, BaseType::FLOAT, new Float(0.0)));
         $outcomeProcessingEngine = new OutcomeProcessingEngine($this->buildLtiOutcomeProcessing(), $this);
         $outcomeProcessingEngine->process();
         // if numberPresented returned 0, division by 0 -> null.
         $testUri = $this->getTest()->getUri();
         $var = $this->getVariable('LtiOutcome');
         $varIdentifier = $var->getIdentifier();
         common_Logger::t("Submitting test result '{$varIdentifier}' related to test '{$testUri}'.");
         $this->getResultTransmitter()->transmitTestVariable($var, $this->getSessionId(), $testUri);
         $this->unsetVariable('LtiOutcome');
     } catch (ProcessingException $e) {
         $msg = "An error occured while processing the 'LtiOutcome' outcome variable.";
         throw new taoQtiTest_helpers_TestSessionException($msg, taoQtiTest_helpers_TestSessionException::RESULT_SUBMISSION_ERROR, $e);
     } catch (taoQtiCommon_helpers_ResultTransmissionException $e) {
         $msg = "An error occured during test-level outcome results transmission.";
         throw new taoQtiTest_helpers_TestSessionException($msg, taoQtiTest_helpers_TestSessionException::RESULT_SUBMISSION_ERROR, $e);
     }
 }
 /**
  * @param AssessmentTestSession $session
  */
 public function persist(AssessmentTestSession $session)
 {
     $sessionId = $session->getSessionId();
     $storage = $this->cache[$sessionId]['storage'];
     $storage->persist($session);
 }
 /**
  * Persist an AssessmentTestSession into binary data.
  * 
  * The QTI Binary Storage Version that will be used to persist the AssessmentTestSession
  * will be systematically the one defined in QtiBinaryConstants::QTI_BINARY_STORAGE_VERSION. 
  * 
  * @param AssessmentTestSession $assessmentTestSession
  * @throws StorageException
  */
 public function persist(AssessmentTestSession $assessmentTestSession)
 {
     try {
         $stream = new MemoryStream();
         $stream->open();
         $access = $this->createBinaryStreamAccess($stream);
         // write the QTI Binary Storage version in use to persist the test session.
         $access->writeTinyInt(QtiBinaryConstants::QTI_BINARY_STORAGE_VERSION);
         $access->writeTinyInt($assessmentTestSession->getState());
         $route = $assessmentTestSession->getRoute();
         $access->writeTinyInt($route->getPosition());
         // Persist the Route of the AssessmentTestSession and the related item sessions.
         $access->writeTinyInt($route->count());
         $itemSessionStore = $assessmentTestSession->getAssessmentItemSessionStore();
         $pendingResponseStore = $assessmentTestSession->getPendingResponseStore();
         foreach ($route as $routeItem) {
             $item = $routeItem->getAssessmentItemRef();
             $occurence = $routeItem->getOccurence();
             // Deal with RouteItem
             $access->writeRouteItem($this->getSeeker(), $routeItem);
             // Deal with ItemSession related to the previously written RouteItem.
             $itemSession = $itemSessionStore->getAssessmentItemSession($item, $occurence);
             $access->writeAssessmentItemSession($this->getSeeker(), $itemSession);
             // Deal with last occurence update.
             $access->writeBoolean($assessmentTestSession->isLastOccurenceUpdate($item, $occurence));
             // Deal with PendingResponses
             if (($pendingResponses = $pendingResponseStore->getPendingResponses($item, $occurence)) !== false) {
                 $access->writeBoolean(true);
                 $access->writePendingResponses($this->getSeeker(), $pendingResponses);
             } else {
                 $access->writeBoolean(false);
             }
         }
         // Deal with test session configuration.
         // -- AutoForward (not in use anymore, fake it).
         $access->writeBoolean(false);
         // Persist the test-level global scope.
         foreach ($assessmentTestSession->getKeys() as $outcomeIdentifier) {
             $outcomeVariable = $assessmentTestSession->getVariable($outcomeIdentifier);
             $access->writeVariableValue($outcomeVariable);
         }
         $durationStore = $assessmentTestSession->getDurationStore();
         $access->writeShort(count($durationStore));
         foreach ($durationStore->getKeys() as $k) {
             $access->writeString($k);
             $access->writeVariableValue($durationStore->getVariable($k));
         }
         $this->persistStream($assessmentTestSession, $stream);
         $stream->close();
     } catch (Exception $e) {
         $sessionId = $assessmentTestSession->getSessionId();
         $msg = "An error occured while persisting AssessmentTestSession with ID '{$sessionId}'.";
         throw new StorageException($msg, StorageException::PERSITANCE, $e);
     }
 }
 /**
  * Get the array of available categories for the current itemRef
  * 
  * @param \qtism\runtime\tests\AssessmentTestSession $session
  * @return array
  */
 public static function getCategories(AssessmentTestSession $session)
 {
     return $session->getCurrentAssessmentItemRef()->getCategories()->getArrayCopy();
 }