<?php

/**
 * Device Detector - The Universal Device Detection library for parsing User Agents
 *
 * @link https://matomo.org
 *
 * @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later
 */

declare(strict_types=1);

namespace DeviceDetector\Parser\Device;

use DeviceDetector\Parser\AbstractParser;

/**
 * Class AbstractDeviceParser
 *
 * Abstract class for all device parsers
 */
abstract class AbstractDeviceParser extends AbstractParser
{
    /**
     * @var ?int
     */
    protected $deviceType = null;

    /**
     * @var string
     */
    protected $model = '';

    /**
     * @var string
     */
    protected $brand = '';

    public const DEVICE_TYPE_DESKTOP              = 0;
    public const DEVICE_TYPE_SMARTPHONE           = 1;
    public const DEVICE_TYPE_TABLET               = 2;
    public const DEVICE_TYPE_FEATURE_PHONE        = 3;
    public const DEVICE_TYPE_CONSOLE              = 4;
    public const DEVICE_TYPE_TV                   = 5; // including set top boxes, blu-ray players,...
    public const DEVICE_TYPE_CAR_BROWSER          = 6;
    public const DEVICE_TYPE_SMART_DISPLAY        = 7;
    public const DEVICE_TYPE_CAMERA               = 8;
    public const DEVICE_TYPE_PORTABLE_MEDIA_PAYER = 9;
    public const DEVICE_TYPE_PHABLET              = 10;
    public const DEVICE_TYPE_SMART_SPEAKER        = 11;
    public const DEVICE_TYPE_WEARABLE             = 12; // including set watches, headsets
    public const DEVICE_TYPE_PERIPHERAL           = 13; // including portable terminal, portable projector

    /**
     * Detectable device types
     *
     * @var array
     */
    protected static $deviceTypes = [
        'desktop'               => self::DEVICE_TYPE_DESKTOP,
        'smartphone'            => self::DEVICE_TYPE_SMARTPHONE,
        'tablet'                => self::DEVICE_TYPE_TABLET,
        'feature phone'         => self::DEVICE_TYPE_FEATURE_PHONE,
        'console'               => self::DEVICE_TYPE_CONSOLE,
        'tv'                    => self::DEVICE_TYPE_TV,
        'car browser'           => self::DEVICE_TYPE_CAR_BROWSER,
        'smart display'         => self::DEVICE_TYPE_SMART_DISPLAY,
        'camera'                => self::DEVICE_TYPE_CAMERA,
        'portable media player' => self::DEVICE_TYPE_PORTABLE_MEDIA_PAYER,
        'phablet'               => self::DEVICE_TYPE_PHABLET,
        'smart speaker'         => self::DEVICE_TYPE_SMART_SPEAKER,
        'wearable'              => self::DEVICE_TYPE_WEARABLE,
        'peripheral'            => self::DEVICE_TYPE_PERIPHERAL,
    ];

