@param string $userAgent

@return string
438841
public function normalize(string $userAgent): string
    {
        if (preg_match('/(ca|fr)\-crawler/', $userAgent)) {
            return $userAgent;
        }

        $regex = '/(; ?)(a[defgilmoqrstuwxz]|b[abdefghijlmnoqrstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[ceghnrst]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdefghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnorstvxyz]|t[cdfghjklmnortvwz]|u[agmsyz]|v[aceginu]|w[fs]|y[et]|z[ahmw])([-_]r?[a-zA-Z]{2})?(\.utf8|\.big5)?(\b-?)(?!:)([;)])/';

        if (!preg_match($regex, $userAgent, $matches)) {
            return $userAgent;
        }

        $replacement = str_replace(
            ['; )', '; -;', '; ;', ';;'],
            [')', ';', ';', ';'],
            sprintf('%s%s%s%s', $matches[1], $matches[4], $matches[5], $matches[6])
        );

        return preg_replace($regex, $replacement, $userAgent);
    }
179322
public function applyRecoveryMatch($userAgent)
    {
        if (Utils::checkIfContains($userAgent, 'Series60')) {
            return 'nokia_generic_series60';
        }

        if (Utils::checkIfContains($userAgent, 'Series80')) {
            return 'nokia_generic_series80';
        }

        if (Utils::checkIfContains($userAgent, 'MeeGo')) {
            return 'nokia_generic_meego';
        }

        return WurflConstants::NO_MATCH;
    }
1189022
public function getDeviceForUserAgent($userAgent)
    {
        if (!isset($userAgent)) {
            $userAgent = '';
        }
        
        $request = $this->_requestFactory->createRequestForUserAgent($userAgent);
        return $this->getDeviceForRequest($request);
    }
996823
protected function _getUserAgent()
    {
        $ua = str_replace('%v', self::VERSION, $this->userAgent);
        $ua = str_replace('%m', $this->_getUpdateMethod(), $ua);

        return $ua;
    }
1113177
public function applyRecoveryMatch($userAgent)
    {
        $operaVersion = self::getOperaVersion($userAgent);

        if ($operaVersion === null) {
            return 'opera';
        }

        $majorVersion = floor($operaVersion);
        $id           = 'opera_' . $majorVersion;

        if (in_array($id, self::$constantIDs)) {
            return $id;
        }

        return 'opera';
    }
834627
public static function toleranceToRisDelimeter($userAgent)
    {
        $tolerance = strpos($userAgent, WurflConstants::RIS_DELIMITER);
        if ($tolerance === false) {
            return false;
        }

        // Push the tolerance to the *end* of the RIS Delimiter
        return $tolerance + strlen(WurflConstants::RIS_DELIMITER);
    }
1066503
public function applyConclusiveMatch($userAgent)
    {
        $tolerance = Utils::toleranceToRisDelimeter($userAgent);
        if ($tolerance !== false) {
            return $this->getDeviceIDFromRIS($userAgent, $tolerance);
        }

        $tolerance = Utils::firstSlash($userAgent);

        return $this->getDeviceIDFromRIS($userAgent, $tolerance);
    }
313882
public function userAgent($useragent) {

		if(false === is_string($useragent)) {
            return trigger_error(sprintf('Argument 1 passed to %s() must be of the type string, "%s" given', __METHOD__, gettype($useragent)), E_USER_ERROR);
        }

		$this -> options[CURLOPT_USERAGENT] = $useragent;

		return $this;
	}
898255
public static function getWindowsPhoneAdClientModel($userAgent)
    {
        // Normalize spaces in UA before capturing parts
        $userAgent = preg_replace('|;(?! )|', '; ', $userAgent);
        if (preg_match(
            '|Windows ?Phone ?Ad ?Client/[0-9\.]+ ?\(.+; ?Windows ?Phone(?: ?OS)? ?[0-9\.]+; ?([^;\)]+(; ?[^;\)]+)?)|',
            $userAgent,
            $matches
        )
        ) {
            $model = $matches[1];
            $model = str_replace('_blocked', '', $model);
            $model = preg_replace('/(NOKIA; RM-.+?)_.*/', '$1', $model, 1);
            $model = preg_replace('/(Microsoft; RM-.+?)_.*/', '$1', $model, 1);

            return $model;
        }

        return null;
    }
191085
public function normalize($userAgent)
    {
        $model     = WebOSHandler::getWebOSModelVersion($userAgent);
        $osVersion = WebOSHandler::getWebOSVersion($userAgent);

        if ($model !== null && $osVersion !== null) {
            $prefix = $model . ' ' . $osVersion . WurflConstants::RIS_DELIMITER;

            return $prefix . $userAgent;
        }

        return $userAgent;
    }
691389
public static function toleranceToRisDelimeter($userAgent)
    {
        $tolerance = strpos($userAgent, WURFL_Constants::RIS_DELIMITER);
        if ($tolerance === false) {
            return false;
        }
        // Push the tolerance to the *end* of the RIS Delimiter
        return $tolerance + strlen(WURFL_Constants::RIS_DELIMITER);
    }
