/**
  * Parse a relative URI and returns information about it.
  */
 public static function parseUri(IPieCrust $pieCrust, $uri, $uriTypes = self::PAGE_URI_ANY)
 {
     if (strpos($uri, '..') !== false) {
         throw new PieCrustException('404');
     }
     $uri = '/' . trim($uri, '/');
     $pageNumber = 1;
     $matches = array();
     if (preg_match('/\\/(\\d+)\\/?$/', $uri, $matches)) {
         // Requesting a page other than the first for this article.
         $uri = substr($uri, 0, strlen($uri) - strlen($matches[0]));
         $pageNumber = intval($matches[1]);
     }
     $uri = ltrim($uri, '/');
     $pageInfo = array('uri' => $uri, 'page' => $pageNumber, 'type' => IPage::TYPE_REGULAR, 'blogKey' => null, 'key' => null, 'date' => null, 'path' => null, 'was_path_checked' => false);
     // Try first with a regular page path.
     if (($uriTypes & self::PAGE_URI_REGULAR) != 0 and UriParser::tryParsePageUri($pieCrust, $uri, $pageInfo)) {
         return $pageInfo;
     }
     $blogKeys = $pieCrust->getConfig()->getValueUnchecked('site/blogs');
     // Try with a post.
     if (($uriTypes & self::PAGE_URI_POST) != 0) {
         foreach ($blogKeys as $blogKey) {
             if (UriParser::tryParsePostUri($pieCrust, $blogKey, $uri, $pageInfo)) {
                 return $pageInfo;
             }
         }
     }
     // Try with special pages (tag & category)
     if (($uriTypes & (self::PAGE_URI_CATEGORY | self::PAGE_URI_TAG)) != 0) {
         foreach ($blogKeys as $blogKey) {
             if (($uriTypes & self::PAGE_URI_TAG) != 0 and UriParser::tryParseTagUri($pieCrust, $blogKey, $uri, $pageInfo)) {
                 return $pageInfo;
             }
             if (($uriTypes & self::PAGE_URI_CATEGORY) != 0 and UriParser::tryParseCategoryUri($pieCrust, $blogKey, $uri, $pageInfo)) {
                 return $pageInfo;
             }
         }
     }
     // No idea what that URI is...
     return null;
 }