# frozen_string_literal: true

class DeviceDetector
  class Device < Parser
    # order is relevant for testing with fixtures
    # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/Device/AbstractDeviceParser.php#L59-L74
    DEVICE_NAMES = [
      'desktop',
      'smartphone',
      'tablet',
      'feature phone',
      'console',
      'tv',
      'car browser',
      'smart display',
      'camera',
      'portable media player',
      'phablet',
      'smart speaker',
      'wearable',
      'peripheral'
    ].freeze

    # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/Device/AbstractDeviceParser.php#L83-L1951
    DEVICE_BRANDS = {
      '5E' => '2E',
      '5IV' => '5IVE',
      '2F' => 'F2 Mobile',
      '3Q' => '3Q',
      'J7' => '7 Mobile',
      '2Q' => '3GNET',
      '4G' => '4Good',
      '27' => '3GO',
      '04' => '4ife',
      '36' => '360',
      '88' => '8848',
      '10M' => '10moons',
      '41' => 'A1',
      'AK1' => 'A&K',
      '00' => 'Accent',
      'ACC' => 'Accesstyle',
      'AE' => 'Ace',
      'AC' => 'Acer',
      'ACL' => 'Aceline',
      '3K' => 'Acteck',
      'ACT' => 'actiMirror',
      'A9' => 'Advan',
      'AD' => 'Advance',
      'ADV' => 'Advantage Air',
      '76' => 'Adronix',
      'AF' => 'AfriOne',
      'FY' => 'AFFIX',
      'A3' => 'AGM',
      'AEE' => 'AEEZO',
      'J0' => 'AG Mobile',
      'AJI' => 'Ajib',
      'AZ' => 'Ainol',
      'AIR' => 'Airis',
      'AI' => 'Airness',
      'ARP' => 'Airpha',
      'AT' => 'Airties',
      '7U' => 'Airtel',
      'AIT' => 'AirTouch',
      'U0' => 'AIRON',
      '0A' => 'AIS',
      'AW' => 'Aiwa',
      '85' => 'Aiuto',
      'U7' => 'AIDATA',
      'AK' => 'Akai',
      'Q3' => 'AKIRA',
      '1A' => 'Alba',
      'AL' => 'Alcatel',
      'AL0' => 'Alienware',
      '20' => 'Alcor',
      'XY' => 'Alps',
      'XYA' => 'XY Auto',
      'AAU' => 'AAUW',
      '7L' => 'ALDI NORD',
      '6L' => 'ALDI SÜD',
      '3L' => 'Alfawise',
      '4A' => 'Aligator',
      'AA' => 'AllCall',
      '3A' => 'AllDocube',
      'A2' => 'Allview',
      'ALI' => 'ALLINmobile',
      'A7' => 'Allwinner',
      'A1' => 'Altech UEC',
      '66' => 'Altice',
      'ALM' => 'Altimo',
      'A5' => 'altron',
      'ALT' => 'Altus',
      'KN' => 'Amazon',
      'AMZ' => 'Amazon Basics',
      'AMA' => 'AMA',
      'AG' => 'AMGOO',
      '9A' => 'Amigoo',
      'AO' => 'Amoi',
      '3J' => 'Amino',
      '54' => 'AMCV',
      '60' => 'Andowl',
      'ANX' => 'ANXONIT',
      'ANC' => 'ANBERNIC',
      '6J' => 'Angelcare',
      'ANG' => 'AngelTech',
      '7A' => 'Anry',
      'A0' => 'ANS',
      '74' => 'Anker',
      '3N' => 'Aoson',
      'O8' => 'AOC',
      'J2' => 'AOYODKG',
      '55' => 'AOpen',
      'RW' => 'Aoro',
      '9Y' => 'Aocos',
      'AOW' => 'Aocwei',
      'AP' => 'Apple',
      'ARC' => 'Arçelik',
      'AR' => 'Archos',
      'AB' => 'Arian Space',
      'ARI' => 'Arival',
      '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',
      'ASS' => 'ASSE',
      'AU' => 'Asus',
      '6A' => 'AT&T',
      'ATH' => 'Athesi',
      'ATE' => 'Atlantic Electrics',
      '5Q' => 'Atmaca Elektronik',
      'YH' => 'ATMAN',
      '2A' => 'Atom',
      'ATO' => 'ATOL',
      'Z2' => 'Atvio',
      'ATI' => 'Attila',
      'AX' => 'Audiovox',
      'AJ' => 'AURIS',
      'YZ' => 'Autan',
      'AUP' => 'AUPO',
      'ZA' => 'Avenzo',
      'AH' => 'AVH',
      'AV' => 'Avvio',
      'AVA' => 'Avaya',
      'AXE' => 'AXEN',
      'AY' => 'Axxion',
      'AXX' => 'AXXA',
      'AYA' => 'AYA',
      'YR' => 'AYYA',
      'XA' => 'Axioo',
      'AM' => 'Azumi Mobile',
      'AZE' => 'Azeyou',
      'WW' => 'Awow',
      'AWO' => 'AWOX',
      'XU' => 'AUX',
      'BAC' => 'Backcell',
      'BFF' => 'BAFF',
      'BO' => 'BangOlufsen',
      'BN' => 'Barnes & Noble',
      'BAR' => 'BARTEC',
      'BAS' => 'BASE',
      'BAU' => 'BAUHN',
      'BB' => 'BBK',
      '0B' => 'BB Mobile',
      'B6' => 'BDF',
      'QD' => 'BDQ',
      '8Z' => 'BDsharing',
      'BEF' => 'Beafon',
      'BE' => 'Becker',
      'B5' => 'Beeline',
      'B0' => 'Beelink',
      'BL' => 'Beetel',
      'BEK' => 'Beko',
      '2X' => 'Benco',
      'BQ' => 'BenQ',
      'BS' => 'BenQ-Siemens',
      '4Y' => 'Benzo',
      'XJ' => 'Benesse',
      'BEN' => 'BenWee',
      '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',
      'BLK' => 'Black Box',
      'BF' => 'Black Fox',
      'BPC' => 'Blackpcs',
      'B2' => 'Blackview',
      '2Y' => 'b2m',
      'BP' => 'Blaupunkt',
      'BU' => 'Blu',
      'BUS' => 'BluSlate',
      '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',
      'BMX' => 'BMXC',
      'B9' => 'Bobarry',
      'B4' => 'bogo',
      'BOL' => 'Bolva',
      'BW' => 'Boway',
      'BOO' => 'Boost',
      'BOK' => 'Bookeen',
      'BOT' => 'Botech',
      'BX' => 'bq',
      '8B' => 'Brandt',
      'BRA' => 'BrandCode',
      'BV' => 'Bravis',
      'BRV' => 'BRAVE',
      'BRG' => 'Brigmton',
      'BR' => 'Brondi',
      'XF' => 'BROR',
      'BJ' => 'BrightSign',
      'B1' => 'Bush',
      '4Q' => 'Bundy',
      'Y8' => 'Bubblegum',
      'BMW' => 'BMW',
      'C9' => 'CAGI',
      'CAD' => 'CADENA',
      'CT' => 'Capitel',
      'G3' => 'CG Mobile',
      '37' => 'CGV',
      'CP' => 'Captiva',
      'CF' => 'Carrefour',
      'CA1' => 'Carbon Mobile',
      'CS' => 'Casio',
      'R4' => 'Casper',
      'CA' => 'Cat',
      'BC' => 'Camfone',
      'CJ' => 'Cavion',
      'CAN' => 'Canal+',
      '4D' => 'Canal Digital',
      'CNG' => 'Canguro',
      'CNT' => 'CCIT',
      'CEC' => 'Cecotec',
      'CEP' => 'CEPTER',
      'CEI' => 'Ceibal',
      '02' => 'Cell-C',
      'CEL' => 'Cellacom',
      '34' => 'CellAllure',
      '7C' => 'Celcus',
      'CE' => 'Celkon',
      'CG' => 'Cellution',
      '62' => 'Centric',
      'CEN' => 'CENTEK',
      'C2' => 'Changhong',
      'CHA' => 'Chainway',
      'CHG' => 'ChiliGreen',
      'CH' => 'Cherry Mobile',
      'C3' => 'China Mobile',
      'U9' => 'China Telecom',
      'CI' => 'Chico Mobile',
      'CIA' => 'C Idea',
      'CIP' => 'CipherLab',
      'CIT' => 'Citycall',
      '1C' => 'Chuwi',
      'L8' => 'Clarmin',
      '25' => 'Claresta',
      'CLA' => 'CLAYTON',
      'CLT' => 'Clovertek',
      '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',
      'CON' => 'Conceptum',
      'CED' => 'Continental Edison',
      '9C' => 'Colors',
      'CO' => 'Coolpad',
      'COO' => 'Coopers',
      'CDE' => 'COOD-E',
      '4R' => 'CORN',
      '1O' => 'Cosmote',
      'CW' => 'Cowon',
      '75' => 'Covia',
      'QG' => 'COYOTE',
      'CKK' => 'CKK Mobile',
      'YW' => 'ClearPHONE',
      '33' => 'Clementoni',
      'CR' => 'CreNova',
      'CX' => 'Crescent',
      'CK' => 'Cricket',
      'CM' => 'Crius Mea',
      '0C' => 'Crony',
      'C1' => 'Crosscall',
      '4W' => 'Crown',
      'CTR' => 'Ctroniq',
      'CU' => 'Cube',
      'CB' => 'CUBOT',
      'CUI' => 'Cuiud',
      'CV' => 'CVTE',
      'CWO' => 'Cwowdefu',
      'C4' => 'Cyrus',
      'D5' => 'Daewoo',
      'DA' => 'Danew',
      'DAN' => 'Dany',
      'DA1' => 'DangcapHD',
      'DAR' => 'Daria',
      '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',
      'DSD' => 'DSDevices',
      'DSI' => 'DSIC',
      'DW' => 'DeWalt',
      'DX' => 'DEXP',
      'DEY' => 'DEYI',
      'DEN' => 'Denali',
      'DEA' => 'DEALDIG',
      '8D' => 'DF',
      'DGT' => 'DGTEC',
      'DG' => 'Dialog',
      'DIA' => 'DIALN',
      'DI' => 'Dicam',
      'D4' => 'Digi',
      'D3' => 'Digicel',
      'DDG' => 'Digidragon',
      'DH' => 'Digihome',
      'DD' => 'Digiland',
      'DIJ' => 'DIJITSU',
      'DIG' => 'Digit4G',
      'DIC' => 'DIGICOM',
      'Q0' => 'DIGIFORS',
      'DIK' => 'DIKOM',
      'DQ' => 'DISH',
      'DIS' => 'Disney',
      '9D' => 'Ditecma',
      'D2' => 'Digma',
      '1D' => 'Diva',
      'DIV' => 'DiverMax',
      'D6' => 'Divisat',
      'DIO' => 'DIORA',
      'X6' => 'DIXON',
      'DIM' => 'DIMO',
      '5D' => 'DING DING',
      'DIN' => 'Dinax',
      'DNA' => 'Dinalink',
      'DM' => 'DMM',
      'DN' => 'DNS',
      'DC' => 'DoCoMo',
      'DF' => 'Doffler',
      'D9' => 'Dolamee',
      'DO' => 'Doogee',
      'D0' => 'Doopro',
      'DV' => 'Doov',
      'DOM' => 'Dom.ru',
      'DP' => 'Dopod',
      'DPA' => 'DPA',
      'JQ' => 'Doppio',
      'DR' => 'Doro',
      'ZD' => 'DORLAND',
      'DRO' => 'Droidlogic',
      'D8' => 'Droxio',
      'DJ' => 'Dragon Touch',
      'DRA' => 'DRAGON',
      'DY' => 'Dreamgate',
      'DRE' => 'DreamTab',
      'DR1' => 'DreamStar',
      'DTA' => 'Dtac',
      'DU' => 'Dune HD',
      'UD' => 'DUNNS Mobile',
      'DUU' => 'Duubee',
      'DUR' => 'Durabook',
      'DYO' => 'Dyon',
      'DTE' => 'D-Tech',
      'DLI' => 'D-Link',
      'ENO' => 'eNOVA',
      'IN2' => 'iNOVA',
      'IN3' => 'inovo',
      'INH' => 'Inhon',
      'EB' => 'E-Boda',
      'EJ' => 'Engel',
      'ENA' => 'ENACOM',
      'ENI' => 'ENIE',
      '2E' => 'E-Ceros',
      'E8' => 'E-tel',
      'EAS' => 'EAS Electric',
      'EP' => 'Easypix',
      'EQ' => 'Eagle',
      'EGS' => 'EagleSoar',
      'EA' => 'EBEST',
      'YC' => 'EBEN',
      'E4' => 'Echo Mobiles',
      'EQ1' => 'Equator',
      'ES' => 'ECS',
      '35' => 'ECON',
      'ECC' => 'ECOO',
      'ZZ' => 'ecom',
      'EDE' => 'Edenwood',
      'E6' => 'EE',
      'GW' => 'EGL',
      'EFT' => 'EFT',
      'EK' => 'EKO',
      'EY' => 'Einstein',
      'EM' => 'Eks Mobility',
      'UE' => 'Ematic',
      'EMR' => 'Emporia',
      '4K' => 'EKT',
      'EKI' => 'EKINOX',
      '7E' => 'ELARI',
      '03' => 'Electroneum',
      'Z8' => 'ELECTRONIA',
      'EL1' => 'Elecson',
      'ELK' => 'Elektroland',
      'L0' => 'Element',
      'EG' => 'Elenberg',
      'EL' => 'Elephone',
      'JE' => 'Elekta',
      'ELE' => 'Elevate',
      '4E' => 'Eltex',
      'ELM' => 'Elong Mobile',
      'ED' => 'Energizer',
      'E1' => 'Energy Sistem',
      '3E' => 'Enot',
      'ENT' => 'Entity',
      'ENV' => 'Envizen',
      '8E' => 'Epik One',
      'EPK' => 'Epic',
      'XP' => 'Epson',
      'EPH' => 'Ephone',
      'E7' => 'Ergo',
      'EC' => 'Ericsson',
      '05' => 'Erisson',
      'ER' => 'Ericy',
      'EE' => 'Essential',
      'E2' => 'Essentielb',
      '6E' => 'eSTAR',
      'ETO' => 'ETOE',
      'EN' => 'Eton',
      'ET' => 'eTouch',
      '1E' => 'Etuline',
      'EU' => 'Eurostar',
      '4J' => 'Eurocase',
      'E9' => 'Evercoss',
      'EV' => 'Evertek',
      'EVE' => 'Everest',
      'EV1' => 'Everex',
      'E3' => 'Evolio',
      'EO' => 'Evolveo',
      '0Q' => 'Evoo',
      '5U' => 'EVPAD',
      'E0' => 'EvroMedia',
      'XE' => 'ExMobile',
      '4Z' => 'Exmart',
      'EH' => 'EXO',
      'EX' => 'Explay',
      'EXP' => 'Express LUCK',
      'E5' => 'Extrem',
      'EXL' => 'ExtraLink',
      'EF' => 'EXCEED',
      'QE' => 'EWIS',
      'EI' => 'Ezio',
      'EZ' => 'Ezze',
      'UF' => 'EYU',
      'EYE' => 'Eyemoo',
      'UE1' => 'UE',
      '5F' => 'F150',
      'FPS' => 'F+',
      'F6' => 'Facebook',
      'FAC' => 'Facetel',
      'FA1' => 'Facime',
      'FA' => 'Fairphone',
      'FM' => 'Famoco',
      'FAM' => 'Famous',
      '17' => 'FarEasTone',
      '9R' => 'FaRao Pro',
      'FAR' => 'Farassoo',
      'FB' => 'Fantec',
      'FE' => 'Fengxiang',
      'FEN' => 'Fenoti',
      'F7' => 'Fero',
      '67' => 'FEONAL',
      'FI' => 'FiGO',
      'J9' => 'FiGi',
      'FIG' => 'Figgers',
      'F9' => 'FiiO',
      'F1' => 'FinePower',
      'FX' => 'Finlux',
      'F3' => 'FireFly Mobile',
      'F8' => 'FISE',
      'FIT' => 'FITCO',
      'FLM' => 'Filimo',
      'FIL' => 'FILIX',
      'FL' => 'Fly',
      'QC' => 'FLYCAT',
      'FLY' => 'FLYCOAY',
      'FLU' => 'Fluo',
      'FN' => 'FNB',
      'FOB' => 'Fobem',
      'FD' => 'Fondi',
      '0F' => 'Fourel',
      '44' => 'Four Mobile',
      'F0' => 'Fonos',
      'F2' => 'FORME',
      'F5' => 'Formuler',
      'FR' => 'Forstar',
      'RF' => 'Fortis',
      'FO' => 'Foxconn',
      'FOD' => 'FoxxD',
      'FJ' => 'FOODO',
      'FOS' => 'FOSSiBOT',
      'FRE' => 'free',
      'FT' => 'Freetel',
      'FEY' => 'FreeYond',
      'FRU' => 'Frunsi',
      'F4' => 'F&U',
      '1F' => 'FMT',
      'FPT' => 'FPT',
      'FG' => 'Fuego',
      'FU' => 'Fujitsu',
      '4F' => 'Funai',
      '5J' => 'Fusion5',
      'FF' => 'Future Mobile Technology',
      'FFF' => 'FFF SmartLife',
      'FW' => 'FNF',
      'FXT' => 'Fxtec',
      'GT' => 'G-TiDE',
      'G9' => 'G-Touch',
      'GFO' => 'Gfone',
      'GTM' => 'GTMEDIA',
      'GTX' => 'GTX',
      '0G' => 'GFive',
      'GM' => 'Garmin-Asus',
      'GA' => 'Gateway',
      '99' => 'Galaxy Innovations',
      'GA1' => 'Galactic',
      'GAM' => 'Gamma',
      'GAZ' => 'Gazer',
      'GEA' => 'Geanee',
      'GEN' => 'Geant',
      'GD' => 'Gemini',
      'GN' => 'General Mobile',
      '2G' => 'Genesis',
      'G2' => 'GEOFOX',
      'GE' => 'Geotel',
      'Q4' => 'Geotex',
      'GEO' => 'GEOZON',
      'GNO' => 'Getnord',
      'GER' => 'Gear Mobile',
      'GH' => 'Ghia',
      '2C' => 'Ghong',
      'GJ' => 'Ghost',
      'GG' => 'Gigabyte',
      'GS' => 'Gigaset',
      'GZ' => 'Ginzzu',
      '1G' => 'Gini',
      'GI' => 'Gionee',
      'GIR' => 'GIRASOLE',
      'G4' => 'Globex',
      'GLB' => 'Globmall',
      '38' => 'GLONYX',
      'U6' => 'Glofiish',
      'G7' => 'GoGEN',
      'GC' => 'GOCLEVER',
      '5G' => 'Gocomma',
      'GB' => 'Gol Mobile',
      'GL' => 'Goly',
      'GOL' => 'GoldMaster',
      'GOS' => 'GoldStar',
      'GOB' => 'GOLDBERG',
      'GX' => 'GLX',
      'G5' => 'Gome',
      'G1' => 'GoMobile',
      'GO' => 'Google',
      'G0' => 'Goophone',
      '6G' => 'Gooweel',
      'GOO' => 'GOODTEL',
      '8G' => 'Gplus',
      'GR' => 'Gradiente',
      'GRE' => 'Graetz',
      'GP' => 'Grape',
      'G6' => 'Gree',
      'GRA' => 'Great Asia',
      '3G' => 'Greentel',
      'GRO' => 'Green Orange',
      'GRL' => 'Green Lion',
      'GR1' => 'GroBerwert',
      'GF' => 'Gretel',
      '82' => 'Gresso',
      'GU' => 'Grundig',
      'GV' => 'Gtel',
      'CUO' => 'Guophone',
      'H13' => 'H133',
      '9Z' => 'H96',
      'HF' => 'Hafury',
      '9F' => 'HAOVM',
      'HAQ' => 'HAOQIN',
      'HA' => 'Haier',
      'HEC' => 'HEC',
      'XH' => 'Haipai',
      'HAN' => 'Handheld',
      'HE' => 'HannSpree',
      'HNS' => 'Hanseatic',
      'HK' => 'Hardkernel',
      'HAR' => 'Harper',
      'HA1' => 'Hartens',
      'HS' => 'Hasee',
      '8H' => 'Hamlet',
      'HAM' => 'Hammer',
      'HAT' => 'Hathway',
      'H6' => 'Helio',
      'HQ' => 'HERO',
      'ZH' => 'Hezire',
      'HEX' => 'HexaByte',
      'HEW' => 'HeadWolf',
      'HEI' => 'Heimat',
      'HL' => 'Hi-Level',
      '3H' => 'Hi',
      'HIB' => 'Hiberg',
      'HBY' => 'HiBy',
      'HIH' => 'HiHi',
      'HIK' => 'HiKing',
      'H2' => 'Highscreen',
      'Q1' => 'High Q',
      'HIG' => 'HiGrace',
      '1H' => 'Hipstreet',
      'HIR' => 'Hiremco',
      'HI' => 'Hisense',
      'HIP' => 'HIPER',
      'HC' => 'Hitachi',
      'H8' => 'Hitech',
      'W3' => 'HiMax',
      '8X' => 'Hi Nova',
      'HLL' => 'HLLO',
      'HKC' => 'HKC',
      'HMD' => 'HMD',
      '8W' => 'HKPro',
      'HOF' => 'HOFER',
      'H1' => 'Hoffmann',
      'HOM' => 'Homatics',
      'H0' => 'Hometech',
      'HLB' => 'HOLLEBERG',
      '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',
      'HYK' => 'Hykker',
      '3I' => 'i-Cherry',
      'IJ' => 'i-Joy',
      'IM' => 'i-mate',
      'IO' => 'i-mobile',
      'INN' => 'I-INN',
      'IPL' => 'I-Plus',
      'OF' => 'iOutdoor',
      'IB' => 'iBall',
      'IY' => 'iBerry',
      '7I' => 'iBrit',
      'IBO' => 'ibowin',
      'I2' => 'IconBIT',
      'IC' => 'iDroid',
      'IDI' => 'iDino',
      '6Z' => 'iData',
      'IG' => 'iGet',
      'IH' => 'iHunt',
      'IA' => 'Ikea',
      'IYO' => 'iYou',
      '8I' => 'IKU Mobile',
      '2K' => 'IKI Mobile',
      'IK' => 'iKoMo',
      '58' => 'iKon',
      '588' => 'iKonia',
      'I7' => 'iLA',
      '2I' => 'iLife',
      '1I' => 'iMars',
      'IMI' => 'iMI',
      'U4' => 'iMan',
      'ILE' => 'iLepo',
      'IL' => 'IMO Mobile',
      'IMA' => 'Imaq',
      'IM1' => 'Imose',
      'I3' => 'Impression',
      'FC' => 'INCAR',
      '2H' => 'Inch',
      '6I' => 'Inco',
      'INK' => 'Inka',
      'IW' => 'iNew',
      'IF' => 'Infinix',
      'INF' => 'Infiniton',
      'I0' => 'InFocus',
      'IN1' => 'InFone',
      'II' => 'Inkti',
      'MIR' => 'Infomir',
      '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',
      'IRO' => 'iRobot',
      '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',
      'IOT' => 'IOTWE',
      'JA' => 'JAY-Tech',
      'KJ' => 'Jiake',
      'JD' => 'Jedi',
      'JEE' => 'Jeep',
      'J6' => 'Jeka',
      'JF' => 'JFone',
      'JI' => 'Jiayu',
      'JG' => 'Jinga',
      'JIN' => 'Jin Tu',
      'JX' => 'Jio',
      'VJ' => 'Jivi',
      'JK' => 'JKL',
      'JR1' => 'JREN',
      'JO' => 'Jolla',
      'JP' => 'Joy',
      'JOY' => 'JoySurf',
      'UJ' => 'Juniper Systems',
      'J5' => 'Just5',
      '7J' => 'Jumper',
      'JPA' => 'JPay',
      'JV' => 'JVC',
      'JXD' => 'JXD',
      'JS' => 'Jesy',
      'KT' => 'K-Touch',
      'KLT' => 'K-Lite',
      'K4' => 'Kaan',
      'K7' => 'Kaiomy',
      'KL' => 'Kalley',
      'K6' => 'Kanji',
      'KA' => 'Karbonn',
      'K5' => 'KATV1',
      'KAP' => 'Kapsys',
      'K0' => 'Kata',
      'KZ' => 'Kazam',
      '9K' => 'Kazuna',
      'KD' => 'KDDI',
      'KHA' => 'Khadas',
      'KS' => 'Kempler & Strauss',
      'K3' => 'Keneksi',
      'KHI' => 'KENSHI',
      'KX' => 'Kenxinda',
      'KEN' => 'Kenbo',
      'KND' => 'Kendo',
      'KZG' => 'KZG',
      'K1' => 'Kiano',
      '5W' => 'Kingbox',
      'KI' => 'Kingsun',
      'KIS' => 'Kinstone',
      'KF' => 'KINGZONE',
      'KIN' => 'Kingstar',
      '46' => 'Kiowa',
      'KV' => 'Kivi',
      '64' => 'Kvant',
      'KVA' => 'KVADRA',
      '0K' => 'Klipad',
      'KNM' => 'KN Mobile',
      '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',
      'KRA' => 'Kraft',
      'KH' => 'KT-Tech',
      'Z6' => 'KUBO',
      'KUG' => 'KuGou',
      'K8' => 'Kuliao',
      '8K' => 'Kult',
      'KU' => 'Kumai',
      '6K' => 'Kurio',
      'KYD' => 'Kydos',
      'KY' => 'Kyocera',
      'KQ' => 'Kyowon',
      '1K' => 'Kzen',
      'LQ' => 'LAIQ',
      'L6' => 'Land Rover',
      'L2' => 'Landvo',
      'LA' => 'Lanix',
      'LA1' => 'Lanin',
      'LK' => 'Lark',
      'Z3' => 'Laurus',
      'LEC' => 'Lectrus',
      'LV' => 'Lava',
      'LVI' => 'Lville',
      'LC' => 'LCT',
      'L5' => 'Leagoo',
      'U3' => 'Leben',
      'LEB' => 'LeBest',
      'LD' => 'Ledstar',
      'LEE' => 'Leelbox',
      'L1' => 'LeEco',
      '4B' => 'Leff',
      'LEG' => 'Legend',
      'L4' => 'Lemhoov',
      'W9' => 'LEMFO',
      'LEM' => 'Lemco',
      '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',
      'LIN' => 'Linsay',
      'LF' => 'Lifemaxx',
      'LI' => 'Lingwin',
      'LIB' => 'Lingbo',
      'LIM' => 'Lime',
      'LJ' => 'L-Max',
      'LW' => 'Linnex',
      'JJ' => 'Listo',
      'LNM' => 'LNMBBS',
      'LO' => 'Loewe',
      'YL' => 'Loview',
      'LOV' => 'Lovme',
      '1L' => 'Logic',
      'LH' => 'Logic Instrument',
      'LM' => 'Logicom',
      'LOG' => 'Logik',
      'GY' => 'LOKMAT',
      'LPX' => 'LPX-G',
      '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',
      'MAG' => 'MAG',
      'MA2' => 'MAGCH',
      '6Y' => 'Magicsee',
      '23' => 'Magnus',
      'NH' => 'Manhattan',
      'MAN' => 'Mango',
      '5M' => 'Mann',
      'MA' => 'Manta Multimedia',
      'Z0' => 'Mantra',
      'J4' => 'Mara',
      'MAR' => 'Marshal',
      '8Y' => 'Massgo',
      'MA1' => 'Mascom',
      '2M' => 'Masstel',
      '3X' => 'Mastertech',
      'MAS' => 'Master-G',
      '50' => 'Matrix',
      'MAT' => 'Matco Tools',
      '7M' => 'Maxcom',
      '7M1' => 'Maxfone',
      'ZM' => 'Maximus',
      '6X' => 'Maxtron',
      '0D' => 'MAXVI',
      'MAX' => 'Maxwell',
      'XZ' => 'MAXX',
      'MW' => 'Maxwest',
      'M0' => 'Maze',
      'YM' => 'Maze Speed',
      '87' => 'Malata',
      'MAU' => 'Maunfeld',
      '28' => 'MBOX',
      'FK' => 'MBI',
      'MBK' => 'MBK',
      '3D' => 'MDC Store',
      '1Y' => 'MDTV',
      '09' => 'meanIT',
      'M3' => 'Mecer',
      'M3M' => 'M3 Mobile',
      '0M' => 'Mecool',
      'MEM' => 'MeMobile',
      'MC' => 'Mediacom',
      'MK' => 'MediaTek',
      'MD' => 'Medion',
      'M2' => 'MEEG',
      'MEG' => 'MEGA VISION',
      'MP' => 'MegaFon',
      'X0' => 'mPhone',
      '3M' => 'Meitu',
      'M1' => 'Meizu',
      '0E' => 'Melrose',
      'MU' => 'Memup',
      'ME' => 'Metz',
      'MEO' => 'MEO',
      'MX' => 'MEU',
      'MI' => 'MicroMax',
      'MIP' => 'mipo',
      'MS' => 'Microsoft',
      '6Q' => 'Microtech',
      '1X' => 'Minix',
      'OM' => 'Mintt',
      'MIN' => 'Mint',
      'MO' => 'Mio',
      'X7' => 'Mione',
      'M7' => 'Miray',
      'MIT' => 'Mitchell & Brown',
      '8M' => 'Mito',
      'MT' => 'Mitsubishi',
      '0Y' => 'Mitsui',
      'M5' => 'MIXC',
      '2D' => 'MIVO',
      '1Z' => 'MiXzo',
      'MIW' => 'MIWANG',
      'ML' => 'MLLED',
      'LS' => 'MLS',
      'MLA' => 'MLAB',
      '5H' => 'MMI',
      '4M' => 'Mobicel',
      'M6' => 'Mobiistar',
      'MOK' => 'Mobile Kingdom',
      'MH' => 'Mobiola',
      'MB' => 'Mobistel',
      'ID' => 'MobiIoT',
      '6W' => 'MobiWire',
      '9M' => 'Mobo',
      'MOB' => 'Mobell',
      'MVO' => 'Mobvoi',
      'M4' => 'Modecom',
      'MF' => 'Mofut',
      'MR' => 'Motorola',
      'MIV' => 'Motiv',
      'MV' => 'Movic',
      'MOV' => 'Movitel',
      'MO1' => 'MOVISUN',
      'MOS' => 'Mosimosi',
      'MOX' => 'Moxee',
      'MM' => 'Mpman',
      'MZ' => 'MSI',
      '3R' => 'MStar',
      'M9' => 'MTC',
      'N4' => 'MTN',
      '72' => 'M-Tech',
      '9H' => 'M-Horse',
      '1R' => 'Multilaser',
      'MPS' => 'MultiPOS',
      '1M' => 'MYFON',
      'MY' => 'MyPhone',
      '51' => 'Myros',
      'M8' => 'Myria',
      '6M' => 'Mystery',
      '3T' => 'MyTab',
      'MG' => 'MyWigo',
      'J3' => 'Mymaga',
      'MYM' => 'MyMobile',
      '07' => 'MyGica',
      'MYG' => 'MygPad',
      'MWA' => 'MwalimuPlus',
      'NEO' => 'neoCore',
      'NER' => 'Neoregent',
      '08' => 'Nabi',
      'N7' => 'National',
      'NC' => 'Navcity',
      '6N' => 'Navitech',
      '7V' => 'Navitel',
      'N3' => 'Navon',
      '7R' => 'NavRoad',
      'NAB' => 'NABO',
      'NAS' => 'NASCO',
      'NP' => 'Naomi Phone',
      'NAN' => 'Nanho',
      'NE' => 'NEC',
      'NDP' => 'Nedaphone',
      '8N' => 'Necnot',
      'NF' => 'Neffos',
      '9X' => 'Neo',
      'NEK' => 'NEKO',
      '1N' => 'Neomi',
      '7Q' => 'Neon IQ',
      '8F' => 'Neolix',
      'NET' => 'NetBox',
      'NA' => 'Netgear',
      'NEM' => 'Netmak',
      'NU' => 'NeuImage',
      'NEU' => 'NeuTab',
      'NEV' => 'NEVIR',
      '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',
      'NST' => 'Next & NextStar',
      'NJO' => 'nJoy',
      'NG' => 'NGM',
      'NZ' => 'NG Optics',
      'NZP' => 'NGpon',
      'NN' => 'Nikon',
      'NI' => 'Nintendo',
      'NIN' => 'NINETEC',
      'N5' => 'NOA',
      'N1' => 'Noain',
      'N6' => 'Nobby',
      'NOC' => 'Novacom',
      'NOS' => 'NoviSea',
      'NOV' => 'Novey',
      'NO1' => 'NOVO',
      '57' => 'Nubia',
      'JN' => 'NOBUX',
      'NB' => 'Noblex',
      'OG' => 'NOGA',
      'NK' => 'Nokia',
      'NM' => 'Nomi',
      '2N' => 'Nomu',
      '6H' => 'Noontec',
      'NR' => 'Nordmende',
      'NOR' => 'NORMANDE',
      '7N' => 'NorthTech',
      'NOT' => 'Nothing Phone',
      '5N' => 'Nos',
      'NO' => 'Nous',
      'NQ' => 'Novex',
      'NOD' => 'noDROPOUT',
      'NJ' => 'NuAns',
      'NL' => 'NUU Mobile',
      'N0' => 'Nuvo',
      'NUV' => 'NuVision',
      'NV' => 'Nvidia',
      'NY' => 'NYX Mobile',
      'NON' => 'N-one',
      'O3' => 'O+',
      'OT' => 'O2',
      'O7' => 'Oale',
      'OC' => 'OASYS',
      'OB' => 'Obi',
      'OBR' => 'Ober',
      'OQ' => 'Meta',
      'O1' => 'Odys',
      'ODP' => 'Odotpad',
      'O9' => 'Ok',
      'OA' => 'Okapia',
      'OKI' => 'Oking',
      'OLA' => 'Olax',
      'OLK' => 'Olkya',
      'OLY' => 'Olympia',
      'OCE' => 'OCEANIC',
      'OLT' => 'OLTO',
      'OJ' => 'Ookee',
      'OD' => 'Onda',
      'ON' => 'OnePlus',
      'ONC' => 'OneClick',
      'ONL' => 'OneLern',
      'OAN' => 'Oangcc',
      'OX' => 'Onix',
      'OIN' => 'Onida',
      '3O' => 'ONYX BOOX',
      'O4' => 'ONN',
      '9Q' => 'Onkyo',
      'ONV' => 'ONVO',
      'OOR' => 'Ooredoo',
      '2O' => 'OpelMobile',
      'OH' => 'Openbox',
      '7Y' => 'Obabox',
      'OP' => 'OPPO',
      'OO' => 'Opsson',
      'OPT' => 'Optoma',
      'OPH' => 'Ophone',
      'OR' => 'Orange',
      'ORA' => 'Orava',
      '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',
      'OSC' => 'OSCAL',
      'OY' => 'Oysters',
      'QF' => 'OYSIN',
      'O6' => 'Oyyu',
      'OZ' => 'OzoneHD',
      'OLL' => 'Ollee',
      '7P' => 'P-UP',
      'PRA' => 'Pacific Research Alliance',
      'PAG' => 'PAGRAER',
      'PAD' => 'Padpro',
      'YP' => 'Paladin',
      'PM' => 'Palm',
      'PN' => 'Panacom',
      'PA' => 'Panasonic',
      'PNV' => 'Panavox',
      'PT' => 'Pantech',
      'PAN' => 'Pano',
      'PND' => 'Panodic',
      'PA1' => 'Panoramic',
      'PLT' => 'Platoon',
      '94' => 'Packard Bell',
      'H9' => 'Parrot Mobile',
      'PAR' => 'Partner Mobile',
      'PAP' => 'PAPYRE',
      'PB' => 'PCBOX',
      'PCS' => 'PC Smart',
      'PC' => 'PCD',
      'PD' => 'PCD Argentina',
      'PE' => 'PEAQ',
      'PEN' => 'Penta',
      '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',
      'PLA' => 'Play Now',
      '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',
      'PR1' => 'Premier',
      'PR' => 'Prestigio',
      'P9' => 'Primepad',
      'PRM' => 'PRIME',
      '6P' => 'Primux',
      '2P' => 'Prixton',
      'PRI' => 'Pritom',
      'PF' => 'PROFiLO',
      'P6' => 'Proline',
      '5O' => 'Prology',
      'P1' => 'ProScan',
      'PRO' => 'PROSONIC',
      'P7' => 'Protruly',
      'R0' => 'ProVision',
      '7O' => 'Polestar',
      'PU' => 'PULID',
      'UP' => 'Purism',
      'PUN' => 'Punos',
      'QFX' => 'QFX',
      'Q7' => 'Q-Box',
      'QH' => 'Q-Touch',
      'QB' => 'Q.Bell',
      'QI' => 'Qilive',
      'QIN' => 'QIN',
      'QM' => 'QMobile',
      'QT' => 'Qtek',
      'Q9' => 'QTECH',
      'QA' => 'Quantum',
      'QUE' => 'Quest',
      'QUA' => 'Quatro',
      'QU' => 'Quechua',
      'QUI' => 'Quipus',
      'QO' => 'Qumo',
      'UQ' => 'Qubo',
      'YQ' => 'QLink',
      'QY' => 'Qnet Mobile',
      'WJ' => 'Qware',
      'QWT' => 'QWATT',
      'R2' => 'R-TV',
      'RA' => 'Ramos',
      '0R' => 'Raspberry',
      'R9' => 'Ravoz',
      'RZ' => 'Razer',
      '95' => 'Rakuten',
      'RAY' => 'Raylandz',
      'RC' => 'RCA Tablets',
      '2R' => 'Reach',
      'REL' => 'RelNAT',
      'RB' => 'Readboy',
      'RE' => 'Realme',
      'RE1' => 'Redbean',
      'R8' => 'RED',
      'REW' => 'Redway',
      '6F' => 'Redfox',
      'RE2' => 'RedLine',
      'RD' => 'Reeder',
      'Z9' => 'REGAL',
      'RH' => 'Remdun',
      'RP' => 'Revo',
      'REV' => 'Revomovil',
      '8R' => 'Retroid Pocket',
      'REN' => 'Renova',
      'RIC' => 'Ricoh',
      'RI' => 'Rikomagic',
      'RM' => 'RIM',
      'RN' => 'Rinno',
      'RX' => 'Ritmix',
      'R7' => 'Ritzviva',
      'RV' => 'Riviera',
      '6R' => 'Rivo',
      'RIZ' => 'Rizzen',
      'RR' => 'Roadrover',
      'QR' => 'ROADMAX',
      'ROC' => 'Roam Cat',
      'ROT' => 'Rocket',
      'R1' => 'Rokit',
      'ROI' => 'ROiK',
      'RK' => 'Roku',
      'R3' => 'Rombica',
      'R5' => 'Ross&Moor',
      'RO' => 'Rover',
      'R6' => 'RoverPad',
      'RQ' => 'RoyQueen',
      'RJ' => 'Royole',
      'RT' => 'RT Project',
      'RG' => 'RugGear',
      'RUG' => 'Ruggex',
      'RUT' => 'RuggeTech',
      'RU' => 'Runbo',
      'RUP' => 'Rupa',
      'RL' => 'Ruio',
      'RY' => 'Ryte',
      'X5' => 'Saba',
      '8L' => 'S-TELL',
      '8L1' => 'S-Color',
      '4O' => 'S2Tel',
      '89' => 'Seatel',
      'SEW' => 'Sewoo',
      'SE1' => 'SEEWO',
      'Y7' => 'Saiet',
      'SLF' => 'SAILF',
      'X1' => 'Safaricom',
      'SG' => 'Sagem',
      'SAG' => 'Sagemcom',
      '4L' => 'Salora',
      'SA' => 'Samsung',
      'SAT' => 'Samtech',
      'SAM' => 'Samtron',
      'SNA' => 'SNAMI',
      'S0' => 'Sanei',
      '12' => 'Sansui',
      'SAK' => 'Sankey',
      'SQ' => 'Santin',
      'SY' => 'Sanyo',
      'SAN' => 'SANY',
      'S9' => 'Savio',
      'Y4' => 'SCBC',
      'CZ' => 'Schneider',
      'SCO' => 'Scosmos',
      'ZG' => 'Schok',
      'G8' => 'SEG',
      'SEX' => 'SEHMAX',
      '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',
      'SEB' => 'SEBBE',
      '61' => 'Seuic',
      'SX' => 'SFR',
      'SGI' => 'SGIN',
      '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',
      'SIL' => 'Silva Schneider',
      '10' => 'Simbans',
      '98' => 'Simply',
      'SIM' => 'simfer',
      '52' => 'Singtech',
      '31' => 'Siragon',
      '83' => 'Sirin Labs',
      '5Z' => 'SK Broadband',
      'GK' => 'SKG',
      'SW' => 'Sky',
      'SK' => 'Skyworth',
      'SKY' => 'Skyline',
      'SK1' => 'SkyStream',
      'SKT' => 'Skytech',
      'SKK' => 'SKK Mobile',
      '14' => 'Smadl',
      '19' => 'Smailo',
      'SR' => 'Smart Electronic',
      'SMA' => 'Smart Kassel',
      '49' => 'Smart',
      '47' => 'SmartBook',
      '3B' => 'Smartab',
      '80' => 'SMARTEC',
      'SM1' => 'Smartex',
      'SC' => 'Smartfren',
      'S7' => 'Smartisan',
      'SMU' => 'SMUX',
      'JR' => 'Sylvania',
      'SYH' => 'SYH',
      '3Y' => 'Smarty',
      'HH' => 'Smooth Mobile',
      '1Q' => 'Smotreshka',
      'SF' => 'Softbank',
      '9L' => 'SOLE',
      'JL' => 'SOLO',
      'SOS' => 'SOSH',
      'SOD' => 'Soda',
      'SOL' => 'Solas',
      '16' => 'Solone',
      'OI' => 'Sonim',
      'SVE' => 'Sveon',
      'SO' => 'Sony',
      'SE' => 'Sony Ericsson',
      'X2' => 'Soundmax',
      'SUL' => 'SoulLink',
      '8S' => 'Soyes',
      '77' => 'SONOS',
      '68' => 'Soho Style',
      'SOB' => 'SobieTech',
      'PK' => 'Spark',
      'SPX' => 'Sparx',
      'FS' => 'SPC',
      '6S' => 'Spectrum',
      '43' => 'Spectralink',
      'SP' => 'Spice',
      '84' => 'Sprint',
      'SPU' => 'SPURT',
      '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',
      'SUR' => 'Surge',
      'SUF' => 'Surfans',
      '06' => 'Subor',
      'SZ' => 'Sumvision',
      '0H' => 'Sunstech',
      'S3' => 'SunVan',
      '5S' => 'Sunvell',
      '5Y' => 'Sunny',
      'W8' => 'SUNWIND',
      'SBX' => 'SuperBOX',
      'SBR' => 'Sber',
      'SGE' => 'Super General',
      'SU' => 'SuperSonic',
      '79' => 'SuperTab',
      'S5' => 'Supra',
      'SUP' => 'Supraim',
      'ZS' => 'Suzuki',
      '2J' => 'Sunmi',
      'SUN' => 'Sunmax',
      '0W' => 'Swipe',
      'SWI' => 'Switel',
      'SS' => 'SWISSMOBILITY',
      '1W' => 'Swisstone',
      'SSK' => 'SSKY',
      'SYC' => 'Syco',
      'SM' => 'Symphony',
      '4S' => 'Syrox',
      'SYS' => 'System76',
      'TM' => 'T-Mobile',
      'T96' => 'T96',
      'TAD' => 'TADAAM',
      'TK' => 'Takara',
      '73' => 'Tambo',
      '9N' => 'Tanix',
      'U5' => 'Taiga System',
      'TAL' => 'Talius',
      '7G' => 'TAG Tech',
      'TAU' => 'TAUBE',
      'T5' => 'TB Touch',
      'TC' => 'TCL',
      'T0' => 'TD Systems',
      'YY' => 'TD Tech',
      'H4' => 'Technicolor',
      'TEA' => 'TeachTouch',
      'Z5' => 'Technika',
      'TE1' => 'TechSmart',
      'TX' => 'TechniSat',
      'TT' => 'TechnoTrend',
      'TTS' => 'TECHNOSAT',
      'TP' => 'TechPad',
      'TPS' => 'TPS',
      '9E' => 'Techwood',
      '7F' => 'Technopc',
      'TCH' => 'Techstorm',
      'T7' => 'Teclast',
      'TB' => 'Tecno Mobile',
      'TEC' => 'TecToy',
      '91' => 'TEENO',
      'TLK' => 'Telkom',
      '2L' => 'Tele2',
      'TL' => 'Telefunken',
      'TG' => 'Telego',
      'T2' => 'Telenor',
      'TE' => 'Telit',
      '65' => 'Telia',
      'TLY' => 'Telly',
      'TEL' => 'Telma',
      'PW' => 'Telpo',
      'TLS' => 'TeloSystems',
      'TER' => 'Teracube',
      'TD' => 'Tesco',
      'TA' => 'Tesla',
      '9T' => 'Tetratab',
      'TET' => 'TETC',
      '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',
      'TYD' => 'TYD',
      'TOO' => 'TOOGO',
      'T9' => 'Top House',
      'DK' => 'Topelotek',
      '42' => 'Topway',
      'TO' => 'Toplux',
      'TOD' => 'TOPDON',
      'TOP' => 'TopDevice',
      'TO2' => 'TOPSHOWS',
      '7T' => 'Torex',
      'TOR' => 'Torque',
      '6O' => 'TOSCIDO',
      'TO1' => 'Topsion',
      'TS' => 'Toshiba',
      'T8' => 'Touchmate',
      'TOU' => 'Touch Plus',
      '5R' => 'Transpeed',
      'T6' => 'TrekStor',
      'T3' => 'Trevi',
      'TRI' => 'TriaPlay',
      'TJ' => 'Trifone',
      'Q5' => 'Trident',
      '4T' => 'Tronsmart',
      '11' => 'True',
      'JT' => 'True Slim',
      'J1' => 'Trio',
      'THT' => 'Tsinghua Tongfang',
      '5C' => 'TTEC',
      'TTF' => 'TTfone',
      'TTK' => 'TTK-TV',
      'TU' => 'Tunisie Telecom',
      '1T' => 'Turbo',
      'TR' => 'Turbo-X',
      '5X' => 'TurboPad',
      '5T' => 'TurboKids',
      'UR' => 'Turkcell',
      '4U' => 'TuCEL',
      'TUV' => 'Tuvio',
      '2U' => 'Türk Telekom',
      'TV' => 'TVC',
      'TW' => 'TWM',
      'Z1' => 'TWZ',
      '6T' => 'Twoe',
      'TWN' => 'TwinMOS',
      '15' => 'Tymes',
      'UC' => 'U.S. Cellular',
      'UD1' => 'UD',
      'UGI' => 'UGINE',
      'UG' => 'Ugoos',
      'U1' => 'Uhans',
      'UH' => 'Uhappy',
      'UL' => 'Ulefone',
      'UA' => 'Umax',
      'UM' => 'UMIDIGI',
      'UNT' => 'Unitech',
      'UZ' => 'Unihertz',
      '3Z' => 'UZ Mobile',
      'UX' => 'Unimax',
      'UNQ' => 'Uniqcell',
      'US' => 'Uniscope',
      'UNI' => 'Unistrong',
      'U2' => 'UNIWA',
      'UND' => 'Uniden',
      'UO' => 'Unnecto',
      'UNN' => 'Unnion Technologies',
      'UU' => 'Unonu',
      'UN' => 'Unowhy',
      'UY' => 'UNNO',
      'UOO' => 'UOOGOU',
      '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',
      'VA2' => 'VALE',
      'VAT' => 'VALTECH',
      'VAN' => 'VANGUARD',
      'VAW' => 'VANWIN',
      'VB' => 'VC',
      'VN' => 'Venso',
      'VNP' => 'VNPT Technology',
      'VEN' => 'Venstar',
      'UV' => 'Venturer',
      'VQ' => 'Vega',
      'WC' => 'VEON',
      '4V' => 'Verico',
      'V4' => 'Verizon',
      'VR' => 'Vernee',
      'VX' => 'Vertex',
      'VE' => 'Vertu',
      'VET' => 'VETAS',
      'VL' => 'Verykool',
      'QV' => 'Verssed',
      'VER' => 'Versus',
      'V8' => 'Vesta',
      'VEK' => 'Vekta',
      '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',
      'VIP' => 'Viper',
      'VI' => 'Vitelcom',
      'VIB' => 'ViBox',
      '8V' => 'Viumee',
      'V5' => 'Vivax',
      'VIV' => 'VIVIMAGE',
      'VV' => 'Vivo',
      '6V' => 'VIWA',
      'VII' => 'VIIPOO',
      'VID' => 'VIDA',
      'VZ' => 'Vizio',
      'VIZ' => 'Vizmo',
      'VIT' => 'Vityaz',
      '9V' => 'Vision Touch',
      'VIL' => 'Visual Land',
      'VI1' => 'VILLAON',
      'VK' => 'VK Mobile',
      'JM' => 'v-mobile',
      'VHO' => 'V-HOPE',
      'VHM' => 'V-HOME',
      'VGE' => 'V-Gen',
      'V0' => 'VKworld',
      'VM' => 'Vodacom',
      'VOC' => 'VOCAL',
      'VF' => 'Vodafone',
      '7W' => 'VOGA',
      'V2' => 'Vonino',
      '1V' => 'Vontar',
      'VG' => 'Vorago',
      '2V' => 'Vorke',
      '8U' => 'Vorcom',
      'JW' => 'Vortex',
      'VOR' => 'Vormor',
      'V1' => 'Voto',
      'Z7' => 'VOX',
      'VO' => 'Voxtel',
      'VY' => 'Voyo',
      'VOL' => 'Völfen',
      'VO1' => 'Volt',
      'VOP' => 'Volla',
      'V02' => 'VOLIA',
      'VH' => 'Vsmart',
      'V9' => 'Vsun',
      'VU' => 'Vulcan',
      '3V' => 'VVETIME',
      'ZC' => 'VUCATIMES',
      'VO2' => 'VOLKANO',
      'VUE' => 'Vue Micro',
      'WAK' => 'Walker',
      'WA' => 'Walton',
      'WAF' => 'WAF',
      'WAO' => 'W&O',
      'WAL' => 'Waltter',
      'WAI' => 'Wainyok',
      'WHI' => 'White Mobile',
      'WHO' => 'Whoop',
      'WBL' => 'We. by Loewe.',
      'WCP' => 'WeChip',
      'WM' => 'Weimei',
      'WE' => 'WellcoM',
      'W6' => 'WELLINGTON',
      'WD' => 'Western Digital',
      'WT' => 'Westpoint',
      'WAN' => 'Wanmukang',
      'WA1' => 'WANSA',
      'WY' => 'Wexler',
      '3W' => 'WE',
      'WEC' => 'Wecool',
      'WEE' => 'Weelikeit',
      'WP' => 'Wieppo',
      'W2' => 'Wigor',
      'WI' => 'Wiko',
      'WF' => 'Wileyfox',
      'WS' => 'Winds',
      'WN' => 'Wink',
      '9W' => 'Winmax',
      'W5' => 'Winnovo',
      'WU' => 'Wintouch',
      'WIS' => 'Winstar',
      'W0' => 'Wiseasy',
      '2W' => 'Wizz',
      'W4' => 'WIWA',
      'WIZ' => 'WizarPos',
      'WL' => 'Wolder',
      'WG' => 'Wolfgang',
      'WQ' => 'Wolki',
      'WON' => 'WONDER',
      'WO' => 'Wonu',
      'W1' => 'Woo',
      'WR' => 'Wortmann',
      'WX' => 'Woxter',
      'XQ' => 'X-AGE',
      'XEL' => 'XElectron',
      'X3' => 'X-BO',
      'XMO' => 'X-Mobile',
      'XT' => 'X-TIGI',
      'XV' => 'X-View',
      'X4' => 'X.Vision',
      'X88' => 'X88',
      'X96' => 'X96',
      '96Q' => 'X96Q',
      'A95' => 'A95X',
      'XG' => 'Xgody',
      'XGE' => 'XGEM',
      'QX' => 'XGIMI',
      'XL' => 'Xiaolajiao',
      'XI' => 'Xiaomi',
      'XW' => 'Xiaodu',
      'XN' => 'Xion',
      'XO' => 'Xolo',
      'XR' => 'Xoro',
      'XS' => 'Xshitou',
      'XSM' => 'Xsmart',
      '4X' => 'Xtouch',
      'X8' => 'Xtratech',
      'XCR' => 'Xcruiser',
      'XCO' => 'XCOM',
      'XCL' => 'Xcell',
      'XWA' => 'Xwave',
      'YD' => 'Yandex',
      'YA' => 'Yarvik',
      'Y2' => 'Yes',
      'YES' => 'Yestel',
      'YE' => 'Yezz',
      'YG' => 'YEPEN',
      'YEL' => 'YELLYOUTH',
      'YK' => 'Yoka TV',
      'YO' => 'Yota',
      'YOU' => 'Youin',
      'YO1' => 'Youwei',
      'YOO' => 'Yooz',
      'YT' => 'Ytone',
      'Y9' => 'YOTOPT',
      'Y1' => 'Yu',
      'YF' => 'YU Fly',
      'Y0' => 'YUHO',
      'YN' => 'Yuno',
      'YUN' => 'YUNDOO',
      'YUS' => 'YunSong',
      'YUM' => 'YUMKEM',
      'YU' => 'Yuandao',
      'YS' => 'Yusun',
      'YJ' => 'YASIN',
      'YX' => 'Yxtel',
      '0Z' => 'Zatec',
      '2Z' => 'Zaith',
      'ZAM' => 'Zamolxe',
      'ZEA' => 'Zealot',
      'PZ' => 'Zebra',
      'ZE1' => 'Zeblaze',
      'ZE' => 'Zeemi',
      'WZ' => 'Zeeker',
      'ZN' => 'Zen',
      'ZK' => 'Zenek',
      'ZL' => 'Zentality',
      'ZF' => 'Zfiner',
      'ZI' => 'Zidoo',
      'FZ' => 'ZIFRO',
      'ZX' => 'Ziox',
      'ZIK' => 'ZIK',
      'ZKI' => 'Z-Kai',
      'ZIG' => 'Zigo',
      'ZIN' => 'Zinox',
      'ZO' => 'Zonda',
      'ZW' => 'Zonko',
      'ZP' => 'Zopo',
      'ZOO' => 'ZoomSmart',
      'ZO1' => 'Zoom',
      'ZT' => 'ZTE',
      'ZU' => 'Zuum',
      'ZY' => 'Zync',
      'ZR' => 'Zyrex',
      'ZQ' => 'ZYQ',
      'Z4' => 'ZH&K',
      'OW' => 'öwn',
      'WBF' => 'Webfleet',
      'WSS' => 'WS',

      # legacy brands, might be removed in future versions
      'WB' => 'Web TV',
      'XX' => 'Unknown'
    }.freeze

    def known?
      regex_meta.any?
    end

    def name
      ModelExtractor.new(user_agent, regex_meta).call
    end

    def type
      if hbbtv? || shelltv?
        'tv'
      else
        regex_meta[:device]
      end
    end

    def brand
      return regex_meta[:brand] if regex_meta[:brand] == 'Sony Ericsson'

      brand = regex_meta[:regex_name] || regex_meta[:brand] || vendor_fragment.name || fix_for_x_music
      return if brand == 'Unknown'

      brand
    end

    private

    def fix_for_x_music
      user_agent&.include?('X-music Ⅲ') ? 'OneClick' : nil
    end

    def vendor_fragment
      ::DeviceDetector::VendorFragment.new(user_agent)
    end

    # The order of files needs to be the same as the order of device
    # parser classes used in the piwik project.
    def filenames
      [
        'device/televisions.yml',
        'device/shell_tv.yml',
        'device/notebooks.yml',
        'device/consoles.yml',
        'device/car_browsers.yml',
        'device/cameras.yml',
        'device/portable_media_player.yml',
        'device/mobiles.yml'
      ]
    end

    def matching_regex
      from_cache([self.class.name, user_agent]) do
        regex_list = hbbtv? ? regexes_for_hbbtv : regexes_other
        regex_list = shelltv? ? regexes_for_shelltv : regex_list

        regex = regex_find(user_agent, regex_list)
        if regex && regex[:models]
          model_regex = regex[:models].find { |m| user_agent =~ m[:regex] }
          if model_regex
            regex = regex.merge({
                                  regex_model: model_regex[:regex],
                                  model: model_regex[:model],
                                  brand: model_regex[:brand]
                                })
            regex[:brand] = DEVICE_BRANDS[regex[:brand]] if DEVICE_BRANDS.key?(regex[:brand])
            regex[:device] = model_regex[:device] if model_regex.key?(:device)
            regex.delete(:models)
          end
        end
        regex
      end
    end

    # Finds the first match of the string in a list of regexes.
    # Handles exception with special characters caused by bug in Ruby regex
    # @param user_agent [String] User Agent string
    # @param regex_list [Array<Regex>] List of regexes
    #
    # @return [MatchData, nil] MatchData if string matches any regexp, nil otherwise
    def regex_find(user_agent, regex_list)
      regex_list.find { |r| user_agent =~ r[:regex] }
    rescue RegexpError
      # Bug in ruby regex and special characters, retry with clean
      # https://bugs.ruby-lang.org/issues/13671
      user_agent = user_agent.encode(
        ::Encoding::ASCII, invalid: :replace, undef: :replace, replace: ''
      )
      regex_list.find { |r| user_agent =~ r[:regex] }
    end

    def hbbtv?
      @regex_hbbtv ||= build_regex('HbbTV/([1-9]{1}(?:\.[0-9]{1}){1,2})')
      user_agent =~ @regex_hbbtv
    end

    def shelltv?
      @regex_shelltv ||= build_regex('[a-z]+[ _]Shell[ _]\w{6}')
      user_agent =~ @regex_shelltv
    end

    def regexes_for_hbbtv
      regexes.select { |r| r[:path] == :'device/televisions.yml' }
    end

    def regexes_for_shelltv
      regexes.select { |r| r[:path] == :'device/shell_tv.yml' }
    end

    def regexes_other
      regexes.reject { |r| r[:path] == :'device/televisions.yml' }
    end

    def parse_regexes(path, raw_regexes)
      raw_regexes.map do |brand, meta|
        raise "invalid device spec: #{meta.inspect}" unless meta[:regex].is_a? String

        meta[:regex] = build_regex(meta[:regex])
        if meta.key?(:models)
          meta[:models].each do |model|
            raise "invalid model spec: #{model.inspect}" unless model[:regex].is_a? String

            model[:regex] = build_regex(model[:regex])
            model[:brand] = brand.to_s unless model[:brand]
          end
        end
        meta[:path] = path
        meta
      end
    end
  end
end
