function neighbourhood(AssessmentTestSession $session, array &$average = null)
{
    $start = microtime();
    $neighbourhood = $session->getPossibleJumps();
    if (is_null($average) === false) {
        spentTime($start, microtime(), $average);
    }
}
 /**
  * Gets the section map for navigation between test parts, sections and items.
  *
  * @param AssessmentTestSession $session
  * @return array A navigator map (parts, sections, items so on)
  */
 private static function getNavigatorMap(AssessmentTestSession $session)
 {
     // get jumps
     $jumps = $session->getPossibleJumps();
     // no jumps, notify linear-mode
     if (!$jumps->count()) {
         return NavigationMode::LINEAR;
     }
     $jumpsMapInfo = self::getJumpsMap($session, $jumps);
     $jumpsMap = $jumpsMapInfo['map'];
     $numberItemsFlagged = $jumpsMapInfo['flagged'];
     // the active test-part identifier
     $activePart = $session->getCurrentTestPart()->getIdentifier();
     // the active section identifier
     $activeSection = $session->getCurrentAssessmentSection()->getIdentifier();
     $route = $session->getRoute();
     $activeItem = $session->getCurrentAssessmentItemRef()->getIdentifier();
     if (isset($jumpsMap[$activePart][$activeSection][$activeItem])) {
         $jumpsMap[$activePart][$activeSection][$activeItem]['active'] = true;
     }
     // current position
     $oldPosition = $route->getPosition();
     $route->setPosition($oldPosition);
     // get config for the sequence number option
     $config = common_ext_ExtensionsManager::singleton()->getExtensionById('taoQtiTest')->getConfig('testRunner');
     $forceTitles = !empty($config['test-taker-review-force-title']);
     $uniqueTitle = isset($config['test-taker-review-item-title']) ? $config['test-taker-review-item-title'] : '%d';
     $returnValue = array();
     $testParts = array();
     $testPartIdx = 0;
     $numberItemsPart = 0;
     $numberItemsSection = 0;
     $numberCompletedPart = 0;
     $numberCompletedSection = 0;
     $numberPresentedPart = 0;
     $numberPresentedSection = 0;
     $numberFlaggedPart = 0;
     $numberFlaggedSection = 0;
     $itemPositionPart = 0;
     $itemPositionSection = 0;
     $itemPosition = $session->getRoute()->getPosition();
     foreach ($jumps as $jump) {
         $testPart = $jump->getTarget()->getTestPart();
         $id = $testPart->getIdentifier();
         if (isset($testParts[$id])) {
             continue;
         }
         $sections = array();
         if ($testPart->getNavigationMode() == NavigationMode::NONLINEAR) {
             $firstPositionPart = PHP_INT_MAX;
             foreach ($testPart->getAssessmentSections() as $sectionId => $section) {
                 $completed = 0;
                 $presented = 0;
                 $flagged = 0;
                 $items = array();
                 $firstPositionSection = PHP_INT_MAX;
                 $positionInSection = 0;
                 foreach ($section->getSectionParts() as $itemId => $item) {
                     if (isset($jumpsMap[$id][$sectionId][$itemId])) {
                         $jumpInfo = $jumpsMap[$id][$sectionId][$itemId];
                         $resItem = new \core_kernel_classes_Resource(strstr($item->getHref(), '|', true));
                         if ($jumpInfo['answered']) {
                             ++$completed;
                         }
                         if ($jumpInfo['viewed']) {
                             ++$presented;
                         }
                         if ($jumpInfo['flagged']) {
                             ++$flagged;
                         }
                         if ($forceTitles) {
                             $label = sprintf($uniqueTitle, ++$positionInSection);
                         } else {
                             $label = $resItem->getLabel();
                         }
                         $items[] = array_merge(array('id' => $itemId, 'label' => $label), $jumpInfo);
                         $firstPositionPart = min($firstPositionPart, $jumpInfo['position']);
                         $firstPositionSection = min($firstPositionSection, $jumpInfo['position']);
                     }
                 }
                 $sectionData = array('id' => $sectionId, 'active' => $sectionId === $activeSection, 'label' => $section->getTitle(), 'answered' => $completed, 'items' => $items);
                 $sections[] = $sectionData;
                 if ($sectionData['active']) {
                     $numberItemsSection = count($items);
                     $itemPositionSection = $itemPosition - $firstPositionSection;
                     $numberCompletedSection = $completed;
                     $numberPresentedSection = $presented;
                     $numberFlaggedSection = $flagged;
                 }
                 if ($id === $activePart) {
                     $numberItemsPart += count($items);
                     $numberCompletedPart += $completed;
                     $numberPresentedPart += $presented;
                     $numberFlaggedPart += $flagged;
                 }
             }
             if ($id === $activePart) {
                 $itemPositionPart = $itemPosition - $firstPositionPart;
             }
         }
         $data = array('id' => $id, 'sections' => $sections, 'active' => $id === $activePart, 'label' => __('Part %d', ++$testPartIdx));
         if (empty($sections)) {
             $item = current(current($jumpsMap[$id]));
             $data['position'] = $item['position'];
             $data['itemId'] = key(current($jumpsMap[$id]));
         }
         $returnValue[] = $data;
         $testParts[$id] = false;
     }
     return array('map' => $returnValue, 'numberItemsFlagged' => $numberItemsFlagged, 'numberItemsPart' => $numberItemsPart, 'numberItemsSection' => $numberItemsSection, 'numberCompletedPart' => $numberCompletedPart, 'numberCompletedSection' => $numberCompletedSection, 'numberPresentedPart' => $numberPresentedPart, 'numberPresentedSection' => $numberPresentedSection, 'numberFlaggedPart' => $numberFlaggedPart, 'numberFlaggedSection' => $numberFlaggedSection, 'itemPositionPart' => $itemPositionPart, 'itemPositionSection' => $itemPositionSection);
 }
 /**
  * Build an array where each cell represent a possible Assessment Item a candidate
  * can jump on during a given $session. Each cell is an array with two keys:
  * 
  * * 'identifier': The identifier of the Assessment Item the candidate is allowed to jump on.
  * * 'position': The position in the route of the Assessment Item.
  * 
  * @param AssessmentTestSession $session A given AssessmentTestSession object.
  * @return array
  */
 public static function buildPossibleJumps(AssessmentTestSession $session)
 {
     $jumps = array();
     foreach ($session->getPossibleJumps() as $jumpObject) {
         $jump = array();
         $jump['identifier'] = $jumpObject->getTarget()->getAssessmentItemRef()->getIdentifier();
         $jump['position'] = $jumpObject->getPosition();
         $jumps[] = $jump;
     }
     return $jumps;
 }