protected function matchPartial($routePathPartial, $toEnd = false) {
		$result = false;

		$numOfRouteMatches = preg_match_all(
			self::ROUTE_PARAM_PATTERN,
			$routePathPartial,
			$routeMatches,
			PREG_OFFSET_CAPTURE
		);

		if ($numOfRouteMatches === 0) { // plain string
			if ($toEnd) {
				$requestPathPartial = substr($this->request->getPath(), $this->requestPathOffset);
			} else {
				$requestPathPartial = substr($this->request->getPath(), $this->requestPathOffset, strlen($routePathPartial));
			}

			if ($routePathPartial === $requestPathPartial) {
				$result = true;

				if (!$toEnd) {
					// Move offset if it is not matching to the end, i.e. not the last match.
					$this->requestPathOffset += strlen($routePathPartial);
				}
			}
		} else if ($numOfRouteMatches > 0) { // has params
			// Build regex
			$pos = 0;
			$pattern = '#^';
			for ($i = 0; $i < $numOfRouteMatches; $i++) {
				$pattern .= substr($routePathPartial, $pos, $routeMatches[1][$i][1] - $pos);
				$pattern .= '(?P<' . $routeMatches[2][$i][0] . '>[^/]+)';
				$pos = $routeMatches[1][$i][1] + strlen($routeMatches[1][$i][0]);
			}
			$pattern .= substr($routePathPartial, $pos);
			if ($toEnd) {
				$pattern .= '$';
			}
			$pattern .= '#';

			$requestPathPartial = substr($this->request->getPath(), $this->requestPathOffset);

			$numOfPathMatches = preg_match($pattern, $requestPathPartial, $pathMatches);

			if ($numOfPathMatches === 1) {
				$result = true;

				// Setup params
				foreach ($routeMatches[2] as $m) {
					$paramName = $m[0];
					$this->params[$paramName] = $pathMatches[$paramName];
				}

				if (!$toEnd) {
					// Move offset if it is not matching to the end, i.e. not the last match.
					$this->requestPathOffset += strlen($pathMatches[0]);
				}
			}
		}

		return $result;
	}