# Mappings from Browser names we use to known client hint values
# fmt: off
APP_TO_CLIENT_HINT_MAPPING = {
    'Chrome'                    : ['Google Chrome'],
    'Chrome Webview'            : ['Android WebView'],
    'DuckDuckGo Privacy Browser': ['DuckDuckGo'],
    'Edge WebView'              : ['Microsoft Edge WebView2'],
    'Mi Browser'                : ['Miui Browser', 'XiaoMiBrowser'],
    'Microsoft Edge'            : ['Edge'],
    'Norton Private Browser'    : ['Norton Secure Browser'],
    'Opera GX'                  : ['Opera GX Android'],
    'Opera Mini'                : ['Opera Mini Android'],
    'Puffin Cloud Browser'      : ['Puffin'],
    'Vewd Browser'              : ['Vewd Core'],
    'Yandex Browser'            : ['YaSearchBrowser'],
}

CLIENT_HINT_TO_APP_MAP = {}
for dd_app_name, ch_app_names in APP_TO_CLIENT_HINT_MAPPING.items():
    for ch_app_name in ch_app_names:
        CLIENT_HINT_TO_APP_MAP[ch_app_name.lower()] = dd_app_name
        CLIENT_HINT_TO_APP_MAP[ch_app_name] = dd_app_name


# Mappings from OS names we use to known client hint values
OS_CLIENT_HINT_MAPPING = {
    'GNU/Linux': ['Linux'],
    'Mac'      : ['MacOS', 'macOS', 'Mac OS X', 'MacIntel'],
    'Puffin OS': ['Cloud Phone 2.4'],
}

# Operating system families that are known as desktop only
DESKTOP_OS = {
    'AmigaOS', 'IBM', 'GNU/Linux', 'Mac', 'Unix', 'Windows', 'BeOS', 'Chrome OS', 'Chromium OS',
    'OpenVMS',
}

# Sub-list of Desktop OS that never falsely appear in UAs
ALWAYS_DESKTOP_OS = {
    'AmigaOS', 'IBM', 'Unix', 'BeOS', 'Arch Linux',
}

APPLE_OS_NAMES = {
    'tvOS',
    'watchOS',
    'iPadOS',
    'iOS',
    'macOS',
    'Mac',
}

# Fire OS version mapping
FIREOS_VERSION_MAPPING = {
    '16'   : '16',
    '15'   : '15',
    '14'   : '14',
    '13'   : '14',
    '12'   : '14',
    '11'   : '8',
    '10'   : '8',
    '9'    : '7',
    '7'    : '6',
    '5'    : '5',
    '4.4.3': '4.5.1',
    '4.4.2': '4',
    '4.2.2': '3',
    '4.0.3': '3',
    '4.0.2': '3',
    '4'    : '2',
    '2'    : '1',
}

# Lineage OS version mapping
LINEAGEOS_VERSION_MAPPING = {
    '16'   : '23',
    '15'   : '22',
    '14'   : '21',
    '13'   : '20.0',
    '12.1' : '19.1',
    '12'   : '19.0',
    '11'   : '18.0',
    '10'   : '17.0',
    '9'    : '16.0',
    '8.1.0': '15.1',
    '8.0.0': '15.0',
    '7.1.2': '14.1',
    '7.1.1': '14.1',
    '7.0'  : '14.0',
    '6.0.1': '13.0',
    '6.0'  : '13.0',
    '5.1.1': '12.1',
    '5.0.2': '12.0',
    '5.0'  : '12.0',
    '4.4.4': '11.0',
    '4.3'  : '10.2',
    '4.2.2': '10.1',
    '4.0.4': '9.1.0',
}
# fmt: off

ANDROID_APPS = {
    'com.hisense.odinbrowser',
    'com.seraphic.openinet.pre',
    'com.appssppa.idesktoppcbrowser',
    'every.browser.inc',
}


