# 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'],
    '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'],
}

# 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 = {
    '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',
    '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',
    'HAS': 'HasCodingOS',
    'HEL': 'HELIX OS',
    'IRI': 'IRIX',
    'INF': 'Inferno',
    'JME': 'Java ME',
    'JOL': 'Joli OS',
    'KOS': 'KaiOS',
    'KAL': 'Kali',
    'KAN': 'Kanotix',
    'KIN': 'KIN OS',
    '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',
    'TDX': 'ThreadX',
    'TIT': 'Titan OS',
    'TIZ': 'Tizen',
    'TIV': 'TiVo OS',
    'TOS': 'TmaxOS',
    'TUR': 'Turbolinux',
    'UBT': 'Ubuntu',
    'ULT': 'ULTRIX',
    'UOS': 'UOS',
    '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', 'OHS', 'SMA',
    ],
    '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',
    ),
    'Mac': ('MAC',),
    'Mobile Gaming Console': ('PSP', 'NDS', 'XBX'),
    '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',
    ),
    'WebTV': ('WTV',),
    'Windows': ('WIN',),
    'Windows Mobile': ('WPH', 'WMO', 'WCE', 'WRT', 'WIO', 'KIN'),
    'Other Smart TV': ('WHS', 'TIT', 'ORS'),
    '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',
}
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',
    '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',
    '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',
    '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',
    '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',
    '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',
    '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',
    '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',
    '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',
    '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',
    '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',
    ),
    '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',
    '0I',
}
# 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',
}

# 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',
)