    /**
     * Known device brands
     *
     * Note: Before using a new brand in on of the regex files, it needs to be added here
     *
     * @var array
     */
    public static $deviceBrands = [
        '5E'  => '2E',
        '2F'  => 'F2 Mobile',
        '3Q'  => '3Q',
        'J7'  => '7 Mobile',
        '2Q'  => '3GNET',
        '4G'  => '4Good',
        '27'  => '3GO',
        '04'  => '4ife',
        '36'  => '360',
        '88'  => '8848',
        '41'  => 'A1',
        '00'  => 'Accent',
        'AE'  => 'Ace',
        'AC'  => 'Acer',
        '3K'  => 'Acteck',
        'ACT' => 'actiMirror',
        'A9'  => 'Advan',
        'AD'  => 'Advance',
        '76'  => 'Adronix',
        'AF'  => 'AfriOne',
        'FY'  => 'AFFIX',
        'A3'  => 'AGM',
        'J0'  => 'AG Mobile',
        'AZ'  => 'Ainol',
        'AIR' => 'Airis',
        'AI'  => 'Airness',
        'AT'  => 'Airties',
        '7U'  => 'Airtel',
        'U0'  => 'AIRON',
        '0A'  => 'AIS',
        'AW'  => 'Aiwa',
        '85'  => 'Aiuto',
        'U7'  => 'AIDATA',
        'AK'  => 'Akai',
        'Q3'  => 'AKIRA',
        '1A'  => 'Alba',
        'AL'  => 'Alcatel',
        '20'  => 'Alcor',
        'XY'  => 'Alps',
        '7L'  => 'ALDI NORD',
        '6L'  => 'ALDI SÜD',
        '3L'  => 'Alfawise',
        '4A'  => 'Aligator',
        'AA'  => 'AllCall',
        '3A'  => 'AllDocube',
        'A2'  => 'Allview',
        'A7'  => 'Allwinner',
        'A1'  => 'Altech UEC',
        '66'  => 'Altice',
        'A5'  => 'altron',
        'KN'  => 'Amazon',
        'AG'  => 'AMGOO',
        '9A'  => 'Amigoo',
        'AO'  => 'Amoi',
        '3J'  => 'Amino',
        '54'  => 'AMCV',
        '60'  => 'Andowl',
        '6J'  => 'Angelcare',
        '7A'  => 'Anry',
        'A0'  => 'ANS',
        '74'  => 'Anker',
        '3N'  => 'Aoson',
        'O8'  => 'AOC',
        'J2'  => 'AOYODKG',
        '55'  => 'AOpen',
        'RW'  => 'Aoro',
        '9Y'  => 'Aocos',
        'AP'  => 'Apple',
        'AR'  => 'Archos',
        'AB'  => 'Arian Space',
        'A6'  => 'Ark',
        '5A'  => 'ArmPhone',
        'AN'  => 'Arnova',
        'AS'  => 'ARRIS',
        'AQ'  => 'Aspera',
        'HJ'  => 'Aquarius',
        '40'  => 'Artel',
        '21'  => 'Artizlee',
        '59'  => 'ArtLine',
        '8A'  => 'Asano',
        '90'  => 'Asanzo',
        '1U'  => 'Astro',
        'A4'  => 'Ask',
        'A8'  => 'Assistant',
        'AU'  => 'Asus',
        '6A'  => 'AT&T',
        'ATH' => 'Athesi',
        '5Q'  => 'Atmaca Elektronik',
        'YH'  => 'ATMAN',
        '2A'  => 'Atom',
        'ATO' => 'ATOL',
        'Z2'  => 'Atvio',
        'AX'  => 'Audiovox',
        'AJ'  => 'AURIS',
        'YZ'  => 'Autan',
        'ZA'  => 'Avenzo',
        'AH'  => 'AVH',
        'AV'  => 'Avvio',
        'AVA' => 'Avaya',
        'AY'  => 'Axxion',
        'AXX' => 'AXXA',
        'YR'  => 'AYYA',
        'XA'  => 'Axioo',
        'AM'  => 'Azumi Mobile',
        'WW'  => 'Awow',
        'XU'  => 'AUX',
        'BAC' => 'Backcell',
        'BO'  => 'BangOlufsen',
        'BN'  => 'Barnes & Noble',
        'BB'  => 'BBK',
        '0B'  => 'BB Mobile',
        'B6'  => 'BDF',
        'QD'  => 'BDQ',
        '8Z'  => 'BDsharing',
        'BE'  => 'Becker',
        'B5'  => 'Beeline',
        'B0'  => 'Beelink',
        'BL'  => 'Beetel',
        '2X'  => 'Benco',
        'BQ'  => 'BenQ',
        'BS'  => 'BenQ-Siemens',
        '4Y'  => 'Benzo',
        'XJ'  => 'Benesse',
        'YB'  => 'Beista',
        'BY'  => 'BS Mobile',
        'BZ'  => 'Bezkam',
        '9B'  => 'Bellphone',
        '63'  => 'Beyond',
        'BG'  => 'BGH',
        '6B'  => 'Bigben',
        'B8'  => 'BIHEE',
        '1B'  => 'Billion',
        'BA'  => 'BilimLand',
        'BIL' => 'Billow',
        'BH'  => 'BioRugged',
        'BI'  => 'Bird',
        'BT'  => 'Bitel',
        'B7'  => 'Bitmore',
        'ZB'  => 'Bittium',
        'BK'  => 'Bkav',
        '5B'  => 'Black Bear',
        'BF'  => 'Black Fox',
        'B2'  => 'Blackview',
        '2Y'  => 'b2m',
        'BP'  => 'Blaupunkt',
        'BU'  => 'Blu',
        'BUZ' => 'BuzzTV',
        'B3'  => 'Bluboo',
        '2B'  => 'Bluedot',
        'BD'  => 'Bluegood',
        'LB'  => 'Bluewave',
        'J8'  => 'Bluebird',
        'BSS' => 'BlueSky',
        '7B'  => 'Blloc',
        'UB'  => 'Bleck',
        'Q2'  => 'Blow',
        'BLI' => 'BLISS',
        'BM'  => 'Bmobile',
        'Y5'  => 'BMAX',
        'B9'  => 'Bobarry',
        'B4'  => 'bogo',
        'BW'  => 'Boway',
        'BOO' => 'Boost',
        'BX'  => 'bq',
        '8B'  => 'Brandt',
        'BRA' => 'BrandCode',
        'BV'  => 'Bravis',
        'BR'  => 'Brondi',
        'XF'  => 'BROR',
        'BJ'  => 'BrightSign',
        'B1'  => 'Bush',
        '4Q'  => 'Bundy',
        'Y8'  => 'Bubblegum',
        'C9'  => 'CAGI',
        'CT'  => 'Capitel',
        'G3'  => 'CG Mobile',
        '37'  => 'CGV',
        'CP'  => 'Captiva',
        'CF'  => 'Carrefour',
        'CA1' => 'Carbon Mobile',
        'CS'  => 'Casio',
        'R4'  => 'Casper',
        'CA'  => 'Cat',
        'BC'  => 'Camfone',
        'CJ'  => 'Cavion',
        '4D'  => 'Canal Digital',
        'CEI' => 'Ceibal',
        '02'  => 'Cell-C',
        'CEL' => 'Cellacom',
        '34'  => 'CellAllure',
        '7C'  => 'Celcus',
        'CE'  => 'Celkon',
        'CG'  => 'Cellution',
        '62'  => 'Centric',
        'C2'  => 'Changhong',
        'CHA' => 'Chainway',
        'CHG' => 'ChiliGreen',
        'CH'  => 'Cherry Mobile',
        'C3'  => 'China Mobile',
        'U9'  => 'China Telecom',
        'CI'  => 'Chico Mobile',
        'CIP' => 'CipherLab',
        '1C'  => 'Chuwi',
        'L8'  => 'Clarmin',
        '25'  => 'Claresta',
        '1J'  => 'Cloud',
        'CD'  => 'Cloudfone',
        '6C'  => 'Cloudpad',
        'C0'  => 'Clout',
        'CN'  => 'CnM',
        'CY'  => 'Coby Kyros',
        'XC'  => 'Cobalt',
        'C6'  => 'Comio',
        'CL'  => 'Compal',
        'CQ'  => 'Compaq',
        'C7'  => 'ComTrade Tesla',
        '7Z'  => 'COMPUMAX',
        'C8'  => 'Concord',
        'CC'  => 'ConCorde',
        'C5'  => 'Condor',
        'C5M' => 'C5 Mobile',
        '4C'  => 'Conquest',
        '3C'  => 'Contixo',
        '8C'  => 'Connex',
        '53'  => 'Connectce',
        '9C'  => 'Colors',
        'CO'  => 'Coolpad',
        'COO' => 'Coopers',
        '4R'  => 'CORN',
        '1O'  => 'Cosmote',
        'CW'  => 'Cowon',
        '75'  => 'Covia',
        'QG'  => 'COYOTE',
        'YW'  => 'ClearPHONE',
        '33'  => 'Clementoni',
        'CR'  => 'CreNova',
        'CX'  => 'Crescent',
        'CK'  => 'Cricket',
        'CM'  => 'Crius Mea',
        '0C'  => 'Crony',
        'C1'  => 'Crosscall',
        '4W'  => 'Crown',
        'CU'  => 'Cube',
        'CB'  => 'CUBOT',
        'CV'  => 'CVTE',
        'C4'  => 'Cyrus',
        'D5'  => 'Daewoo',
        'DA'  => 'Danew',
        'DAN' => 'Dany',
        'DT'  => 'Datang',
        'D7'  => 'Datawind',
        '7D'  => 'Datamini',
        '6D'  => 'Datalogic',
        'D1'  => 'Datsun',
        'DZ'  => 'Dazen',
        'DAS' => 'DASS',
        'DB'  => 'Dbtel',
        'DBP' => 'DbPhone',
        'DCO' => 'Dcode',
        'DL'  => 'Dell',
        'DL0' => 'DL',
        'DE'  => 'Denver',
        'DS'  => 'Desay',
        'DW'  => 'DeWalt',
        'DX'  => 'DEXP',
        'DEN' => 'Denali',
        '8D'  => 'DF',
        'DGT' => 'DGTEC',
        'DG'  => 'Dialog',
        'DI'  => 'Dicam',
        'D4'  => 'Digi',
        'D3'  => 'Digicel',
        'DDG' => 'Digidragon',
        'DH'  => 'Digihome',
        'DD'  => 'Digiland',
        'DIG' => 'Digit4G',
        'DIC' => 'DIGICOM',
        'Q0'  => 'DIGIFORS',
        'DQ'  => 'DISH',
        '9D'  => 'Ditecma',
        'D2'  => 'Digma',
        '1D'  => 'Diva',
        'DIV' => 'DiverMax',
        'D6'  => 'Divisat',
        'X6'  => 'DIXON',
        '5D'  => 'DING DING',
        'DIN' => 'Dinax',
        'DM'  => 'DMM',
        'DN'  => 'DNS',
        'DC'  => 'DoCoMo',
        'DF'  => 'Doffler',
        'D9'  => 'Dolamee',
        'DO'  => 'Doogee',
        'D0'  => 'Doopro',
        'DV'  => 'Doov',
        'DOM' => 'Dom.ru',
        'DP'  => 'Dopod',
        'JQ'  => 'Doppio',
        'DR'  => 'Doro',
        'ZD'  => 'DORLAND',
        'D8'  => 'Droxio',
        'DJ'  => 'Dragon Touch',
        'DY'  => 'Dreamgate',
        'DRE' => 'DreamTab',
        'DR1' => 'DreamStar',
        'DTA' => 'Dtac',
        'DU'  => 'Dune HD',
        'UD'  => 'DUNNS Mobile',
        'DTE' => 'D-Tech',
        'DLI' => 'D-Link',
        'ENO' => 'eNOVA',
        'IN2' => 'iNOVA',
        'EB'  => 'E-Boda',
        'EJ'  => 'Engel',
        'ENA' => 'ENACOM',
        'ENI' => 'ENIE',
        '2E'  => 'E-Ceros',
        'E8'  => 'E-tel',
        'EP'  => 'Easypix',
        'EQ'  => 'Eagle',
        'EA'  => 'EBEST',
        'YC'  => 'EBEN',
        'E4'  => 'Echo Mobiles',
        'EQ1' => 'Equator',
        'ES'  => 'ECS',
        '35'  => 'ECON',
        'ECC' => 'ECOO',
        'ZZ'  => 'ecom',
        'E6'  => 'EE',
        'GW'  => 'EGL',
        'EFT' => 'EFT',
        'EK'  => 'EKO',
        'EY'  => 'Einstein',
        'EM'  => 'Eks Mobility',
        'UE'  => 'Ematic',
        'EMR' => 'Emporia',
        '4K'  => 'EKT',
        '7E'  => 'ELARI',
        '03'  => 'Electroneum',
        'Z8'  => 'ELECTRONIA',
        'EL1' => 'Elecson',
        'L0'  => 'Element',
        'EG'  => 'Elenberg',
        'EL'  => 'Elephone',
        'JE'  => 'Elekta',
        'ELE' => 'Elevate',
        '4E'  => 'Eltex',
        'ELM' => 'Elong Mobile',
        'ED'  => 'Energizer',
        'E1'  => 'Energy Sistem',
        '3E'  => 'Enot',
        'ENV' => 'Envizen',
        '8E'  => 'Epik One',
        'XP'  => 'Epson',
        'E7'  => 'Ergo',
        'EC'  => 'Ericsson',
        '05'  => 'Erisson',
        'ER'  => 'Ericy',
        'EE'  => 'Essential',
        'E2'  => 'Essentielb',
        '6E'  => 'eSTAR',
        'EN'  => 'Eton',
        'ET'  => 'eTouch',
        '1E'  => 'Etuline',
        'EU'  => 'Eurostar',
        '4J'  => 'Eurocase',
        'E9'  => 'Evercoss',
        'EV'  => 'Evertek',
        'E3'  => 'Evolio',
        'EO'  => 'Evolveo',
        '0Q'  => 'Evoo',
        '5U'  => 'EVPAD',
        'E0'  => 'EvroMedia',
        'XE'  => 'ExMobile',
        '4Z'  => 'Exmart',
        'EH'  => 'EXO',
        'EX'  => 'Explay',
        'E5'  => 'Extrem',
        'EF'  => 'EXCEED',
        'QE'  => 'EWIS',
        'EI'  => 'Ezio',
        'EZ'  => 'Ezze',
        'UF'  => 'EYU',
        '5F'  => 'F150',
        'F6'  => 'Facebook',
        'FAC' => 'Facetel',
        'FA1' => 'Facime',
        'FA'  => 'Fairphone',
        'FM'  => 'Famoco',
        'FAM' => 'Famous',
        '17'  => 'FarEasTone',
        '9R'  => 'FaRao Pro',
        'FB'  => 'Fantec',
        'FE'  => 'Fengxiang',
        'F7'  => 'Fero',
        '67'  => 'FEONAL',
        'FI'  => 'FiGO',
        'J9'  => 'FiGi',
        'F9'  => 'FiiO',
        'F1'  => 'FinePower',
        'FX'  => 'Finlux',
        'F3'  => 'FireFly Mobile',
        'F8'  => 'FISE',
        'FIL' => 'FILIX',
        'FL'  => 'Fly',
        'QC'  => 'FLYCAT',
        'FN'  => 'FNB',
        'FD'  => 'Fondi',
        '0F'  => 'Fourel',
        '44'  => 'Four Mobile',
        'F0'  => 'Fonos',
        'F2'  => 'FORME',
        'F5'  => 'Formuler',
        'FR'  => 'Forstar',
        'RF'  => 'Fortis',
        'FO'  => 'Foxconn',
        'FJ'  => 'FOODO',
        'FT'  => 'Freetel',
        'F4'  => 'F&U',
        '1F'  => 'FMT',
        'FPT' => 'FPT',
        'FG'  => 'Fuego',
        'FU'  => 'Fujitsu',
        '4F'  => 'Funai',
        '5J'  => 'Fusion5',
        'FF'  => 'Future Mobile Technology',
        'FW'  => 'FNF',
        'GT'  => 'G-TiDE',
        'G9'  => 'G-Touch',
        '0G'  => 'GFive',
        'GM'  => 'Garmin-Asus',
        'GA'  => 'Gateway',
        '99'  => 'Galaxy Innovations',
        'GAZ' => 'Gazer',
        'GEA' => 'Geanee',
        'GD'  => 'Gemini',
        'GN'  => 'General Mobile',
        '2G'  => 'Genesis',
        'G2'  => 'GEOFOX',
        'GE'  => 'Geotel',
        'Q4'  => 'Geotex',
        'GEO' => 'GEOZON',
        'GER' => 'Gear Mobile',
        'GH'  => 'Ghia',
        '2C'  => 'Ghong',
        'GJ'  => 'Ghost',
        'GG'  => 'Gigabyte',
        'GS'  => 'Gigaset',
        'GZ'  => 'Ginzzu',
        '1G'  => 'Gini',
        'GI'  => 'Gionee',
        'G4'  => 'Globex',
        '38'  => 'GLONYX',
        'U6'  => 'Glofiish',
        'G7'  => 'GoGEN',
        'GC'  => 'GOCLEVER',
        '5G'  => 'Gocomma',
        'GB'  => 'Gol Mobile',
        'GL'  => 'Goly',
        'GOL' => 'GoldMaster',
        'GX'  => 'GLX',
        'G5'  => 'Gome',
        'G1'  => 'GoMobile',
        'GO'  => 'Google',
        'G0'  => 'Goophone',
        '6G'  => 'Gooweel',
        '8G'  => 'Gplus',
        'GR'  => 'Gradiente',
        'GP'  => 'Grape',
        'G6'  => 'Gree',
        '3G'  => 'Greentel',
        'GF'  => 'Gretel',
        '82'  => 'Gresso',
        'GU'  => 'Grundig',
        'GV'  => 'Gtel',
        'H13' => 'H133',
        '9Z'  => 'H96',
        'HF'  => 'Hafury',
        '9F'  => 'HAOVM',
        'HA'  => 'Haier',
        'XH'  => 'Haipai',
        'HAN' => 'Handheld',
        'HE'  => 'HannSpree',
        'HK'  => 'Hardkernel',
        'HAR' => 'Harper',
        'HS'  => 'Hasee',
        '8H'  => 'Hamlet',
        'HAM' => 'Hammer',
        'H6'  => 'Helio',
        'HQ'  => 'HERO',
        'ZH'  => 'Hezire',
        'HEX' => 'HexaByte',
        'HL'  => 'Hi-Level',
        '3H'  => 'Hi',
        'HIH' => 'HiHi',
        'HIK' => 'HiKing',
        'H2'  => 'Highscreen',
        'Q1'  => 'High Q',
        '1H'  => 'Hipstreet',
        'HI'  => 'Hisense',
        'HC'  => 'Hitachi',
        'H8'  => 'Hitech',
        'W3'  => 'HiMax',
        '8X'  => 'Hi Nova',
        'HLL' => 'HLLO',
        '8W'  => 'HKPro',
        'H1'  => 'Hoffmann',
        'H0'  => 'Hometech',
        'HM'  => 'Homtom',
        'HZ'  => 'Hoozo',
        'H7'  => 'Horizon',
        '4H'  => 'Horizont',
        'HO'  => 'Hosin',
        'H3'  => 'Hotel',
        'HV'  => 'Hotwav',
        'U8'  => 'Hot Pepper',
        'JH'  => 'HOTREALS',
        'HW'  => 'How',
        'WH'  => 'Honeywell',
        'HP'  => 'HP',
        'HDC' => 'HDC',
        'HT'  => 'HTC',
        'QZ'  => 'Huagan',
        'HD'  => 'Huadoo',
        'HG'  => 'Huavi',
        'HU'  => 'Huawei',
        'HX'  => 'Humax',
        'HR'  => 'Hurricane',
        'H5'  => 'Huskee',
        'HUG' => 'Hugerock',
        'HY'  => 'Hyrican',
        'HN'  => 'Hyundai',
        '7H'  => 'Hyve',
        'HYT' => 'Hytera',
        '3I'  => 'i-Cherry',
        'IJ'  => 'i-Joy',
        'IM'  => 'i-mate',
        'IO'  => 'i-mobile',
        'INN' => 'I-INN',
        'OF'  => 'iOutdoor',
        'IB'  => 'iBall',
        'IY'  => 'iBerry',
        '7I'  => 'iBrit',
        'I2'  => 'IconBIT',
        'IC'  => 'iDroid',
        '6Z'  => 'iData',
        'IG'  => 'iGet',
        'IH'  => 'iHunt',
        'IA'  => 'Ikea',
        '8I'  => 'IKU Mobile',
        '2K'  => 'IKI Mobile',
        'IK'  => 'iKoMo',
        '58'  => 'iKon',
        'I7'  => 'iLA',
        '2I'  => 'iLife',
        '1I'  => 'iMars',
        'IMI' => 'iMI',
        'U4'  => 'iMan',
        'IL'  => 'IMO Mobile',
        'IM1' => 'Imose',
        'I3'  => 'Impression',
        'FC'  => 'INCAR',
        '2H'  => 'Inch',
        '6I'  => 'Inco',
        'IW'  => 'iNew',
        'IF'  => 'Infinix',
        'INF' => 'Infiniton',
        'I0'  => 'InFocus',
        'IN1' => 'InFone',
        'II'  => 'Inkti',
        '81'  => 'InfoKit',
        'I5'  => 'InnJoo',
        '26'  => 'Innos',
        'IN'  => 'Innostream',
        'I4'  => 'Inoi',
        'INO' => 'iNo Mobile',
        'IQ'  => 'INQ',
        'QN'  => 'iQ&T',
        'IS'  => 'Insignia',
        'YI'  => 'INSYS',
        'IT'  => 'Intek',
        'INT' => 'Intel',
        'IX'  => 'Intex',
        'IV'  => 'Inverto',
        '32'  => 'Invens',
        '4I'  => 'Invin',
        'INA' => 'iNavi',
        'I1'  => 'iOcean',
        'IMU' => 'iMuz',
        'IP'  => 'iPro',
        'X9'  => 'iPEGTOP',
        '8Q'  => 'IQM',
        'Q8'  => 'IRA',
        'I6'  => 'Irbis',
        '5I'  => 'Iris',
        'IRE' => 'iReplace',
        'IR'  => 'iRola',
        'IU'  => 'iRulu',
        '9I'  => 'iSWAG',
        '9J'  => 'iSafe Mobile',
        'IST' => 'iStar',
        '86'  => 'IT',
        'IZ'  => 'iTel',
        '0I'  => 'iTruck',
        'I8'  => 'iVA',
        'IE'  => 'iView',
        '0J'  => 'iVooMi',
        'UI'  => 'ivvi',
        'QW'  => 'iWaylink',
        'I9'  => 'iZotron',
        'IXT' => 'iXTech',
        'JA'  => 'JAY-Tech',
        'KJ'  => 'Jiake',
        'JD'  => 'Jedi',
        'J6'  => 'Jeka',
        'JF'  => 'JFone',
        'JI'  => 'Jiayu',
        'JG'  => 'Jinga',
        'JX'  => 'Jio',
        'VJ'  => 'Jivi',
        'JK'  => 'JKL',
        'JR1' => 'JREN',
        'JO'  => 'Jolla',
        'JP'  => 'Joy',
        'UJ'  => 'Juniper Systems',
        'J5'  => 'Just5',
        '7J'  => 'Jumper',
        'JPA' => 'JPay',
        'JV'  => 'JVC',
        'JXD' => 'JXD',
        'JS'  => 'Jesy',
        'KT'  => 'K-Touch',
        'K4'  => 'Kaan',
        'K7'  => 'Kaiomy',
        'KL'  => 'Kalley',
        'K6'  => 'Kanji',
        'KA'  => 'Karbonn',
        'K5'  => 'KATV1',
        'K0'  => 'Kata',
        'KZ'  => 'Kazam',
        '9K'  => 'Kazuna',
        'KD'  => 'KDDI',
        'KS'  => 'Kempler & Strauss',
        'K3'  => 'Keneksi',
        'KX'  => 'Kenxinda',
        'KEN' => 'Kenbo',
        'K1'  => 'Kiano',
        '5W'  => 'Kingbox',
        'KI'  => 'Kingsun',
        'KF'  => 'KINGZONE',
        'KIN' => 'Kingstar',
        '46'  => 'Kiowa',
        'KV'  => 'Kivi',
        '64'  => 'Kvant',
        '0K'  => 'Klipad',
        'KC'  => 'Kocaso',
        'KK'  => 'Kodak',
        'KG'  => 'Kogan',
        'KM'  => 'Komu',
        'KO'  => 'Konka',
        'KW'  => 'Konrow',
        'KB'  => 'Koobee',
        '7K'  => 'Koolnee',
        'K9'  => 'Kooper',
        'KP'  => 'KOPO',
        'KR'  => 'Koridy',
        'XK'  => 'Koslam',
        'K2'  => 'KRONO',
        'KE'  => 'Krüger&Matz',
        '5K'  => 'KREZ',
        'WK'  => 'KRIP',
        'KH'  => 'KT-Tech',
        'Z6'  => 'KUBO',
        'K8'  => 'Kuliao',
        '8K'  => 'Kult',
        'KU'  => 'Kumai',
        '6K'  => 'Kurio',
        'KY'  => 'Kyocera',
        'KQ'  => 'Kyowon',
        '1K'  => 'Kzen',
        'LQ'  => 'LAIQ',
        'L6'  => 'Land Rover',
        'L2'  => 'Landvo',
        'LA'  => 'Lanix',
        'LA1' => 'Lanin',
        'LK'  => 'Lark',
        'Z3'  => 'Laurus',
        'LV'  => 'Lava',
        'LC'  => 'LCT',
        'L5'  => 'Leagoo',
        'U3'  => 'Leben',
        'LD'  => 'Ledstar',
        'LEE' => 'Leelbox',
        'L1'  => 'LeEco',
        '4B'  => 'Leff',
        'LEG' => 'Legend',
        'L4'  => 'Lemhoov',
        'W9'  => 'LEMFO',
        'LN'  => 'Lenco',
        'LE'  => 'Lenovo',
        'LT'  => 'Leotec',
        'LP'  => 'Le Pan',
        'ZJ'  => 'Leke',
        'L7'  => 'Lephone',
        'LZ'  => 'Lesia',
        'L3'  => 'Lexand',
        'LX'  => 'Lexibook',
        'LG'  => 'LG',
        '39'  => 'Liberton',
        '5L'  => 'Linsar',
        'LF'  => 'Lifemaxx',
        'LI'  => 'Lingwin',
        'LJ'  => 'L-Max',
        'LW'  => 'Linnex',
        'JJ'  => 'Listo',
        'LNM' => 'LNMBBS',
        'LO'  => 'Loewe',
        'YL'  => 'Loview',
        'LOV' => 'Lovme',
        '1L'  => 'Logic',
        'LH'  => 'Logic Instrument',
        'LM'  => 'Logicom',
        'GY'  => 'LOKMAT',
        '0L'  => 'Lumigon',
        'LU'  => 'Lumus',
        'LUM' => 'Lumitel',
        'L9'  => 'Luna',
        'LR'  => 'Luxor',
        'LY'  => 'LYF',
        'LL'  => 'Leader Phone',
        'QL'  => 'LT Mobile',
        'MQ'  => 'M.T.T.',
        'MN'  => 'M4tel',
        'XM'  => 'Macoox',
        '92'  => 'MAC AUDIO',
        'MJ'  => 'Majestic',
        'FQ'  => 'Mafe',
        '6Y'  => 'Magicsee',
        '23'  => 'Magnus',
        'NH'  => 'Manhattan',
        'MAN' => 'Mango',
        '5M'  => 'Mann',
        'MA'  => 'Manta Multimedia',
        'Z0'  => 'Mantra',
        'J4'  => 'Mara',
        'MAR' => 'Marshal',
        '8Y'  => 'Massgo',
        '2M'  => 'Masstel',
        '3X'  => 'Mastertech',
        '50'  => 'Matrix',
        '7M'  => 'Maxcom',
        'ZM'  => 'Maximus',
        '6X'  => 'Maxtron',
        '0D'  => 'MAXVI',
        'XZ'  => 'MAXX',
        'MW'  => 'Maxwest',
        'M0'  => 'Maze',
        'YM'  => 'Maze Speed',
        '87'  => 'Malata',
        '28'  => 'MBOX',
        'FK'  => 'MBI',
        '3D'  => 'MDC Store',
        '1Y'  => 'MDTV',
        '09'  => 'meanIT',
        'M3'  => 'Mecer',
        'M3M' => 'M3 Mobile',
        '0M'  => 'Mecool',
        'MC'  => 'Mediacom',
        'MK'  => 'MediaTek',
        'MD'  => 'Medion',
        'M2'  => 'MEEG',
        'MP'  => 'MegaFon',
        'X0'  => 'mPhone',
        '3M'  => 'Meitu',
        'M1'  => 'Meizu',
        '0E'  => 'Melrose',
        'MU'  => 'Memup',
        'ME'  => 'Metz',
        'MX'  => 'MEU',
        'MI'  => 'MicroMax',
        'MS'  => 'Microsoft',
        '6Q'  => 'Microtech',
        '1X'  => 'Minix',
        'OM'  => 'Mintt',
        'MO'  => 'Mio',
        'X7'  => 'Mione',
        'M7'  => 'Miray',
        '8M'  => 'Mito',
        'MT'  => 'Mitsubishi',
        '0Y'  => 'Mitsui',
        'M5'  => 'MIXC',
        '2D'  => 'MIVO',
        '1Z'  => 'MiXzo',
        'ML'  => 'MLLED',
        'LS'  => 'MLS',
        '5H'  => 'MMI',
        '4M'  => 'Mobicel',
        'M6'  => 'Mobiistar',
        'MH'  => 'Mobiola',
        'MB'  => 'Mobistel',
        'ID'  => 'MobiIoT',
        '6W'  => 'MobiWire',
        '9M'  => 'Mobo',
        'M4'  => 'Modecom',
        'MF'  => 'Mofut',
        'MR'  => 'Motorola',
        'MV'  => 'Movic',
        'MM'  => 'Mpman',
        'MZ'  => 'MSI',
        '3R'  => 'MStar',
        'M9'  => 'MTC',
        'N4'  => 'MTN',
        '72'  => 'M-Tech',
        '9H'  => 'M-Horse',
        '1R'  => 'Multilaser',
        '1M'  => 'MYFON',
        'MY'  => 'MyPhone',
        '51'  => 'Myros',
        'M8'  => 'Myria',
        '6M'  => 'Mystery',
        '3T'  => 'MyTab',
        'MG'  => 'MyWigo',
        'J3'  => 'Mymaga',
        'MYM' => 'MyMobile',
        '07'  => 'MyGica',
        'NEO' => 'neoCore',
        '08'  => 'Nabi',
        'N7'  => 'National',
        'NC'  => 'Navcity',
        '6N'  => 'Navitech',
        '7V'  => 'Navitel',
        'N3'  => 'Navon',
        '7R'  => 'NavRoad',
        'NAS' => 'NASCO',
        'NP'  => 'Naomi Phone',
        'NE'  => 'NEC',
        '8N'  => 'Necnot',
        'NF'  => 'Neffos',
        '9X'  => 'Neo',
        '1N'  => 'Neomi',
        '7Q'  => 'Neon IQ',
        '8F'  => 'Neolix',
        'NA'  => 'Netgear',
        'NU'  => 'NeuImage',
        'NW'  => 'Newgen',
        'N9'  => 'Newland',
        '0N'  => 'Newman',
        'NS'  => 'NewsMy',
        'ND'  => 'Newsday',
        'HB'  => 'New Balance',
        'BRI' => 'New Bridge',
        'XB'  => 'NEXBOX',
        'NX'  => 'Nexian',
        '7X'  => 'Nexa',
        'N8'  => 'NEXON',
        'N2'  => 'Nextbit',
        'NT'  => 'NextBook',
        'NTT' => 'NTT West',
        '4N'  => 'NextTab',
        'NEX' => 'NEXT',
        'NJO' => 'nJoy',
        'NG'  => 'NGM',
        'NZ'  => 'NG Optics',
        'NN'  => 'Nikon',
        'NI'  => 'Nintendo',
        'NIN' => 'NINETEC',
        'N5'  => 'NOA',
        'N1'  => 'Noain',
        'N6'  => 'Nobby',
        'NOV' => 'Novey',
        '57'  => 'Nubia',
        'JN'  => 'NOBUX',
        'NB'  => 'Noblex',
        'OG'  => 'NOGA',
        'NK'  => 'Nokia',
        'NM'  => 'Nomi',
        '2N'  => 'Nomu',
        '6H'  => 'Noontec',
        'NR'  => 'Nordmende',
        '7N'  => 'NorthTech',
        'NOT' => 'Nothing Phone',
        '5N'  => 'Nos',
        'NO'  => 'Nous',
        'NQ'  => 'Novex',
        'NJ'  => 'NuAns',
        'NL'  => 'NUU Mobile',
        'N0'  => 'Nuvo',
        'NV'  => 'Nvidia',
        'NY'  => 'NYX Mobile',
        'O3'  => 'O+',
        'OT'  => 'O2',
        'O7'  => 'Oale',
        'OC'  => 'OASYS',
        'OB'  => 'Obi',
        'OQ'  => 'Meta',
        'O1'  => 'Odys',
        'ODP' => 'Odotpad',
        'O9'  => 'Ok',
        'OA'  => 'Okapia',
        'OJ'  => 'Ookee',
        'OD'  => 'Onda',
        'ON'  => 'OnePlus',
        'ONC' => 'OneClick',
        'OX'  => 'Onix',
        '3O'  => 'ONYX BOOX',
        'O4'  => 'ONN',
        '9Q'  => 'Onkyo',
        '2O'  => 'OpelMobile',
        'OH'  => 'Openbox',
        '7Y'  => 'Obabox',
        'OP'  => 'OPPO',
        'OO'  => 'Opsson',
        'OPT' => 'Optoma',
        'OR'  => 'Orange',
        'O5'  => 'Orbic',
        'Y6'  => 'Orbita',
        'ORB' => 'Orbsmart',
        'OS'  => 'Ordissimo',
        '8O'  => 'Orion',
        'OTT' => 'OTTO',
        'OK'  => 'Ouki',
        '0O'  => 'OINOM',
        'QK'  => 'OKWU',
        'QQ'  => 'OMIX',
        '56'  => 'OKSI',
        'OE'  => 'Oukitel',
        'OU'  => 'OUYA',
        'JB'  => 'OUJIA',
        'OV'  => 'Overmax',
        '30'  => 'Ovvi',
        'O2'  => 'Owwo',
        'OY'  => 'Oysters',
        'QF'  => 'OYSIN',
        'O6'  => 'Oyyu',
        'OZ'  => 'OzoneHD',
        'OLL' => 'Ollee',
        '7P'  => 'P-UP',
        'YP'  => 'Paladin',
        'PM'  => 'Palm',
        'PN'  => 'Panacom',
        'PA'  => 'Panasonic',
        'PT'  => 'Pantech',
        '94'  => 'Packard Bell',
        'H9'  => 'Parrot Mobile',
        'PAR' => 'Partner Mobile',
        'PAP' => 'PAPYRE',
        'PB'  => 'PCBOX',
        'PC'  => 'PCD',
        'PD'  => 'PCD Argentina',
        'PE'  => 'PEAQ',
        'PG'  => 'Pentagram',
        'PQ'  => 'Pendoo',
        '93'  => 'Perfeo',
        '8J'  => 'Pelitt',
        '1P'  => 'Phicomm',
        '4P'  => 'Philco',
        'PH'  => 'Philips',
        '5P'  => 'Phonemax',
        'PO'  => 'phoneOne',
        'PI'  => 'Pioneer',
        'PIC' => 'Pioneer Computers',
        'PJ'  => 'PiPO',
        '8P'  => 'Pixelphone',
        '9O'  => 'Pixela',
        'PX'  => 'Pixus',
        'QP'  => 'Pico',
        'PIR' => 'PIRANHA',
        'PIN' => 'PINE',
        '9P'  => 'Planet Computers',
        'PY'  => 'Ployer',
        'P4'  => 'Plum',
        'PLU' => 'PlusStyle',
        '22'  => 'Pluzz',
        'P8'  => 'PocketBook',
        '0P'  => 'POCO',
        'FH'  => 'Point Mobile',
        'PV'  => 'Point of View',
        'PL'  => 'Polaroid',
        'Q6'  => 'Polar',
        '97'  => 'PolarLine',
        'PP'  => 'PolyPad',
        'P5'  => 'Polytron',
        'P2'  => 'Pomp',
        'P0'  => 'Poppox',
        '0X'  => 'POPTEL',
        'PS'  => 'Positivo',
        '3P'  => 'Positivo BGH',
        '3F'  => 'Porsche',
        'P3'  => 'PPTV',
        'FP'  => 'Premio',
        'PR'  => 'Prestigio',
        'P9'  => 'Primepad',
        '6P'  => 'Primux',
        '2P'  => 'Prixton',
        'PRI' => 'Pritom',
        'PF'  => 'PROFiLO',
        'P6'  => 'Proline',
        '5O'  => 'Prology',
        'P1'  => 'ProScan',
        'P7'  => 'Protruly',
        'R0'  => 'ProVision',
        '7O'  => 'Polestar',
        'PU'  => 'PULID',
        'UP'  => 'Purism',
        'QFX' => 'QFX',
        'Q7'  => 'Q-Box',
        'QH'  => 'Q-Touch',
        'QB'  => 'Q.Bell',
        'QI'  => 'Qilive',
        'QM'  => 'QMobile',
        'QT'  => 'Qtek',
        'Q9'  => 'QTECH',
        'QA'  => 'Quantum',
        'QUE' => 'Quest',
        'QU'  => 'Quechua',
        'QUI' => 'Quipus',
        'QO'  => 'Qumo',
        'UQ'  => 'Qubo',
        'YQ'  => 'QLink',
        'QY'  => 'Qnet Mobile',
        'WJ'  => 'Qware',
        'R2'  => 'R-TV',
        'RA'  => 'Ramos',
        '0R'  => 'Raspberry',
        'R9'  => 'Ravoz',
        'RZ'  => 'Razer',
        '95'  => 'Rakuten',
        'RAY' => 'Raylandz',
        'RC'  => 'RCA Tablets',
        '2R'  => 'Reach',
        'RB'  => 'Readboy',
        'RE'  => 'Realme',
        'RE1' => 'Redbean',
        'R8'  => 'RED',
        'REW' => 'Redway',
        '6F'  => 'Redfox',
        'RD'  => 'Reeder',
        'Z9'  => 'REGAL',
        'RH'  => 'Remdun',
        'RP'  => 'Revo',
        '8R'  => 'Retroid Pocket',
        'RIC' => 'Ricoh',
        'RI'  => 'Rikomagic',
        'RM'  => 'RIM',
        'RN'  => 'Rinno',
        'RX'  => 'Ritmix',
        'R7'  => 'Ritzviva',
        'RV'  => 'Riviera',
        '6R'  => 'Rivo',
        'RIZ' => 'Rizzen',
        'RR'  => 'Roadrover',
        'QR'  => 'ROADMAX',
        'R1'  => 'Rokit',
        'RK'  => 'Roku',
        'R3'  => 'Rombica',
        'R5'  => 'Ross&Moor',
        'RO'  => 'Rover',
        'R6'  => 'RoverPad',
        'RQ'  => 'RoyQueen',
        'RJ'  => 'Royole',
        'RT'  => 'RT Project',
        'RG'  => 'RugGear',
        'RU'  => 'Runbo',
        'RL'  => 'Ruio',
        'RY'  => 'Ryte',
        'X5'  => 'Saba',
        '8L'  => 'S-TELL',
        '4O'  => 'S2Tel',
        '89'  => 'Seatel',
        'Y7'  => 'Saiet',
        'X1'  => 'Safaricom',
        'SG'  => 'Sagem',
        '4L'  => 'Salora',
        'SA'  => 'Samsung',
        'SNA' => 'SNAMI',
        'S0'  => 'Sanei',
        '12'  => 'Sansui',
        'SQ'  => 'Santin',
        'SY'  => 'Sanyo',
        'S9'  => 'Savio',
        'Y4'  => 'SCBC',
        'CZ'  => 'Schneider',
        'SCO' => 'Scosmos',
        'ZG'  => 'Schok',
        'G8'  => 'SEG',
        'SD'  => 'Sega',
        '0U'  => 'Selecline',
        '9G'  => 'Selenga',
        'SV'  => 'Selevision',
        'SL'  => 'Selfix',
        '0S'  => 'SEMP TCL',
        'S1'  => 'Sencor',
        'SN'  => 'Sendo',
        '01'  => 'Senkatel',
        'S6'  => 'Senseit',
        'EW'  => 'Senwa',
        '24'  => 'Seeken',
        '61'  => 'Seuic',
        'SX'  => 'SFR',
        'SH'  => 'Sharp',
        'JU'  => 'Shanling',
        '7S'  => 'Shift Phones',
        '78'  => 'Shivaki',
        'RS'  => 'Shtrikh-M',
        '3S'  => 'Shuttle',
        '13'  => 'Sico',
        'SI'  => 'Siemens',
        '1S'  => 'Sigma',
        '70'  => 'Silelis',
        'SJ'  => 'Silent Circle',
        '10'  => 'Simbans',
        '98'  => 'Simply',
        '52'  => 'Singtech',
        '31'  => 'Siragon',
        '83'  => 'Sirin Labs',
        '5Z'  => 'SK Broadband',
        'GK'  => 'SKG',
        'SW'  => 'Sky',
        'SK'  => 'Skyworth',
        '14'  => 'Smadl',
        '19'  => 'Smailo',
        'SR'  => 'Smart Electronic',
        'SMA' => 'Smart Kassel',
        '49'  => 'Smart',
        '47'  => 'SmartBook',
        '3B'  => 'Smartab',
        '80'  => 'SMARTEC',
        'SC'  => 'Smartfren',
        'S7'  => 'Smartisan',
        'JR'  => 'Sylvania',
        '3Y'  => 'Smarty',
        'HH'  => 'Smooth Mobile',
        '1Q'  => 'Smotreshka',
        'SF'  => 'Softbank',
        '9L'  => 'SOLE',
        'JL'  => 'SOLO',
        'SOD' => 'Soda',
        '16'  => 'Solone',
        'OI'  => 'Sonim',
        'SO'  => 'Sony',
        'SE'  => 'Sony Ericsson',
        'X2'  => 'Soundmax',
        '8S'  => 'Soyes',
        '77'  => 'SONOS',
        '68'  => 'Soho Style',
        'PK'  => 'Spark',
        'FS'  => 'SPC',
        '6S'  => 'Spectrum',
        '43'  => 'Spectralink',
        'SP'  => 'Spice',
        '84'  => 'Sprint',
        'QS'  => 'SQOOL',
        'S4'  => 'Star',
        'OL'  => 'Starlight',
        '18'  => 'Starmobile',
        '2S'  => 'Starway',
        '45'  => 'Starwind',
        'SB'  => 'STF Mobile',
        'S8'  => 'STK',
        'GQ'  => 'STG Telecom',
        'S2'  => 'Stonex',
        'ST'  => 'Storex',
        'STR' => 'Stream',
        '71'  => 'StrawBerry',
        '96'  => 'STRONG',
        '69'  => 'Stylo',
        '9S'  => 'Sugar',
        '06'  => 'Subor',
        'SZ'  => 'Sumvision',
        '0H'  => 'Sunstech',
        'S3'  => 'SunVan',
        '5S'  => 'Sunvell',
        '5Y'  => 'Sunny',
        'W8'  => 'SUNWIND',
        'SU'  => 'SuperSonic',
        '79'  => 'SuperTab',
        'S5'  => 'Supra',
        'ZS'  => 'Suzuki',
        '2J'  => 'Sunmi',
        '0W'  => 'Swipe',
        'SS'  => 'SWISSMOBILITY',
        '1W'  => 'Swisstone',
        'W7'  => 'SWTV',
        'SM'  => 'Symphony',
        '4S'  => 'Syrox',
        'TM'  => 'T-Mobile',
        'T96' => 'T96',
        'TK'  => 'Takara',
        '73'  => 'Tambo',
        '9N'  => 'Tanix',
        'U5'  => 'Taiga System',
        'TAL' => 'Talius',
        '7G'  => 'TAG Tech',
        'T5'  => 'TB Touch',
        'TC'  => 'TCL',
        'T0'  => 'TD Systems',
        'YY'  => 'TD Tech',
        'H4'  => 'Technicolor',
        'TEA' => 'TeachTouch',
        'Z5'  => 'Technika',
        'TX'  => 'TechniSat',
        'TT'  => 'TechnoTrend',
        'TP'  => 'TechPad',
        '9E'  => 'Techwood',
        '7F'  => 'Technopc',
        'T7'  => 'Teclast',
        'TB'  => 'Tecno Mobile',
        '91'  => 'TEENO',
        '2L'  => 'Tele2',
        'TL'  => 'Telefunken',
        'TG'  => 'Telego',
        'T2'  => 'Telenor',
        'TE'  => 'Telit',
        '65'  => 'Telia',
        'TEL' => 'Telma',
        'PW'  => 'Telpo',
        'TER' => 'Teracube',
        'TD'  => 'Tesco',
        'TA'  => 'Tesla',
        '9T'  => 'Tetratab',
        'TZ'  => 'teXet',
        '29'  => 'Teknosa',
        'JZ'  => 'TJC',
        'JC'  => 'TENPLUS',
        'T4'  => 'ThL',
        'TN'  => 'Thomson',
        'O0'  => 'Thuraya',
        'TI'  => 'TIANYU',
        'JY'  => 'Tigers',
        '8T'  => 'Time2',
        'TQ'  => 'Timovi',
        'TIM' => 'TIMvision',
        '2T'  => 'Tinai',
        'TF'  => 'Tinmo',
        'TH'  => 'TiPhone',
        'YV'  => 'TiVo',
        'TIB' => 'Tibuta',
        'Y3'  => 'TOKYO',
        'TOX' => 'TOX',
        'T1'  => 'Tolino',
        '0T'  => 'Tone',
        'TY'  => 'Tooky',
        'T9'  => 'Top House',
        'DK'  => 'Topelotek',
        '42'  => 'Topway',
        'TO'  => 'Toplux',
        'TOD' => 'TOPDON',
        '7T'  => 'Torex',
        'TOR' => 'Torque',
        '6O'  => 'TOSCIDO',
        'TO1' => 'Topsion',
        'TS'  => 'Toshiba',
        'T8'  => 'Touchmate',
        'TOU' => 'Touch Plus',
        '5R'  => 'Transpeed',
        'T6'  => 'TrekStor',
        'T3'  => 'Trevi',
        'TJ'  => 'Trifone',
        'Q5'  => 'Trident',
        '4T'  => 'Tronsmart',
        '11'  => 'True',
        'JT'  => 'True Slim',
        'J1'  => 'Trio',
        '5C'  => 'TTEC',
        'TTK' => 'TTK-TV',
        'TU'  => 'Tunisie Telecom',
        '1T'  => 'Turbo',
        'TR'  => 'Turbo-X',
        '5X'  => 'TurboPad',
        '5T'  => 'TurboKids',
        'UR'  => 'Turkcell',
        '4U'  => 'TuCEL',
        '2U'  => 'Türk Telekom',
        'TV'  => 'TVC',
        'TW'  => 'TWM',
        'Z1'  => 'TWZ',
        '6T'  => 'Twoe',
        '15'  => 'Tymes',
        'UC'  => 'U.S. Cellular',
        'UG'  => 'Ugoos',
        'U1'  => 'Uhans',
        'UH'  => 'Uhappy',
        'UL'  => 'Ulefone',
        'UA'  => 'Umax',
        'UM'  => 'UMIDIGI',
        'UZ'  => 'Unihertz',
        '3Z'  => 'UZ Mobile',
        'UX'  => 'Unimax',
        'US'  => 'Uniscope',
        'UNI' => 'Unistrong',
        'U2'  => 'UNIWA',
        'UO'  => 'Unnecto',
        'UNN' => 'Unnion Technologies',
        'UU'  => 'Unonu',
        'UN'  => 'Unowhy',
        'UY'  => 'UNNO',
        'UNB' => 'Unblock Tech',
        'UK'  => 'UTOK',
        '3U'  => 'IUNI',
        'UT'  => 'UTStarcom',
        '6U'  => 'UTime',
        '9U'  => 'Urovo',
        'UW'  => 'U-Magic',
        '5V'  => 'VAIO',
        'WV'  => 'VAVA',
        'VA'  => 'Vastking',
        'VP'  => 'Vargo',
        'VC'  => 'Vankyo',
        'VAL' => 'VALEM',
        'VB'  => 'VC',
        'VN'  => 'Venso',
        'VEN' => 'Venstar',
        'UV'  => 'Venturer',
        'VQ'  => 'Vega',
        'WC'  => 'VEON',
        '4V'  => 'Verico',
        'V4'  => 'Verizon',
        'VR'  => 'Vernee',
        'VX'  => 'Vertex',
        'VE'  => 'Vertu',
        'VL'  => 'Verykool',
        'QV'  => 'Verssed',
        'V8'  => 'Vesta',
        'VT'  => 'Vestel',
        '48'  => 'Vexia',
        'V6'  => 'VGO TEL',
        'QJ'  => 'VDVD',
        'VIC' => 'Victurio',
        'VD'  => 'Videocon',
        'VW'  => 'Videoweb',
        'VS'  => 'ViewSonic',
        'V7'  => 'Vinga',
        'V3'  => 'Vinsoc',
        'XD'  => 'Vinabox',
        'FV'  => 'Vios',
        '0V'  => 'Vipro',
        'ZV'  => 'Virzo',
        'VI'  => 'Vitelcom',
        '8V'  => 'Viumee',
        'V5'  => 'Vivax',
        'VV'  => 'Vivo',
        '6V'  => 'VIWA',
        'VID' => 'VIDA',
        'VZ'  => 'Vizio',
        '9V'  => 'Vision Touch',
        'VK'  => 'VK Mobile',
        'JM'  => 'v-mobile',
        'VHO' => 'V-HOPE',
        'V0'  => 'VKworld',
        'VM'  => 'Vodacom',
        'VF'  => 'Vodafone',
        '7W'  => 'VOGA',
        'V2'  => 'Vonino',
        '1V'  => 'Vontar',
        'VG'  => 'Vorago',
        '2V'  => 'Vorke',
        '8U'  => 'Vorcom',
        'JW'  => 'Vortex',
        'V1'  => 'Voto',
        'Z7'  => 'VOX',
        'VO'  => 'Voxtel',
        'VY'  => 'Voyo',
        'VOL' => 'Völfen',
        'VH'  => 'Vsmart',
        'V9'  => 'Vsun',
        'VU'  => 'Vulcan',
        '3V'  => 'VVETIME',
        'ZC'  => 'VUCATIMES',
        'VUE' => 'Vue Micro',
        'WA'  => 'Walton',
        'WM'  => 'Weimei',
        'WE'  => 'WellcoM',
        'W6'  => 'WELLINGTON',
        'WD'  => 'Western Digital',
        'WT'  => 'Westpoint',
        'WAN' => 'Wanmukang',
        'WY'  => 'Wexler',
        '3W'  => 'WE',
        'WEE' => 'Weelikeit',
        'WP'  => 'Wieppo',
        'W2'  => 'Wigor',
        'WI'  => 'Wiko',
        'WF'  => 'Wileyfox',
        'WS'  => 'Winds',
        'WN'  => 'Wink',
        '9W'  => 'Winmax',
        'W5'  => 'Winnovo',
        'WU'  => 'Wintouch',
        'W0'  => 'Wiseasy',
        '2W'  => 'Wizz',
        'W4'  => 'WIWA',
        'WIZ' => 'WizarPos',
        'WL'  => 'Wolder',
        'WG'  => 'Wolfgang',
        'WQ'  => 'Wolki',
        'WO'  => 'Wonu',
        'W1'  => 'Woo',
        'WR'  => 'Wortmann',
        'WX'  => 'Woxter',
        'XQ'  => 'X-AGE',
        'X3'  => 'X-BO',
        'XT'  => 'X-TIGI',
        'XV'  => 'X-View',
        'X4'  => 'X.Vision',
        'X88' => 'X88',
        'X96' => 'X96',
        '96Q' => 'X96Q',
        'XG'  => 'Xgody',
        'QX'  => 'XGIMI',
        'XL'  => 'Xiaolajiao',
        'XI'  => 'Xiaomi',
        'XW'  => 'Xiaodu',
        'XN'  => 'Xion',
        'XO'  => 'Xolo',
        'XR'  => 'Xoro',
        'XS'  => 'Xshitou',
        '4X'  => 'Xtouch',
        'X8'  => 'Xtratech',
        'YD'  => 'Yandex',
        'YA'  => 'Yarvik',
        'Y2'  => 'Yes',
        'YE'  => 'Yezz',
        'YG'  => 'YEPEN',
        'YK'  => 'Yoka TV',
        'YO'  => 'Yota',
        'YOO' => 'Yooz',
        'YT'  => 'Ytone',
        'Y9'  => 'YOTOPT',
        'Y1'  => 'Yu',
        'YF'  => 'YU Fly',
        'Y0'  => 'YUHO',
        'YN'  => 'Yuno',
        'YUN' => 'YUNDOO',
        'YUM' => 'YUMKEM',
        'YU'  => 'Yuandao',
        'YS'  => 'Yusun',
        'YJ'  => 'YASIN',
        'YX'  => 'Yxtel',
        '0Z'  => 'Zatec',
        '2Z'  => 'Zaith',
        'ZEA' => 'Zealot',
        'PZ'  => 'Zebra',
        'ZE'  => 'Zeemi',
        'WZ'  => 'Zeeker',
        'ZN'  => 'Zen',
        'ZK'  => 'Zenek',
        'ZL'  => 'Zentality',
        'ZF'  => 'Zfiner',
        'ZI'  => 'Zidoo',
        'FZ'  => 'ZIFRO',
        'ZX'  => 'Ziox',
        'ZIK' => 'ZIK',
        'ZIN' => 'Zinox',
        'ZO'  => 'Zonda',
        'ZW'  => 'Zonko',
        'ZP'  => 'Zopo',
        'ZT'  => 'ZTE',
        'ZU'  => 'Zuum',
        'ZY'  => 'Zync',
        'ZR'  => 'Zyrex',
        'ZQ'  => 'ZYQ',
        'Z4'  => 'ZH&K',
        'OW'  => 'öwn',
        // legacy brands, might be removed in future versions
        'WB'  => 'Web TV',
        'XX'  => 'Unknown',
    ];