OPERATING_SYSTEMS = {
    'AIX': 'AIX',
    'AND': 'Android',
    'AGO': 'Android Go',
    'ADR': 'Android TV',
    'ALP': 'Alpine Linux',
    'AMZ': 'Amazon Linux',
    'AMG': 'AmigaOS',
    'ARM': 'Armadillo OS',
    'ARO': 'AROS',
    'ATV': 'tvOS',
    'ARC': 'ArcaOS',
    'ARL': 'Arch Linux',
    'AOS': 'AOSC OS',
    'ASP': 'ASPLinux',
    'AZU': 'Azure Linux',
    'BTR': 'BackTrack',
    'SBA': 'Bada',
    'BYI': 'Baidu Yi',
    'BEO': 'BeOS',
    'BLB': 'BlackBerry OS',
    'QNX': 'BlackBerry Tablet OS',
    'PAN': 'blackPanther OS',
    'BOS': 'Bliss OS',
    'BMP': 'Brew',
    'BSN': 'BrightSignOS',
    'BS1': 'BSD',
    'CAI': 'Caixa Mágica',
    'CES': 'CentOS',
    'CST': 'CentOS Stream',
    'CLO': 'Clear Linux OS',
    'CLR': 'ClearOS Mobile',
    'COS': 'Chrome OS',
    'CRS': 'Chromium OS',
    'CHN': 'China OS',
    'CON': 'Contiki',
    'COL': 'Coolita OS',
    'CYN': 'CyanogenMod',
    'DEB': 'Debian',
    'DEE': 'Deepin',
    'DFB': 'DragonFly',
    'DVK': 'DVKBuntu',
    'ELE': 'ElectroBSD',
    'ELM': 'elementary OS',
    'EUL': 'EulerOS',
    'FED': 'Fedora',
    'FEN': 'Fenix',
    'FOS': 'Firefox OS',
    'FIR': 'Fire OS',
    'FOR': 'Foresight Linux',
    'FRE': 'Freebox',
    'BSD': 'FreeBSD',
    'FRI': 'FRITZ!OS',
    'FYD': 'FydeOS',
    'FUC': 'Fuchsia',
    'GNT': 'Gentoo',
    'GNX': 'GENIX',
    'GEO': 'GEOS',
    'GHO': 'GhostBSD',
    'GNS': 'gNewSense',
    'GRI': 'GridOS',
    'GTV': 'Google TV',
    'HPX': 'HP-UX',
    'HAI': 'Haiku OS',
    'IPA': 'iPadOS',
    'HAR': 'HarmonyOS',
    'HNX': 'HarmonyOS NEXT',
    'HAS': 'HasCodingOS',
    'HEL': 'HELIX OS',
    'HYP': 'HyperOS',
    'IRI': 'IRIX',
    'INF': 'Inferno',
    'JME': 'Java ME',
    'JOL': 'Joli OS',
    'KOS': 'KaiOS',
    'KAL': 'Kali',
    'KAN': 'Kanotix',
    'KIN': 'KIN OS',
    'KOB': 'KoboOS',
    'KOL': 'KolibriOS',
    'KNO': 'Knoppix',
    'KTV': 'KreaTV',
    'KBT': 'Kubuntu',
    'LIN': 'GNU/Linux',
    'LEA': 'LeafOS',
    'LND': 'LindowsOS',
    'LNS': 'Linspire',
    'LEN': 'Lineage OS',
    'LPU': 'Linpus',
    'LIR': 'Liri OS',
    'LOO': 'Loongnix',
    'LBT': 'Lubuntu',
    'LOS': 'Lumin OS',
    'LUN': 'LuneOS',
    'VLN': 'VectorLinux',
    'MAC': 'Mac',
    'MAE': 'Maemo',
    'MAG': 'Mageia',
    'MDR': 'Mandriva',
    'SMG': 'MeeGo',
    'MET': 'Meta Horizon',
    'MNX': 'MINIX',
    'MOS': 'Mocor OS',
    'MCD': 'MocorDroid',
    'MON': 'moonOS',
    'EZX': 'Motorola EZX',
    'MIN': 'Mint',
    'MLD': 'MildWild',
    'MOR': 'MorphOS',
    'NBS': 'NetBSD',
    'MTK': 'MTK / Nucleus',
    'MRE': 'MRE',
    'NXT': 'NeXTSTEP',
    'NWS': 'NEWS-OS',
    'WII': 'Nintendo',
    'NDS': 'Nintendo Mobile',
    'NOV': 'Nova',
    'NTX': 'NuttX',
    'OS2': 'OS/2',
    'T64': 'OSF1',
    'OSS': 'openSUSE',
    'OBS': 'OpenBSD',
    'OHS': 'OpenHarmony',
    'OVS': 'OpenVMS',
    'OVZ': 'OpenVZ',
    'OWR': 'OpenWrt',
    'OTV': 'Opera TV',
    'ORA': 'Oracle Linux',
    'ORD': 'Ordissimo',
    'ORS': 'Orsay',
    'PAR': 'Pardus',
    'PCL': 'PCLinuxOS',
    'PIC': 'PICO OS',
    'PLN': 'Plan 9',
    'PLA': 'Plasma Mobile',
    'PSP': 'PlayStation Portable',
    'PS3': 'PlayStation',
    'PVE': 'Proxmox VE',
    'PUF': 'Puffin OS',
    'PUR': 'PureOS',
    'QTP': 'Qtopia',
    'PIO': 'Raspberry Pi OS',
    'RAS': 'Raspbian',
    'RHT': 'Red Hat',
    'RST': 'Red Star',
    'RED': 'RedOS',
    'REV': 'Revenge OS',
    'RIS': 'risingOS',
    'ROS': 'RISC OS',
    'ROC': 'Rocky Linux',
    'ROK': 'Roku OS',
    'RSO': 'Rosa',
    'ROU': 'RouterOS',
    'REM': 'Remix OS',
    'RRS': 'Resurrection Remix OS',
    'REX': 'REX',
    'RZD': 'RazoDroiD',
    'RXT': 'RTOS & Next',
    'SAB': 'Sabayon',
    'SSE': 'SUSE',
    'SAF': 'Sailfish OS',
    'SCI': 'Scientific Linux',
    'SEE': 'SeewoOS',
    'SER': 'SerenityOS',
    'SIR': 'Sirin OS',
    'SLW': 'Slackware',
    'SMA': 'Smartisan OS',
    'SOS': 'Solaris',
    'SBL': 'Star-Blade OS',
    'SYL': 'Syllable',
    'SYM': 'Symbian',
    'SYS': 'Symbian OS',
    'S40': 'Symbian OS Series 40',
    'S60': 'Symbian OS Series 60',
    'SY3': 'Symbian^3',
    'TEN': 'TencentOS',
    'THN': 'ThinOS',
    'TDX': 'ThreadX',
    'TIT': 'Titan OS',
    'TIZ': 'Tizen',
    'TIV': 'TiVo OS',
    'TOS': 'TmaxOS',
    'TUR': 'Turbolinux',
    'UBT': 'Ubuntu',
    'ULT': 'ULTRIX',
    'UOS': 'UOS',
    'VEG': 'Vega OS',
    'VID': 'VIDAA',
    'VIZ': 'ViziOS',
    'WAS': 'watchOS',
    'WER': 'Wear OS',
    'WTV': 'WebTV',
    'WHS': 'Whale OS',
    'WIN': 'Windows',
    'WCE': 'Windows CE',
    'WIO': 'Windows IoT',
    'WMO': 'Windows Mobile',
    'WPH': 'Windows Phone',
    'WRT': 'Windows RT',
    'WPO': 'WoPhone',
    'XBX': 'Xbox',
    'XBT': 'Xubuntu',
    'YNS': 'YunOS',
    'ZEN': 'Zenwalk',
    'ZOR': 'ZorinOS',
    'IOS': 'iOS',
    'POS': 'palmOS',
    'WEB': 'Webian',
    'WOS': 'webOS',
    'UNK': 'Unknown',
}

# flip Abbrev / OS for fast membership testing
OS_TO_ABBREV = {os.lower(): abbrev for abbrev, os in OPERATING_SYSTEMS.items()}

# fmt: off
OS_FAMILIES = {
    'Android': [
        'AND', 'CYN', 'FIR', 'REM', 'RZD', 'MLD', 'MCD', 'YNS', 'GRI', 'HAR',
        'ADR', 'CLR', 'BOS', 'REV', 'LEN', 'SIR', 'RRS', 'WER', 'PIC', 'ARM',
        'HEL', 'BYI', 'RIS', 'PUF', 'LEA', 'MET', 'SMA', 'AGO',
    ],
    'AmigaOS': ('AMG', 'MOR', 'ARO'),
    'BlackBerry': ('BLB', 'QNX'),
    'Brew': ('BMP',),
    'BeOS': ('BEO', 'HAI'),
    'Chrome OS': ('COS', 'CRS', 'FYD', 'SEE'),
    'Firefox OS': ('FOS', 'KOS'),
    'Gaming Console': ('WII', 'PS3'),
    'Google TV': ('GTV',),
    'IBM': ('OS2', 'ARC'),
    'iOS': ('IOS', 'ATV', 'WAS', 'IPA'),
    'RISC OS': ('ROS',),
    'GNU/Linux': (
        'LIN', 'ARL', 'DEB', 'KNO', 'MIN', 'UBT', 'KBT', 'XBT', 'LBT', 'FED',
        'RHT', 'VLN', 'MDR', 'GNT', 'SAB', 'SLW', 'SSE', 'CES', 'BTR', 'SAF',
        'ORD', 'TOS', 'RSO', 'DEE', 'FRE', 'MAG', 'FEN', 'CAI', 'PCL', 'HAS',
        'LOS', 'DVK', 'ROK', 'OWR', 'OTV', 'KTV', 'PUR', 'PLA', 'FUC', 'PAR',
        'FOR', 'MON', 'KAN', 'ZEN', 'LND', 'LNS', 'CHN', 'AMZ', 'TEN', 'CST',
        'NOV', 'ROU', 'ZOR', 'RED', 'KAL', 'ORA', 'VID', 'TIV', 'BSN', 'RAS',
        'UOS', 'PIO', 'FRI', 'LIR', 'WEB', 'SER', 'ASP', 'AOS', 'LOO', 'EUL',
        'SCI', 'ALP', 'CLO', 'ROC', 'OVZ', 'PVE', 'RST', 'EZX', 'GNS', 'JOL',
        'TUR', 'QTP', 'WPO', 'PAN', 'VIZ', 'AZU', 'COL', 'OSS', 'ELM', 'LPU',
        'KOB',
    ),
    'Mac': ('MAC',),
    'Mobile Gaming Console': ('PSP', 'NDS', 'XBX'),
    'OpenHarmony': ('OHS', 'HNX'),
    'OpenVMS': ('OVS',),
    'Other Mobile': ('WOS', 'POS', 'SBA', 'TIZ', 'SMG', 'MAE', 'LUN', 'GEO', 'CON'),
    'Real-time OS': ('MTK', 'TDX', 'MRE', 'JME', 'REX', 'RXT', 'KOL', 'MOS', 'NTX'),
    'Symbian': ('SYM', 'SYS', 'SY3', 'S60', 'S40'),
    'Unix': (
        'SOS', 'AIX', 'HPX', 'BSD', 'NBS', 'OBS', 'DFB', 'SYL', 'IRI', 'T64',
        'INF', 'ELE', 'GNX', 'ULT', 'NWS', 'NXT', 'SBL', 'BS1', 'GHO', 'PLN',
        'MNX', 'THN',
    ),
    'WebTV': ('WTV',),
    'Windows': ('WIN',),
    'Windows Mobile': ('WPH', 'WMO', 'WCE', 'WRT', 'WIO', 'KIN'),
    'Other Smart TV': ('WHS', 'TIT', 'ORS', 'VEG'),
    'Unknown': ('UNK',),
}
# fmt: on