560662
protected function getBrowserParentId(string $userAgent) : int
    {
        if ($this->browserParentId === null) {
            $this->findBrowser($userAgent);
        }

        return $this->browserParentId;
    }
1197156
public function applyConclusiveMatch($userAgent)
    {
        $find      = 'NetFrontLifeBrowser/2.2';
        $tolerance = strpos($userAgent, $find) + strlen($find);

        if ($tolerance > strlen($userAgent)) {
            $tolerance = strlen($userAgent);
        }

        return $this->getDeviceIDFromRIS($userAgent, $tolerance);
    }
1226234
public function applyRecoveryCatchAllMatch($userAgent)
    {
        if (Utils::isDesktopBrowserHeavyDutyAnalysis($userAgent)) {
            return WurflConstants::GENERIC_WEB_BROWSER;
        }

        if (Utils::checkIfContains($userAgent, 'CoreMedia')) {
            return 'apple_iphone_coremedia_ver1';
        }

        if (Utils::checkIfContains($userAgent, 'Windows CE')) {
            return 'generic_ms_mobile';
        }

        if (Utils::checkIfContains($userAgent, 'UP.Browser/7.2')) {
            return 'opwv_v72_generic';
        }

        if (Utils::checkIfContains($userAgent, 'UP.Browser/7')) {
            return 'opwv_v7_generic';
        }

        if (Utils::checkIfContains($userAgent, 'UP.Browser/6.2')) {
            return 'opwv_v62_generic';
        }

        if (Utils::checkIfContains($userAgent, 'UP.Browser/6')) {
            return 'opwv_v6_generic';
        }

        if (Utils::checkIfContains($userAgent, 'UP.Browser/5')) {
            return 'upgui_generic';
        }

        if (Utils::checkIfContains($userAgent, 'UP.Browser/4')) {
            return 'uptext_generic';
        }

        if (Utils::checkIfContains($userAgent, 'UP.Browser/3')) {
            return 'uptext_generic';
        }

        // Series 60
        if (Utils::checkIfContains($userAgent, 'Series60')) {
            return 'nokia_generic_series60';
        }

        // Access/Net Front
        if (Utils::checkIfContainsAnyOf($userAgent, array('NetFront/3.0', 'ACS-NF/3.0'))) {
            return 'generic_netfront_ver3';
        }

        if (Utils::checkIfContainsAnyOf($userAgent, array('NetFront/3.1', 'ACS-NF/3.1'))) {
            return 'generic_netfront_ver3_1';
        }

        if (Utils::checkIfContainsAnyOf($userAgent, array('NetFront/3.2', 'ACS-NF/3.2'))) {
            return 'generic_netfront_ver3_2';
        }

        if (Utils::checkIfContainsAnyOf($userAgent, array('NetFront/3.3', 'ACS-NF/3.3'))) {
            return 'generic_netfront_ver3_3';
        }

        if (Utils::checkIfContains($userAgent, 'NetFront/3.4')) {
            return 'generic_netfront_ver3_4';
        }

        if (Utils::checkIfContains($userAgent, 'NetFront/3.5')) {
            return 'generic_netfront_ver3_5';
        }

        if (Utils::checkIfContains($userAgent, 'NetFront/4.0')) {
            return 'generic_netfront_ver4_0';
        }

        // Contains Mozilla/, but not at the beginning of the UA
        // ie: MOTORAZR V8/R601_G_80.41.17R Mozilla/4.0 (compatible; MSIE 6.0 Linux; MOTORAZR V88.50) Profile/MIDP-2.0 Configuration/CLDC-1.1 Opera 8.50[zh]
        if (strpos($userAgent, 'Mozilla/') > 0) {
            return WurflConstants::GENERIC_XHTML;
        }

        if (Utils::checkIfContainsAnyOf(
            $userAgent,
            array('Obigo', 'AU-MIC/2', 'AU-MIC-', 'AU-OBIGO/', 'Teleca Q03B1')
        )
        ) {
            return WurflConstants::GENERIC_XHTML;
        }

        // DoCoMo
        if (Utils::checkIfStartsWithAnyOf($userAgent, array('DoCoMo', 'KDDI'))) {
            return 'docomo_generic_jap_ver1';
        }

        if (Utils::isMobileBrowser($userAgent)) {
            return WurflConstants::GENERIC_MOBILE;
        }

        return WurflConstants::GENERIC;
    }
546772
public static function getInstance( $useragent = 'Spiget4PHP' )
    {
        if (is_null(SpigetAPI::$instance)) {
            SpigetAPI::$instance = new SpigetAPI($useragent);
        }
        return SpigetAPI::$instance;
    }