    /**
     * Returns the device type represented by one of the DEVICE_TYPE_* constants
     *
     * @return int|null
     */
    public function getDeviceType(): ?int
    {
        return $this->deviceType;
    }

    /**
     * Returns available device types
     *
     * @see $deviceTypes
     *
     * @return array
     */
    public static function getAvailableDeviceTypes(): array
    {
        return self::$deviceTypes;
    }

    /**
     * Returns names of all available device types
     *
     * @return array
     */
    public static function getAvailableDeviceTypeNames(): array
    {
        return \array_keys(self::$deviceTypes);
    }

    /**
     * Returns the name of the given device type
     *
     * @param int $deviceType one of the DEVICE_TYPE_* constants
     *
     * @return mixed
     */
    public static function getDeviceName(int $deviceType)
    {
        return \array_search($deviceType, self::$deviceTypes);
    }

    /**
     * Returns the detected device model
     *
     * @return string
     */
    public function getModel(): string
    {
        return $this->model;
    }

    /**
     * Returns the detected device brand
     *
     * @return string
     */
    public function getBrand(): string
    {
        return $this->brand;
    }

    /**
     * Returns the full brand name for the given short name
     *
     * @param string $brandId short brand name
     *
     * @return string
     */
    public static function getFullName(string $brandId): string
    {
        if (\array_key_exists($brandId, self::$deviceBrands)) {
            return self::$deviceBrands[$brandId];
        }

        return '';
    }