FAMILY_FROM_OS = {}
for os, families in OS_FAMILIES.items():
    for family in families:
        FAMILY_FROM_OS[family] = os

for os, families in OS_CLIENT_HINT_MAPPING.items():
    for family in families:
        FAMILY_FROM_OS[family] = os
        FAMILY_FROM_OS[family.lower()] = os

AVAILABLE_ENGINES = {
    'WebKit',
    'Blink',
    'Trident',
    'Text-based',
    'Dillo',
    'iCab',
    'Elektra',
    'Presto',
    'Clecko',
    'Gecko',
    'KHTML',
    'NetFront',
    'Edge',
    'NetSurf',
    'Servo',
    'Goanna',
    'EkiohFlow',
    'Arachne',
    'LibWeb',
    'Maple',
    'ArkWeb',
}
AVAILABLE_ENGINES_LOWER_CASE = {engine.lower(): engine for engine in AVAILABLE_ENGINES}

AVAILABLE_BROWSERS = {
    'V1': 'Via',
    '1P': 'Pure Mini Browser',
    '4P': 'Pure Lite Browser',
    '1R': 'Raise Fast Browser',
    'R1': 'Rabbit Private Browser',
    'FQ': 'Fast Browser UC Lite',
    'FJ': 'Fast Explorer',
    '1L': 'Lightning Browser',
    '1C': 'Cake Browser',
    '1I': 'IE Browser Fast',
    '1V': 'Vegas Browser',
    '1O': 'OH Browser',
    '3O': 'OH Private Browser',
    '1X': 'XBrowser Mini',
    '1S': 'Sharkee Browser',
    '2L': 'Lark Browser',
    '3P': 'Pluma',
    '1A': 'Anka Browser',
    'AZ': 'Azka Browser',
    '1D': 'Dragon Browser',
    '1E': 'Easy Browser',
    'DW': 'Dark Web Browser',
    'D6': 'Dark Browser',
    '18': '18+ Privacy Browser',
    '1B': '115 Browser',
    'DM': '1DM Browser',
    '1M': '1DM+ Browser',
    '2B': '2345 Browser',
    '3B': '360 Secure Browser',
    '36': '360 Phone Browser',
    '7B': '7654 Browser',
    'AA': 'Avant Browser',
    'AB': 'ABrowse',
    '00': 'Ace',
    '4A': 'Acoo Browser',
    'BW': 'AdBlock Browser',
    'A7': 'Adult Browser',
    '8A': 'Ai Browser',
    'A9': 'Airfind Secure Browser',
    'AF': 'ANT Fresco',
    'AG': 'ANTGalio',
    'AL': 'Aloha Browser',
    'AH': 'Aloha Browser Lite',
    'A8': 'ALVA',
    '9A': 'AltiBrowser',
    'AM': 'Amaya',
    'A3': 'Amaze Browser',
    'A5': 'Amerigo',
    'AO': 'Amigo',
    'AN': 'Android Browser',
    'AY': 'Anonyv Browser',
    '3A': 'AOL Explorer',
    'AE': 'AOL Desktop',
    'AD': 'AOL Shield',
    'A4': 'AOL Shield Pro',
    '2A': 'Aplix',
    'A6': 'AppBrowzer',
    '0A': 'AppTec Secure Browser',
    'AP': 'APUS Browser',
    'AR': 'Arora',
    'AX': 'Arctic Fox',
    'AV': 'Amiga Voyager',
    'AW': 'Amiga Aweb',
    'PN': 'APN Browser',
    '6A': 'Arachne',
    'RA': 'Arc Search',
    'R5': 'Armorfly Browser',
    'AQ': 'ArtisBrowser',
    'AI': 'Arvin',
    'AK': 'Ask.com',
    'KA': 'Ask Browser',
    'AU': 'Asus Browser',
    'A0': 'Atom',
    'AT': 'Atomic Web Browser',
    'A2': 'Atlas',
    'AS': 'Avast Secure Browser',
    'VG': 'AVG Secure Browser',
    'AC': 'Avira Secure Browser',
    'A1': 'AwoX',
    '7A': 'Awesomium',
    '5B': 'Basic Web Browser',
    'BA': 'Beaker Browser',
    'BM': 'Beamrise',
    'F7': 'BF Browser',
    'BB': 'BlackBerry Browser',
    '6B': 'Bluefy',
    'H1': 'BrowseHere',
    'B8': 'Browser Hup Pro',
    'BD': 'Baidu Browser',
    'BS': 'Baidu Spark',
    'BG': 'Bang',
    'B9': 'Bangla Browser',
    'BI': 'Basilisk',
    'BV': 'Belva Browser',
    'B5': 'Beyond Private Browser',
    'BE': 'Beonex',
    'B2': 'Berry Browser',
    'BT': 'Bitchute Browser',
    '9B': 'BizBrowser',
    'BC': 'Black Browser',
    'BH': 'BlackHawk',
    'Z1': 'Blazer',
    'B0': 'Bloket',
    'BJ': 'Bunjalloo',
    'BL': 'B-Line',
    'B6': 'Black Lion Browser',
    'BU': 'Blue Browser',
    'BO': 'Bonsai',
    'BN': 'Borealis Navigator',
    'BR': 'Brave',
    'BK': 'BriskBard',
    'K2': 'BroKeep Browser',
    'B3': 'Browspeed Browser',
    'BX': 'BrowseX',
    'BZ': 'Browzar',
    'B7': 'Browlser',
    'BQ': 'Browse Safe',
    'M9': 'Browser Mini',
    '4B': 'BrowsBit',
    'BY': 'Biyubi',
    'BF': 'Byffox',
    'B4': 'BXE Browser',
    'CA': 'Camino',
    '5C': 'Catalyst',
    'XP': 'Catsxp',
    '0C': 'Cave Browser',
    'CL': 'CCleaner',
    'C8': 'CG Browser',
    'CJ': 'ChanjetCloud',
    'C6': 'Chedot',
    'C9': 'Cherry Browser',
    'C0': 'Centaury',
    'ZC': 'Clario Browser',
    '9C': 'Clear TV Browser',
    'CQ': 'Cliqz',
    'CC': 'Coc Coc',
    'C4': 'CoolBrowser',
    'C2': 'Colibri',
    '6C': 'Columbus Browser',
    'CD': 'Comodo Dragon',
    'XC': 'Comet',
    'C1': 'Coast',
    'CX': 'Charon',
    'G0': 'ChatGPT Atlas',
    'CE': 'CM Browser',
    'C7': 'CM Mini',
    'CF': 'Chrome Frame',
    'HC': 'Headless Chrome',
    'H0': 'Headless Edge',
    'CH': 'Chrome',
    'CI': 'Chrome Mobile iOS',
    'CK': 'Conkeror',
    'CM': 'Chrome Mobile',
    '3C': 'Chowbo',
    '7C': 'Classilla',
    'CN': 'CoolNovo',
    '4C': 'Colom Browser',
    'CO': 'CometBird',
    '2C': 'Comfort Browser',
    'CB': 'COS Browser',
    'CW': 'Cornowser',
    'C3': 'Chim Lac',
    'CP': 'ChromePlus',
    'CR': 'Chromium',
    'C5': 'Chromium GOST',
    'CY': 'Cyberfox',
    'CS': 'Cheshire',
    '8C': 'Cromite',
    'RC': 'Crow Browser',
    'CT': 'Crusta',
    'CG': 'Craving Explorer',
    'CZ': 'Crazy Browser',
    'CU': 'Cunaguaro',
    'CV': 'Chrome Webview',
    'YC': 'CyBrowser',
    'DB': 'dbrowser',
    'PD': 'Peeps dBrowser',
    'DK': 'Dark Web',
    'DP': 'Dark Web Private',
    'D4': 'DDU Browser',
    'D1': 'Debuggable Browser',
    'DC': 'Decentr',
    'DE': 'Deepnet Explorer',
    'DG': 'deg-degan',
    'DA': 'Deledao',
    'DT': 'Delta Browser',
    'D0': 'Desi Browser',
    'DS': 'DeskBrowse',
    'D3': 'Dezor',
    'II': 'Diigo Browser',
    'D2': 'DoCoMo',
    'DF': 'Dolphin',
    'DZ': 'Dolphin Zero',
    'DO': 'Dorado',
    'DR': 'Dot Browser',
    'DL': 'Dooble',
    'D8': 'Doubao',
    'DI': 'Dillo',
    'DU': 'DUC Browser',
    'DD': 'DuckDuckGo Privacy Browser',
    'E1': 'East Browser',
    'EC': 'Ecosia',
    'EW': 'Edge WebView',
    'EV': 'Every Browser',
    'EI': 'Epic',
    'EL': 'Elinks',
    'EN': 'EinkBro',
    'EB': 'Element Browser',
    'EE': 'Elements Browser',
    'EO': 'Eolie',
    'EX': 'Explore Browser',
    'EZ': 'eZ Browser',
    'E2': 'EudoraWeb',
    'EU': 'EUI Browser',
    'EP': 'GNOME Web',
    'G1': 'G Browser',
    'ES': 'Espial TV Browser',
    'FG': 'fGet',
    'FA': 'Falkon',
    'FX': 'Faux Browser',
    'F8': 'Fire Browser',
    'F4': 'Fiery Browser',
    'F1': 'Firefox Mobile iOS',
    'FB': 'Firebird',
    'FD': 'Fluid',
    'FE': 'Fennec',
    'FF': 'Firefox',
    'FK': 'Firefox Focus',
    'FY': 'Firefox Reality',
    'FR': 'Firefox Rocket',
    '1F': 'Firefox Klar',
    'F0': 'Float Browser',
    'FL': 'Flock',
    'FP': 'Floorp',
    'FO': 'Flow',
    'F2': 'Flow Browser',
    'FM': 'Firefox Mobile',
    '3F': 'FireSend Browser',
    'FW': 'Fireweb',
    'FN': 'Fireweb Navigator',
    'FH': 'Flash Browser',
    'FS': 'Flast',
    'F5': 'Flyperlink',
    'F9': 'FOSS Browser',
    'FU': 'FreeU',
    'F6': 'Freedom Browser',
    'FT': 'Frost',
    'F3': 'Frost+',
    'FI': 'Fulldive',
    'GA': 'Galeon',
    'G8': 'Gener8',
    'GH': 'Ghostery Privacy Browser',
    'GI': 'GinxDroid Browser',
    'GB': 'Glass Browser',
    'GD': 'Godzilla Browser',
    'G3': 'Good Browser',
    'GE': 'Google Earth',
    'GP': 'Google Earth Pro',
    'GO': 'GOG Galaxy',
    'GR': 'GoBrowser',
    'GK': 'GoKu',
    'G2': 'GO Browser',
    'RN': 'GreenBrowser',
    'HW': 'Habit Browser',
    'H7': 'Halo Browser',
    'HB': 'Harman Browser',
    'HS': 'HasBrowser',
    'HA': 'Hawk Turbo Browser',
    'HQ': 'Hawk Quick Browser',
    'HE': 'Helio',
    'HN': 'Herond Browser',
    'HX': 'Hexa Web Browser',
    'H8': 'HeyTapBrowser',
    'HI': 'Hi Browser',
    'HO': 'hola! Browser',
    'H4': 'Holla Web Browser',
    'H5': 'HotBrowser',
    'HJ': 'HotJava',
    'H6': 'HONOR Browser',
    'HT': 'HTC Browser',
    'HU': 'Huawei Browser Mobile',
    'HP': 'Huawei Browser',
    'HM': 'Harmony 360 Browser',
    'H3': 'HUB Browser',
    'IO': 'iBrowser',
    'IS': 'iBrowser Mini',
    'IB': 'IBrowse',
    'I6': 'iDesktop PC Browser',
    'IC': 'iCab',
    'I2': 'iCab Mobile',
    'I0': 'iTop Private Browser',
    '0I': 'Ifbrowser',
    '4I': 'iNet Browser',
    'I1': 'Iridium',
    'I3': 'Iron Mobile',
    'I4': 'IceCat',
    'ID': 'IceDragon',
    'IV': 'Isivioo',
    'I8': 'IVVI Browser',
    'IW': 'Iceweasel',
    '2I': 'Impervious Browser',
    'N3': 'Incognito Browser',
    'IN': 'Inspect Browser',
    'I9': 'Insta Browser',
    'IE': 'Internet Explorer',
    'I7': 'Internet Browser Secure',
    '5I': 'Internet Webbrowser',
    '3I': 'Intune Managed Browser',
    'I5': 'Indian UC Mini Browser',
    'Z0': 'InBrowser',
    'IG': 'Involta Go',
    'IM': 'IE Mobile',
    'IR': 'Iron',
    'IL': 'Island',
    'JB': 'Japan Browser',
    'JS': 'Jasmine',
    'JA': 'JavaFX',
    'JL': 'Jelly',
    'JI': 'Jig Browser',
    'JP': 'Jig Browser Plus',
    'JO': 'JioSphere',
    'JZ': 'JUZI Browser',
    'KB': 'K.Browser',
    'KF': 'Keepsafe Browser',
    'K7': 'KeepSolid Browser',
    'KS': 'Kids Safe Browser',
    'KI': 'Kindle Browser',
    'KM': 'K-meleon',
    'KJ': 'K-Ninja',
    'KO': 'Konqueror',
    'KP': 'Kapiko',
    'KE': 'Keyboard Browser',
    'KN': 'Kinza',
    'K4': 'Kitt',
    'KW': 'Kiwi',
    'KD': 'Kode Browser',
    'KU': 'KUN',
    'KT': 'KUTO Mini Browser',
    'KY': 'Kylo',
    'KZ': 'Kazehakase',
    'LB': 'Cheetah Browser',
    'LD': 'Ladybird',
    'LA': 'Lagatos Browser',
    'GN': 'Legan Browser',
    'LM': 'Lemur Browser',
    'LR': 'Lexi Browser',
    'LV': 'Lenovo Browser',
    'LF': 'LieBaoFast',
    'LG': 'LG Browser',
    'LH': 'Light',
    'LP': 'Lightpanda',
    'L4': 'Lightning Browser Plus',
    'L1': 'Lilo',
    'LI': 'Links',
    'RI': 'Liri Browser',
    'LC': 'LogicUI TV Browser',
    'IF': 'Lolifox',
    'L3': 'Lotus',
    'LO': 'Lovense Browser',
    'LT': 'LT Browser',
    'LU': 'LuaKit',
    'LJ': 'LUJO TV Browser',
    'LL': 'Lulumi',
    'LS': 'Lunascape',
    'LN': 'Lunascape Lite',
    'LX': 'Lynx',
    'L2': 'Lynket Browser',
    'MD': 'Mandarin',
    'MP': 'Maple',
    'M5': 'MarsLab Web Browser',
    'M7': 'MaxBrowser',
    'M1': 'mCent',
    'MB': 'MicroB',
    'MC': 'NCSA Mosaic',
    'MZ': 'Meizu Browser',
    'ME': 'Mercury',
    'M2': 'Me Browser',
    'MF': 'Mobile Safari',
    'MI': 'Midori',
    'M3': 'Midori Lite',
    'M6': 'MixerBox AI',
    'MO': 'Mobicip',
    'MU': 'Mi Browser',
    'MS': 'Mobile Silk',
    'MK': 'Mogok Browser',
    'M8': 'Motorola Internet Browser',
    'MN': 'Minimo',
    'MT': 'Mint Browser',
    'MX': 'Maxthon',
    'M4': 'MaxTube Browser',
    'MA': 'Maelstrom',
    '3M': 'Mises',
    'MM': 'Mmx Browser',
    'NM': 'MxNitro',
    'MY': 'Mypal',
    'M0': 'Mysudo',
    'MR': 'Monument Browser',
    'MW': 'MAUI WAP Browser',
    'N7': 'Naenara Browser',
    'NW': 'Navigateur Web',
    'NK': 'Naked Browser',
    'NA': 'Naked Browser Pro',
    '2N': 'Neuro Browser',
    'NR': 'NFS Browser',
    'N5': 'Ninetails',
    'NB': 'Nokia Browser',
    'NO': 'Nokia OSS Browser',
    'NV': 'Nokia Ovi Browser',
    'N2': 'Norton Private Browser',
    'NX': 'Nox Browser',
    'N1': 'NOMone VR Browser',
    'N6': 'Nook Browser',
    'NE': 'NetSurf',
    'NF': 'NetFront',
    'NL': 'NetFront Life',
    'NP': 'NetPositive',
    'NS': 'Netscape',
    'WR': 'NextWord Browser',
    'N8': 'Ninesky',
    '3N': 'Nintendo Browser',
    'NT': 'NTENT Browser',
    'NU': 'Nuanti Meta',
    'NI': 'Nuviu',
    'O9': 'Ocean Browser',
    'OC': 'Oculus Browser',
    'O6': 'Odd Browser',
    'O1': 'Opera Mini iOS',
    'OB': 'Obigo',
    'O2': 'Odin',
    '2O': 'Odin Browser',
    'H2': 'OceanHero',
    'OD': 'Odyssey Web Browser',
    'OF': 'Off By One',
    'O5': 'Office Browser',
    'HH': 'OhHai Browser',
    'OL': 'OnBrowser Lite',
    'OE': 'ONE Browser',
    'N4': 'Onion Browser',
    '1N': 'ONIONBrowser',
    '6O': 'Opera Air',
    'Y1': 'Opera Crypto',
    'OX': 'Opera GX',
    'OG': 'Opera Neon',
    'OH': 'Opera Devices',
    'OI': 'Opera Mini',
    'OM': 'Opera Mobile',
    'OP': 'Opera',
    'ON': 'Opera Next',
    'OO': 'Opera Touch',
    'OU': 'Orbitum',
    'OA': 'Orca',
    'OS': 'Ordissimo',
    'OR': 'Oregano',
    'O0': 'Origin In-Game Overlay',
    'OY': 'Origyn Web Browser',
    'O8': 'OrNET Browser',
    'OV': 'Openwave Mobile Browser',
    'O3': 'OpenFin',
    'O4': 'Open Browser',
    '4U': 'Open Browser 4U',
    '5G': 'Open Browser fast 5G',
    '5O': 'Open Browser Lite',
    'O7': 'Open TV Browser',
    'OW': 'OmniWeb',
    'OT': 'Otter Browser',
    '4O': 'Owl Browser',
    'JR': 'OJR Browser',
    'PL': 'Palm Blazer',
    'PM': 'Pale Moon',
    'PY': 'Polypane',
    'PZ': 'Panda Browser',
    '8P': 'Prism',
    'PP': 'Oppo Browser',
    'P6': 'Opus Browser',
    'PR': 'Palm Pre',
    '2E': 'Pocket Internet Explorer',
    '7I': 'Puffin Cloud Browser',
    '6I': 'Puffin Incognito Browser',
    'PU': 'Puffin Secure Browser',
    '2P': 'Puffin Web Browser',
    'PW': 'Palm WebPro',
    'PA': 'Palmscape',
    'P7': 'Pawxy',
    '0P': 'Peach Browser',
    'PE': 'Perfect Browser',
    'K6': 'Perk',
    'P1': 'Phantom.me',
    'PH': 'Phantom Browser',
    'PX': 'Phoenix',
    'PB': 'Phoenix Browser',
    '5P': 'Photon',
    'N9': 'Pintar Browser',
    'P9': 'PirateBrowser',
    'P8': 'PICO Browser',
    'PF': 'PlayFree Browser',
    'PK': 'PocketBook Browser',
    'PO': 'Polaris',
    'PT': 'Polarity',
    'LY': 'PolyBrowser',
    'PQ': 'Power Browser',
    '9P': 'Presearch',
    'BP': 'Privacy Browser',
    'PI': 'PrivacyWall',
    'P4': 'Privacy Explorer Fast Safe',
    'X5': 'Cloak Private Browser',
    'P3': 'Private Internet Browser',
    'PG': 'PrivateBrowsing',
    'P5': 'Proxy Browser',
    '7P': 'Proxyium',
    '6P': 'Proxynet',
    '2F': 'ProxyFox',
    '2M': 'ProxyMax',
    'P2': 'Pi Browser',
    'P0': 'PronHub Browser',
    'PC': 'PSI Secure Browser',
    'RW': 'Reqwireless WebViewer',
    'RO': 'Roccat',
    'PS': 'Microsoft Edge',
    'QA': 'Qazweb',
    'QI': 'Qiyu',
    'QJ': 'QJY TV Browser',
    'Q3': 'Qmamu',
    'Q8': 'Quiche Browser',
    'Q4': 'Quick Search TV',
    'Q2': 'QQ Browser Lite',
    'Q1': 'QQ Browser Mini',
    'QQ': 'QQ Browser',
    'QS': 'Quick Browser',
    'QT': 'Qutebrowser',
    'QU': 'Quark',
    'Q6': 'QuarkPC',
    'Q7': 'Quetta',
    'QZ': 'QupZilla',
    'QM': 'Qwant Mobile',
    'Q5': 'QtWeb',
    'QW': 'QtWebEngine',
    'R3': 'Rakuten Browser',
    'R4': 'Rakuten Web Search',
    'R2': 'Raspbian Chromium',
    'R6': 'Ray',
    'RT': 'RCA Tor Explorer',
    'RE': 'Realme Browser',
    'RK': 'Rekonq',
    'RM': 'RockMelt',
    'RB': 'Roku Browser',
    'SB': 'Samsung Browser',
    '3L': 'Samsung Browser Lite',
    'SA': 'Sailfish Browser',
    'R0': 'SberBrowser',
    'S8': 'Seewo Browser',
    'SC': 'SEMC-Browser',
    'SE': 'Sogou Explorer',
    'SO': 'Sogou Mobile Browser',
    'RF': 'SOTI Surf',
    '2S': 'Soul Browser',
    'T0': 'Soundy Browser',
    'SF': 'Safari',
    'PV': 'Safari Technology Preview',
    'S5': 'Safe Exam Browser',
    'D5': 'SafeBrowser',
    'SW': 'SalamWeb',
    'VN': 'Savannah Browser',
    'SD': 'SavySoda',
    'S9': 'Secure Browser',
    'SV': 'SFive',
    'SH': 'Shiira',
    'K1': 'Sidekick',
    'S1': 'SimpleBrowser',
    '3S': 'SilverMob US',
    'ZB': 'Singlebox',
    'SY': 'Sizzy',
    'K3': 'Skye',
    'SK': 'Skyfire',
    'KL': 'SkyLeap',
    'SJ': 'Seekee',
    'SS': 'Seraphic Sraf',
    'KK': 'SiteKiosk',
    'SL': 'Sleipnir',
    '8B': 'SlimBoat',
    'S6': 'Slimjet',
    'S7': 'SP Browser',
    '9S': 'Sony Small Browser',
    '8S': 'Secure Private Browser',
    'X2': 'SecureX',
    'T1': 'Stampy Browser',
    '7S': '7Star',
    'SQ': 'Smart Browser',
    '6S': 'Smart Search & Web Browser',
    'LE': 'Smart Lenovo Browser',
    'OZ': 'Smooz',
    'SM': 'Snap Browser',
    'SN': 'Snowshoe',
    'K5': 'Spark',
    'B1': 'Spectre Browser',
    'S2': 'Splash',
    'SI': 'Sputnik Browser',
    'SR': 'Sunrise',
    '0S': 'Sunflower Browser',
    'SP': 'SuperBird',
    'SU': 'Super Fast Browser',
    '5S': 'SuperFast Browser',
    'HR': 'Sushi Browser',
    'S3': 'surf',
    '4S': 'Surf Browser',
    'RY': 'Surfy Browser',
    'SG': 'Stargon',
    'T6': 'Startpage',
    'S0': 'START Internet Browser',
    'YS': 'Stay Browser',
    '5A': 'Stealth Browser',
    'S4': 'Steam In-Game Overlay',
    'ST': 'Streamy',
    'SX': 'Swiftfox',
    'W7': 'Swiftweasel',
    'SZ': 'Seznam Browser',
    'W1': 'Sweet Browser',
    '2X': 'SX Browser',
    'TP': 'T+Browser',
    'TR': 'T-Browser',
    'TO': 't-online.de Browser',
    'TT': 'TalkTo',
    'TA': 'Tao Browser',
    'T2': 'tararia',
    'TH': 'Thor',
    '1T': 'Tor Browser',
    'TF': 'TenFourFox',
    'TB': 'Tenta Browser',
    'TE': 'Tesla Browser',
    'TZ': 'Tizen Browser',
    'T5': 'Tincat Browser',
    'TI': 'Tint Browser',
    'TL': 'TrueLocation Browser',
    'TC': 'TUC Mini Browser',
    'TK': 'TUSK',
    'TU': 'Tungsten',
    'TG': 'ToGate',
    'T3': 'Total Browser',
    'TQ': 'TQ Browser',
    'TS': 'TweakStyle',
    'TV': 'TV Bro',
    'T4': 'TV-Browser Internet',
    'U0': 'U Browser',
    'UB': 'UBrowser',
    'UC': 'UC Browser',
    'UH': 'UC Browser HD',
    'UM': 'UC Browser Mini',
    'UT': 'UC Browser Turbo',
    'UI': 'Ui Browser Mini',
    'UP': 'UPhone Browser',
    'UR': 'UR Browser',
    'UZ': 'Uzbl',
    'UE': 'Ume Browser',
    'V0': 'vBrowser',
    'VA': 'Vast Browser',
    'VQ': 'VC Browser Mini Pro',
    'V3': 'VD Browser',
    'VR': 'Veera',
    'VE': 'Venus Browser',
    'WD': 'Vewd Browser',
    'V5': 'VibeMate',
    'NQ': 'Nova Browser',
    'N0': 'Nova Video Downloader Pro',
    'VS': 'Viasat Browser',
    'VI': 'Vivaldi',
    'V7': 'Vivaldi Mobile Browser',
    'VV': 'vivo Browser',
    'V2': 'Vivid Browser Mini',
    'VB': 'Vision Mobile Browser',
    'V4': 'Vertex Surf',
    'VM': 'VMware AirWatch',
    'V6': 'VMS Mosaic',
    'VK': 'Vonkeror',
    'VU': 'Vuhuv',
    'WI': 'Wear Internet Browser',
    'WP': 'Web Explorer',
    'W3': 'Web Browser & Explorer',
    'W5': 'Webian Shell',
    'W4': 'WebDiscover',
    'WE': 'WebPositive',
    'W6': 'Weltweitimnetz Browser',
    'WX': 'Wexond',
    'WF': 'Waterfox',
    'WB': 'Wave Browser',
    'WA': 'Wavebox',
    'WH': 'Whale Browser',
    'W2': 'Whale TV Browser',
    'WO': 'wOSBrowser',
    '3W': 'w3m',
    'WT': 'WeTab Browser',
    '1W': 'World Browser',
    'WL': 'Wolvic',
    'WK': 'Wukong Browser',
    'WY': 'Wyzo',
    'YG': 'YAGI',
    'YJ': 'Yahoo! Japan Browser',
    'YA': 'Yandex Browser',
    'Y4': 'Yandex Browser Corp',
    'YL': 'Yandex Browser Lite',
    'YN': 'Yaani Browser',
    'Y2': 'Yo Browser',
    'YB': 'Yolo Browser',
    'YO': 'YouCare',
    'Y3': 'YouBrowser',
    'YZ': 'Yuzu Browser',
    'XR': 'xBrowser',
    'X3': 'MMBOX XBrowser',
    'XB': 'X Browser Lite',
    'X0': 'X-VPN',
    'X1': 'xBrowser Pro Super Fast',
    'XN': 'XNX Browser',
    'X6': 'XPlay Browser',
    'XT': 'XtremeCast',
    'XS': 'xStand',
    'XI': 'Xiino',
    'X4': 'XnBrowse',
    'XO': 'Xooloo Internet',
    'XV': 'Xvast',
    'ZE': 'Zetakey',
    'ZV': 'Zvu',
    'ZI': 'Zirco Browser',
    'ZR': 'Zordo Browser',
    'ZT': 'ZTE Browser',
}

