models/classes/runner/time/QtiTimer.php
public function adjust($tags, $duration)
    {
        // check the provided arguments
        if (!is_null($duration) && (!is_numeric($duration) || $duration < 0)) {
            throw new InvalidDataException('adjust() needs a valid duration!');
        }

        // extract the TimePoint identification from the provided item, and find existing range
        $itemTimeLine = $this->timeLine->filter($tags, TimePoint::TARGET_SERVER);
        $range = $itemTimeLine->getPoints();

        // validate the data consistence
        $rangeLength = count($range);
        if (!$rangeLength || ($rangeLength % 2)) {
            throw new InconsistentRangeException('The time range does not seem to be consistent, the range is not complete!');
        }

        $serverDuration = $itemTimeLine->compute();

        // take care of existing client range
        $clientTimeLine = $this->timeLine->filter($tags, TimePoint::TARGET_CLIENT);
        $clientRange = $clientTimeLine->getPoints();
        $clientRangeLength = count($clientRange);
        if ($clientRangeLength) {
            $clientDuration = 0;
            try {
                $clientDuration = $clientTimeLine->compute();
            } catch(TimeException $e) {
                \common_Logger::t('Handled client range error');
            }

            if (is_null($duration)) {
                if ($clientDuration) {
                    $duration = $clientDuration;
                    \common_Logger::t("No client duration provided to adjust the timer, but a range already exist: ${duration}");
                } else {
                    $duration = $serverDuration;
                    \common_Logger::t("No client duration provided to adjust the timer, fallback to server duration: ${duration}");
                }
            }

            $removed = $this->timeLine->remove($tags, TimePoint::TARGET_CLIENT);
            if ($removed == $clientRangeLength) {
                \common_Logger::t("Replace client duration in timer: ${clientDuration} to ${duration}");
            } else {
                \common_Logger::w("Unable to replace client duration in timer: ${clientDuration} to ${duration}");
            }
        }

        // check if the client side duration is bound by the server side duration
        if (is_null($duration)) {
            $duration = $serverDuration;
            \common_Logger::t("No client duration provided to adjust the timer, fallback to server duration: ${duration}");
        } else if ($duration > $serverDuration) {
            \common_Logger::w("A client duration must not be larger than the server time range! (${duration} > ${serverDuration})");
            $duration = $serverDuration;
        }

        // extract range boundaries
        TimePoint::sort($range);
        $serverStart = $range[0];
        $serverEnd = $range[$rangeLength - 1];

        // adjust the range by inserting the client duration between the server overall time range boundaries
        $overallDuration = $serverEnd->getTimestamp() - $serverStart->getTimestamp();
        $delay = ($overallDuration - $duration) / 2;
        
        $start = new TimePoint($tags, $serverStart->getTimestamp() + $delay, TimePoint::TYPE_START, TimePoint::TARGET_CLIENT);
        $this->timeLine->add($start);
        
        $end = new TimePoint($tags, $serverEnd->getTimestamp() - $delay, TimePoint::TYPE_END, TimePoint::TARGET_CLIENT);
        $this->timeLine->add($end);

        return $this;
    }
public function adjust($tags, $duration)
    {
        // check the provided arguments
        if (!is_null($duration) && (!is_numeric($duration) || $duration < 0)) {
            throw new InvalidDataException('adjust() needs a valid duration!');
        }

        // extract the TimePoint identification from the provided item, and find existing range
        $itemTimeLine = $this->timeLine->filter($tags, TimePoint::TARGET_SERVER);
        $range = $itemTimeLine->getPoints();

        // validate the data consistence
        $rangeLength = count($range);
        if (!$rangeLength || ($rangeLength % 2)) {
            throw new InconsistentRangeException('The time range does not seem to be consistent, the range is not complete!');
        }

        $serverDuration = $itemTimeLine->compute();

        // take care of existing client range
        $clientTimeLine = $this->timeLine->filter($tags, TimePoint::TARGET_CLIENT);
        $clientRange = $clientTimeLine->getPoints();
        $clientRangeLength = count($clientRange);
        if ($clientRangeLength) {
            $clientDuration = 0;
            try {
                $clientDuration = $clientTimeLine->compute();
            } catch(TimeException $e) {
                \common_Logger::t('Handled client range error');
            }

            if (is_null($duration)) {
                if ($clientDuration) {
                    $duration = $clientDuration;
                    \common_Logger::t("No client duration provided to adjust the timer, but a range already exist: ${duration}");
                } else {
                    $duration = $serverDuration;
                    \common_Logger::t("No client duration provided to adjust the timer, fallback to server duration: ${duration}");
                }
            }

            $removed = $this->timeLine->remove($tags, TimePoint::TARGET_CLIENT);
            if ($removed == $clientRangeLength) {
                \common_Logger::t("Replace client duration in timer: ${clientDuration} to ${duration}");
            } else {
                \common_Logger::w("Unable to replace client duration in timer: ${clientDuration} to ${duration}");
            }
        }

        // check if the client side duration is bound by the server side duration
        if (is_null($duration)) {
            $duration = $serverDuration;
            \common_Logger::t("No client duration provided to adjust the timer, fallback to server duration: ${duration}");
        } else if ($duration > $serverDuration) {
            \common_Logger::w("A client duration must not be larger than the server time range! (${duration} > ${serverDuration})");
            $duration = $serverDuration;
        }

        // extract range boundaries
        TimePoint::sort($range);
        $serverStart = $range[0];
        $serverEnd = $range[$rangeLength - 1];

        // adjust the range by inserting the client duration between the server overall time range boundaries
        $overallDuration = $serverEnd->getTimestamp() - $serverStart->getTimestamp();
        $delay = ($overallDuration - $duration) / 2;
        
        $start = new TimePoint($tags, $serverStart->getTimestamp() + $delay, TimePoint::TYPE_START, TimePoint::TARGET_CLIENT);
        $this->timeLine->add($start);
        
        $end = new TimePoint($tags, $serverEnd->getTimestamp() - $delay, TimePoint::TYPE_END, TimePoint::TARGET_CLIENT);
        $this->timeLine->add($end);

        return $this;
    }
Adds "client start" and "client end" TimePoint based on the provided duration for a particular ItemRef
@param string|array $tags
@param float $duration
@return Timer
@throws TimeException