    /**
     * Returns the brand short code for the given name
     *
     * @param string $brand brand name
     *
     * @return string
     *
     * @deprecated since 4.0 - short codes might be removed in next major release
     */
    public static function getShortCode(string $brand): string
    {
        return (string) \array_search($brand, self::$deviceBrands) ?: '';
    }

    /**
     * Sets the useragent to be parsed
     *
     * @param string $userAgent
     */
    public function setUserAgent(string $userAgent): void
    {
        $this->reset();
        parent::setUserAgent($userAgent);
    }

    /**
     * @inheritdoc
     */
    public function parse(): ?array
    {
        $resultClientHint = $this->parseClientHints();
        $deviceModel      = $resultClientHint['model'] ?? '';

        if ('' === $deviceModel && $this->hasDesktopFragment()) {
            return $this->getResult();
        }

        $brand   = '';
        $regexes = $this->getRegexes();

        foreach ($regexes as $brand => $regex) {
            $matches = $this->matchUserAgent($regex['regex']);

            if ($matches) {
                break;
            }
        }

        if (empty($matches)) {
            return $resultClientHint;
        }

        if ('Unknown' !== $brand) {
            if (!\in_array($brand, self::$deviceBrands)) {
                // This Exception should never be thrown. If so a defined brand name is missing in $deviceBrands
                throw new \Exception(\sprintf(
                    "The brand with name '%s' should be listed in deviceBrands array. Tried to parse user agent: %s",
                    $brand,
                    $this->userAgent
                )); // @codeCoverageIgnore
            }

            $this->brand = (string) $brand;
        }

        if (isset($regex['device']) && \array_key_exists($regex['device'], self::$deviceTypes)) {
            $this->deviceType = self::$deviceTypes[$regex['device']];
        }

        $this->model = '';

        if (isset($regex['model'])) {
            $this->model = $this->buildModel($regex['model'], $matches);
        }

        if (isset($regex['models'])) {
            $modelRegex = '';

            foreach ($regex['models'] as $modelRegex) {
                $modelMatches = $this->matchUserAgent($modelRegex['regex']);

                if ($modelMatches) {
                    break;
                }
            }

            if (empty($modelMatches)) {
                return $this->getResult();
            }

            $this->model = $this->buildModel($modelRegex['model'], $modelMatches);

            if (isset($modelRegex['brand']) && \in_array($modelRegex['brand'], self::$deviceBrands)) {
                $this->brand = (string) $modelRegex['brand'];
            }

            if (isset($modelRegex['device']) && \array_key_exists($modelRegex['device'], self::$deviceTypes)) {
                $this->deviceType = self::$deviceTypes[$modelRegex['device']];
            }
        }

        return $this->getResult();
    }