# flip Abbrev / Name for fast membership testing
BROWSER_TO_ABBREV = {browser.lower(): abbrev for abbrev, browser in AVAILABLE_BROWSERS.items()}

# fmt: off
BROWSER_FAMILIES = {
    'Android Browser': ('AN',),
    'BlackBerry Browser': ('BB',),
    'Baidu': ('BD', 'BS', 'H6'),
    'Amiga': ('AV', 'AW'),
    'Chrome': (
        'CH', '2B', '7S', 'A0', 'AC', 'A4', 'AE', 'AH', 'AI',
        'AO', 'AS', 'BA', 'BM', 'BR', 'C2', 'C3', 'C5', 'C4',
        'C6', 'CC', 'CD', 'CE', 'CF', 'CG', '1B', 'CI', 'CL',
        'CM', 'CN', 'CP', 'CR', 'CV', 'CW', 'DA', 'DD', 'DG',
        'DR', 'EC', 'EE', 'EU', 'EW', 'FA', 'FS', 'GB', 'GI',
        'H2', 'HA', 'HE', 'HH', 'HS', 'I3', 'IR', 'JB', 'KN',
        'KW', 'LF', 'LL', 'LO', 'M1', 'MA', 'MD', 'MR', 'MS',
        'MT', 'MZ', 'NM', 'NR', 'O0', 'O2', 'O3', 'OC', 'PB',
        'PT', 'QU', 'QW', 'RM', 'S4', 'S6', 'S8', 'S9', 'SB',
        'SG', 'SS', 'SU', 'SV', 'SW', 'SY', 'SZ', 'T1', 'TA',
        'TB', 'TG', 'TR', 'TS', 'TU', 'TV', 'UB', 'UR', 'VE',
        'VG', 'VI', 'VM', 'WP', 'WH', 'XV', 'YJ', 'FH', 'H8',
        'B1', 'BO', 'HB', 'PC', 'LA', 'LT', 'PD', 'HR', 'HU',
        'HP', 'IO', 'TP', 'CJ', 'HQ', 'HI', 'PN', 'BW', 'YO',
        'DC', 'G8', 'DT', 'AP', 'AK', 'UI', 'SD', 'VN', '4S',
        '2S', 'RF', 'LR', 'SQ', 'BV', 'L1', 'F0', 'KS', 'V0',
        'C8', 'AZ', 'MM', 'BT', 'N0', 'P0', 'F3', 'VS', 'DU',
        'D0', 'P1', 'O4', '8S', 'H3', 'TE', 'WB', 'K1', 'P2',
        'XO', 'U0', 'B0', 'VA', 'X0', 'NX', 'O5', 'R1', 'I1',
        'HO', 'A5', 'X1', '18', 'B5', 'B6', 'TC', 'A6', '2X',
        'F4', 'YG', 'WR', 'NA', 'DM', '1M', 'A7', 'XN', 'XT',
        'XB', 'W1', 'HT', 'B8', 'F5', 'B9', 'WA', 'T0', 'HC',
        'O6', 'P7', 'LJ', 'LC', 'O7', 'N2', 'A8', 'P8', 'RB',
        '1W', 'EV', 'I9', 'V4', 'H4', '1T', 'M5', '0S', '0C',
        'ZR', 'D6', 'F6', 'RC', 'WD', 'P3', 'FT', 'A9', 'X2',
        'N3', 'GD', 'O9', 'Q3', 'F7', 'K2', 'P5', 'H5', 'V3',
        'K3', 'Q4', 'G2', 'R2', 'WX', 'XP', '3I', 'BG', 'R0',
        'JO', 'OL', 'GN', 'W4', 'QI', 'E1', 'RI', '8B', '5B',
        'K4', 'WK', 'T3', 'K5', 'MU', '9P', 'K6', 'VR', 'N9',
        'M9', 'F9', '0P', '0A', 'JR', 'D3', 'TK', 'BP', '2F',
        '2M', 'K7', '1N', '8A', 'H7', 'X3', 'T4', 'X4', '5O',
        '8C', '3M', '6I', '2P', 'PU', '7I', 'X5', 'AL', '3P',
        'W2', 'ZB', 'HN', 'Q6', 'Q7', 'G0', '00', 'R6', 'D8',
        'PQ', 'LM', 'T5', '2N', 'SJ', 'X6', 'SM', 'AY', 'BQ',
        'BC', 'NQ', 'VQ', '9C', 'KA', 'YS', 'D4', 'PZ', '0I',
        '3F', 'Z1', 'XC', 'ZC', 'V7', 'H0', 'IL', 'PG', 'I0',
        'T6',
    ),
    'Firefox': (
        'FF', 'BI', 'BF', 'BH', 'BN', 'C0', 'CU', 'EI', 'F1',
        'FB', 'FE', 'AX', 'FM', 'FR', 'FY', 'I4', 'IF', '8P',
        'IW', 'LH', 'LY', 'MB', 'MN', 'MO', 'MY', 'OA', 'OS',
        'PI', 'PX', 'QA', 'S5', 'SX', 'TF', 'TO', 'WF', 'ZV',
        'FP', 'AD', '2I', 'P9', 'KJ', 'WY', 'VK', 'W5',
        '7C', 'N7', 'W7',
    ),
    'Internet Explorer': ('IE', 'CZ', 'BZ', 'IM', 'PS', '3A', '4A', 'RN', '2E'),
    'Konqueror': ('KO',),
    'NetFront': ('NF', '3N'),
    'NetSurf': ('NE',),
    'Nokia Browser': ('DO', 'NB', 'NO', 'NV'),
    'Opera': (
        'OP', 'OG', 'OH', 'OI', 'OM', 'ON', 'OO', 'O1', 'OX',
        'Y1', '6O',
    ),
    'Safari': ('SF', 'S7', 'MF', 'SO', 'PV'),
    'Sailfish Browser': ('SA',),
}

