protected function doParse($userAgentString)
  {
    $userAgent = array(
      'string'            => $this->cleanUserAgentString($userAgentString),
      'browser_name'      => null,
      'browser_version'   => null,
      'operating_system'  => null,
      'engine'            => null
    );

    if(empty($userAgent['string']))
    {
      return $userAgent;
    }

    // build regex that matches phrases for known browsers
    // (e.g. "Firefox/2.0" or "MSIE 6.0" (This only matches the major and minor
    // version numbers.  E.g. "2.0.0.6" is parsed as simply "2.0"
    $pattern = '#('.join('|', $this->getKnownBrowsers()).')[/ ]+([0-9]+(?:\.[0-9]+)?)#';

    // Find all phrases (or return empty array if none found)
    if (preg_match_all($pattern, $userAgent['string'], $matches))
    {
      // Since some UAs have more than one phrase (e.g Firefox has a Gecko phrase,
      // Opera 7,8 have a MSIE phrase), use the last one found (the right-most one
      // in the UA).  That's usually the most correct.
      $i = count($matches[1])-1;

      if (isset($matches[1][$i]))
      {
        $userAgent['browser_name'] = $matches[1][$i];
      }
      if (isset($matches[2][$i]))
      {
        $userAgent['browser_version'] = $matches[2][$i];
      }
    }

    // Find operating system
    $pattern = '#'.join('|', $this->getKnownOperatingSystems()).'#';
    
    if (preg_match($pattern, $userAgent['string'], $match))
    {
      if (isset($match[0]))
      {
        $userAgent['operating_system'] = $match[0];
      }
    }

    // Find engine
    $pattern = '#'.join('|', $this->getKnownEngines()).'#';
    
    if (preg_match($pattern, $userAgent['string'], $match))
    {
      if (isset($match[0]))
      {
        $userAgent['engine'] = $match[0];
      }
    }

    return $userAgent;
  }