    /**
     * @param string $model
     * @param array  $matches
     *
     * @return string
     */
    protected function buildModel(string $model, array $matches): string
    {
        $model = $this->buildByMatch($model, $matches);

        $model = \str_replace('_', ' ', $model);

        $model = \preg_replace('/ TD$/i', '', $model);

        if ('Build' === $model || empty($model)) {
            return '';
        }

        return \trim($model);
    }

    /**
     * @return array|null
     */
    protected function parseClientHints(): ?array
    {
        if ($this->clientHints && $this->clientHints->getModel()) {
            return [
                'deviceType' => null,
                'model'      => $this->clientHints->getModel(),
                'brand'      => '',
            ];
        }

        return null;
    }

    /**
     * Returns if the parsed UA contains the 'Windows NT;' or 'X11; Linux x86_64' fragments
     *
     * @return bool
     */
    protected function hasDesktopFragment(): bool
    {
        return
            $this->matchUserAgent('(?:Windows (?:NT|IoT)|X11; Linux x86_64)') &&
            !$this->matchUserAgent(' Mozilla/|Andr[o0]id|Tablet|Mobile|iPhone|Windows Phone|ricoh|OculusBrowser') &&
            !$this->matchUserAgent('Lenovo|compatible; MSIE|Trident/|Tesla/|XBOX|FBMD/|ARM; ?([^)]+)');
    }

    /**
     * Resets the stored values
     */
    protected function reset(): void
    {
        $this->deviceType = null;
        $this->model      = '';
        $this->brand      = '';
    }

    /**
     * @return array
     */
    protected function getResult(): array
    {
        return [
            'deviceType' => $this->deviceType,
            'model'      => $this->model,
            'brand'      => $this->brand,
        ];
    }
}