994628
public function getBrowser(string $userAgent) : array
    {
        // Init variables
        $browserId = $this->getBrowserId($userAgent);
        $browserParentId = $this->getBrowserParentId($userAgent);

        // Get all settings for the found browser
        //
        // It's best to use a recursive query here, but some linux distributions like CentOS and RHEL
        // use old sqlite library versions (like 3.6.20 or 3.7.17), so that we have to check the
        // version here and fall back to multiple single queries in case of older versions.
        if (version_compare($this->getSqliteVersion(), '3.8.3', '>=')) {
            $query  = 'SELECT t3.property_key, t4.property_value FROM (';
            $query .= 'WITH RECURSIVE browser_recursive(browser_id,browser_parent_id) AS (';
            $query .= 'SELECT browser_id, browser_parent_id FROM browser WHERE browser_id = :id';
            $query .= ' UNION ALL ';
            $query .= 'SELECT browser.browser_id, browser.browser_parent_id FROM browser, browser_recursive ';
            $query .= 'WHERE browser_recursive.browser_parent_id IS NOT NULL ';
            $query .= 'AND browser.browser_id = browser_recursive.browser_parent_id';
            $query .= ') ';
            $query .= 'SELECT MAX(t2.browser_id) AS browser_id, t2.property_key_id FROM browser_recursive t1 ';
            $query .= 'JOIN browser_property t2 ON t2.browser_id = t1.browser_id ';
            $query .= 'GROUP BY t2.property_key_id';
            $query .= ') t1 ';
            $query .= 'JOIN browser_property t2 ON t2.browser_id = t1.browser_id ';
            $query .= 'AND t2.property_key_id = t1.property_key_id ';
            $query .= 'JOIN browser_property_key t3 ON t3.property_key_id = t2.property_key_id ';
            $query .= 'JOIN browser_property_value t4 ON t4.property_value_id = t2.property_value_id';
            $query .= ' UNION ALL ';
            $query .= 'SELECT \'browser_name_pattern\' AS property_key, browser_pattern AS property_value ';
            $query .= 'FROM browser WHERE browser_id = :id';
            $query .= ' UNION ALL ';
            $query .= 'SELECT \'Parent\' AS property_key, browser_pattern AS property_value ';
            $query .= 'FROM browser WHERE browser_id = :parent';
            $statement = $this->getAdapter()->prepare($query);
        } else {
            $query = 'SELECT browser_id, browser_parent_id FROM browser WHERE browser_id = :id';
            $statement = $this->getAdapter()->prepare($query);
            $browserIds = [];
            $lastBrowserId = $browserId;
            while ($lastBrowserId !== null) {
                $result = $statement->execute(['id' => $lastBrowserId]);

                $lastBrowserId = null;
                if (count($result) > 0) {
                    $browserIds[] = (int)$result[0]['browser_id'];
                    if ($result[0]['browser_parent_id'] !== null) {
                        $lastBrowserId = (int)$result[0]['browser_parent_id'];
                    }
                }
            }

            $query  = 'SELECT t3.property_key, t4.property_value FROM (';
            $query .= 'SELECT MAX(browser_id) AS browser_id, property_key_id ';
            $query .= 'FROM browser_property WHERE browser_id IN (' . implode(', ', $browserIds) . ') ';
            $query .= 'GROUP BY property_key_id';
            $query .= ') t1 ';
            $query .= 'JOIN browser_property t2 ON t2.browser_id = t1.browser_id ';
            $query .= 'AND t2.property_key_id = t1.property_key_id ';
            $query .= 'JOIN browser_property_key t3 ON t3.property_key_id = t2.property_key_id ';
            $query .= 'JOIN browser_property_value t4 ON t4.property_value_id = t2.property_value_id';
            $query .= ' UNION ALL ';
            $query .= 'SELECT \'browser_name_pattern\' AS property_key, browser_pattern AS property_value ';
            $query .= 'FROM browser WHERE browser_id = :id';
            $query .= ' UNION ALL ';
            $query .= 'SELECT \'Parent\' AS property_key, browser_pattern AS property_value ';
            $query .= 'FROM browser WHERE browser_id = :parent';
            $statement = $this->getAdapter()->prepare($query);
        }

        $properties = [];
        foreach ($statement->execute(['id' => $browserId, 'parent' => $browserParentId]) as $row) {
            $properties[$row['property_key']] = $row['property_value'];
        }

        // Set regular expression properties
        $propertyFilter = $this->getPropertyFilter();
        if (!$propertyFilter->isFiltered('browser_name_regex')) {
            $properties['browser_name_regex'] = $this->getRegExpForPattern($properties['browser_name_pattern']);
        }
        if ($propertyFilter->isFiltered('browser_name_pattern')) {
            unset($properties['browser_name_pattern']);
        }
        if ($propertyFilter->isFiltered('Parent')) {
            unset($properties['Parent']);
        }

        // IMPORTANT: Reset browserId and browserParentId for next call
        $this->browserId = null;
        $this->browserParentId = null;

        // The settings are in random order, so sort them
        return $this->sortProperties($properties);
    }
266605
protected function getBrowserId(string $userAgent) : int
    {
        if ($this->browserId === null) {
            $this->findBrowser($userAgent);
        }

        return $this->browserId;
    }