FAMILY_FROM_ABBREV = {}
for b, codes in BROWSER_FAMILIES.items():
    for code in codes:
        FAMILY_FROM_ABBREV[code] = b.lower()

MOBILE_ONLY_BROWSERS = {
    '36', 'AH', 'AI', 'BL', 'C1', 'C4', 'CB', 'CW', 'DB',
    '3M', 'DT', 'EU', 'EZ', 'FK', 'FM', 'FR', 'FX', 'GH',
    'GI', 'GR', 'HA', 'HU', 'IV', 'JB', 'KD', 'M1', 'MF',
    'MN', 'MZ', 'NX', 'OC', 'OI', 'OM', 'OZ', '2P', 'PI',
    'PE', 'QU', 'RE', 'S0', 'S7', 'SA', '0I', 'SG', 'SK',
    'ST', 'SU', 'T1', 'UH', 'UM', 'UT', 'VE', 'VV', 'WI',
    'WP', 'YN', 'IO', 'IS', 'HQ', 'RW', 'HI', 'PN', 'BW',
    'YO', 'PK', 'MR', 'AP', 'AK', 'UI', 'SD', 'VN', '4S',
    'RF', 'LR', 'SQ', 'BV', 'L1', 'F0', 'KS', 'V0', 'C8',
    'AZ', 'MM', 'BT', 'N0', 'P0', 'F3', 'DU', 'D0', 'P1',
    'O4', 'XO', 'U0', 'B0', 'VA', 'X0', 'A5', 'X1', '18',
    'B5', 'B6', 'TC', 'A6', '2X', 'F4', 'YG', 'WR', 'NA',
    'DM', '1M', 'A7', 'XN', 'XT', 'XB', 'W1', 'HT', 'B7',
    'B9', 'T0', 'I8', 'O6', 'P7', 'O8', '4B', 'A8', 'P8',
    '1W', 'EV', 'Z0', 'I9', 'V4', 'H4', 'M5', '0S', '0C',
    'ZR', 'D6', 'F6', 'P3', 'FT', 'A9', 'X2', 'NI', 'FG',
    'TH', 'N3', 'GD', 'O9', 'Q3', 'F7', 'K2', 'N4', 'P5',
    'H5', 'V3', 'G2', 'BG', 'OL', 'II', 'TL', 'M6', 'Y3',
    'M7', 'GN', 'JR', 'IG', 'HW', '4O', 'OU', '5P', 'KE',
    '5A', 'TT', '6P', 'G3', '7P', 'VU', 'F8', 'L4', 'DK',
    'DP', 'KL', 'K4', 'N6', 'KU', 'WK', 'M8', 'UP', 'ZT',
    '9P', 'N8', 'VR', 'N9', 'M9', 'F9', '0P', '0A', '2F',
    '2M', 'K7', '1N', '8A', 'H7', 'X3', 'X4', '5O', '6I',
    '7I', 'X5', '3P', '2E', 'T5', '2N', 'SJ', 'X6', 'SM',
    'AY', 'BQ', 'BC', 'NQ', 'VQ', 'KA', 'YS', 'D4', 'PZ',
    'V7', 'D5', 'M0', 'Q8', 'T6',
}
# fmt: off

TV_CLIENTS = {
    'Kylo', 'Espial TV Browser', 'LUJO TV Browser', 'LogicUI TV Browser', 'Open TV Browser',
    'Seraphic Sraf', 'Opera Devices', 'Crow Browser', 'Vewd Browser', 'TiviMate',
    'Quick Search TV', 'QJY TV Browser', 'TV Bro',
    'Redline', 'Odin',
}

# Taken from ChromeOS regex in oss.yml
CHROME_OS_MODELS = {
    'asurada', 'atlas', 'brask', 'brox', 'brya', 'cherry', 'coral', 'corsola',
    'dedede', 'drallion', 'elm', 'eve', 'fizz', 'geralt', 'grunt', 'guybrush',
    'hana', 'hatch', 'jacuzzi', 'kalista', 'kukui', 'nami', 'nautilus', 'nirva',
    'nissa', 'nocturne', 'octopus', 'ovis', 'puff', 'pyro', 'rammus', 'rauru',
    'reef', 'rex', 'sand', 'sarien', 'skyrim', 'snappy', 'soraka', 'staryu',
    'strongbad', 'trogdor', 'volteer', 'zork',
}

# Crufty name/version prefixes too generic to be meaningful Client names
# iOS/12.1, CFNetwork/975.0.3, Android/7.0
CRUFT_NAMES = {
    'afma-sdk-a',
    '1.0,win',
    'alamofire',
    'applewebkit',
    'carrier',
    'cfnetwork',
    'client',
    'client-protocol',
    'configuration',
    'darwin',
    'dalvik',
    'hw',
    'j2me',
    'mozilla',
    'mozzila',
    'user-agent:mozilla',
    'android mozilla',
    'mobile',
    'ios',
    'android',
    'ipad',
    'iphone',
    'okhttp',
    'oem',
    'os',
    'opera mobi',
    'profile',
    'scale',
    'sdk',
    'sid',
    'sparkle',
    'ss',
    'winsparkle',
    'symbian',
    'unknown',
    'urbanairshiplib',
    'urbanairshiplib-android',
    'windows',
    'windows nt',
    'win64',
    'wow64',
}

# These keys may provide meaningful information,
# but should never be considered app names.
METADATA_NAMES = {
    'app.webview',
    'app.webview app.webview',
    'build',
    'device',
    'ioswebview',
    'linux',
    'version',
    'wfappid',
    'wfexperience',
    'macosx',
    'x-client',
    'windows',
}

# When parsing UA strings generically, multiple name/version pairs may be found.
# Ignore the uninteresting ones
# Mozilla/5.0 (Symbian/3; Series60/5.2 NokiaN8-00/014.002; Profile/MIDP-2.1 Configuration/CLDC-1.1; en-us) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 BrowserNG/7.2.6.4 3gpp-gba  # noqa
SKIP_PREFIXES = set(AVAILABLE_ENGINES_LOWER_CASE.keys()) | \
                CRUFT_NAMES | \
                set(BROWSER_TO_ABBREV.keys())

CHECK_PAIRS = {
    'Android Browser',
    'Mobile Safari',
    'Chrome Mobile',
    'Chrome',
}


def normalized_name(name: str, abbreviations: dict[str, str], names: dict[str, str]) -> str:
    """
    Lookup Brand name by lower casing to account
    for spelling differences.
    """
    try:
        abbrev = abbreviations[str(name).strip().lower()]
        return names[abbrev]
    except KeyError:
        pass
    return name


__all__ = (
    'APPLE_OS_NAMES',
    'APP_TO_CLIENT_HINT_MAPPING',
    'CHROME_OS_MODELS',
    'CLIENT_HINT_TO_APP_MAP',
    'OS_CLIENT_HINT_MAPPING',
    'ALWAYS_DESKTOP_OS',
    'DESKTOP_OS',
    'OPERATING_SYSTEMS',
    'OS_TO_ABBREV',
    'OS_FAMILIES',
    'FAMILY_FROM_OS',
    'AVAILABLE_ENGINES',
    'AVAILABLE_BROWSERS',
    'BROWSER_FAMILIES',
    'BROWSER_TO_ABBREV',
    'FAMILY_FROM_ABBREV',
    'CHECK_PAIRS',
    'CRUFT_NAMES',
    'METADATA_NAMES',
    'MOBILE_ONLY_BROWSERS',
    'TV_CLIENTS',
    'SKIP_PREFIXES',
    'normalized_name',
)
