device_detector-1.1.3/0000755000004100000410000000000014656360042014702 5ustar www-datawww-datadevice_detector-1.1.3/lib/0000755000004100000410000000000014656360041015447 5ustar www-datawww-datadevice_detector-1.1.3/lib/device_detector/0000755000004100000410000000000014656360041020577 5ustar www-datawww-datadevice_detector-1.1.3/lib/device_detector/metadata_extractor.rb0000644000004100000410000000120414656360041024774 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector class MetadataExtractor < Struct.new(:user_agent, :regex_meta) def call regex_meta.any? ? extract_metadata : nil end private def metadata_string message = "#{name} (a child of MetadataExtractor) must implement the '#{__method__}' method." raise NotImplementedError, message end def extract_metadata user_agent.match(regex) do |match_data| metadata_string.gsub(/\$(\d)/) do match_data[Regexp.last_match(1).to_i].to_s end.strip end end def regex @regex ||= regex_meta[:regex] end end end device_detector-1.1.3/lib/device_detector/device.rb0000644000004100000410000014301014656360041022362 0ustar www-datawww-data# 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] 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 device_detector-1.1.3/lib/device_detector/name_extractor.rb0000644000004100000410000000045714656360041024145 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector class NameExtractor < MetadataExtractor def call if /\$[0-9]/ =~ metadata_string extract_metadata else metadata_string end end private def metadata_string regex_meta[:name] end end end device_detector-1.1.3/lib/device_detector/version_extractor.rb0000644000004100000410000000161414656360041024706 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector class VersionExtractor < MetadataExtractor MAJOR_VERSION_2 = Gem::Version.new('2.0') MAJOR_VERSION_3 = Gem::Version.new('3.0') MAJOR_VERSION_4 = Gem::Version.new('4.0') MAJOR_VERSION_8 = Gem::Version.new('8.0') def call simple_version = super&.chomp('.') return simple_version unless simple_version&.empty? os_version_by_regexes end private def os_version_by_regexes version_matches = regex_meta[:versions] return '' unless version_matches version_matches.detect do |matcher| user_agent.match(matcher[:regex]) do |match_data| return matcher[:version].gsub(/\$(\d)/) do match_data[Regexp.last_match(1).to_i].to_s end.strip end end '' end def metadata_string String(regex_meta[:version]) end end end device_detector-1.1.3/lib/device_detector/model_extractor.rb0000644000004100000410000000065014656360041024320 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector class ModelExtractor < MetadataExtractor def call s = super.to_s.gsub('_', ' ').strip s = s.gsub(/ TD$/i, '') return nil if s == 'Build' s.empty? ? nil : s end private def metadata_string String(regex_meta[:model]) end def regex @regex ||= regex_meta[:regex_model] || regex_meta[:regex] end end end device_detector-1.1.3/lib/device_detector/bot.rb0000644000004100000410000000027114656360041021710 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector class Bot < Parser def bot? regex_meta.any? end private def filenames ['bots.yml'] end end end device_detector-1.1.3/lib/device_detector/memory_cache.rb0000644000004100000410000000253114656360041023560 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector class MemoryCache DEFAULT_MAX_KEYS = 5000 STORES_NIL_VALUE = :__is_nil__ attr_reader :data, :max_keys, :lock private :lock def initialize(config) @data = {} @max_keys = config[:max_cache_keys] || DEFAULT_MAX_KEYS @lock = Mutex.new end def set(key, value) lock.synchronize do purge_cache # convert nil values into symbol so we know a value is present cache_value = value.nil? ? STORES_NIL_VALUE : value data[String(key)] = cache_value value end end def get(key) value, _hit = get_hit(key) value end def get_or_set(key, value = nil) string_key = String(key) result, hit = get_hit(string_key) return result if hit value = yield if block_given? set(string_key, value) end private def get_hit(key) value = data[String(key)] is_hit = !value.nil? || value == STORES_NIL_VALUE value = nil if value == STORES_NIL_VALUE [value, is_hit] end def purge_cache key_size = data.size return if key_size < max_keys # always remove about 1/3 of keys to reduce garbage collecting amount_of_keys = key_size / 3 data.keys.first(amount_of_keys).each { |key| data.delete(key) } end end end device_detector-1.1.3/lib/device_detector/os.rb0000644000004100000410000002241014656360041021544 0ustar www-datawww-data# frozen_string_literal: true require 'set' class DeviceDetector class OS < Parser class << self def mapped_os_version(version, mapping) return if version.nil? major_version = version.split('.').first mapping[version] || mapping[major_version] end end def name os_info[:name] end def short_name os_info[:short] end def family os_info[:family] end def desktop? DESKTOP_OSS.include?(family) end def full_version raw_version = super.to_s.split('_').join('.') raw_version == '' ? nil : raw_version end private def os_info from_cache(['os_info', self.class.name, user_agent]) do os_name = NameExtractor.new(user_agent, regex_meta).call if os_name && (short = DOWNCASED_OPERATING_SYSTEMS[os_name.downcase]) os_name = OPERATING_SYSTEMS[short] else short = 'UNK' end { name: os_name, short: short, family: FAMILY_TO_OS[short] } end end # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/OperatingSystem.php#L286-L288 DESKTOP_OSS = Set.new( [ 'AmigaOS', 'IBM', 'GNU/Linux', 'Mac', 'Unix', 'Windows', 'BeOS', 'Chrome OS', 'Chromium OS' ] ) # OS short codes mapped to long names # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/OperatingSystem.php#L42-L220 OPERATING_SYSTEMS = { 'AIX' => 'AIX', 'AND' => 'Android', 'ADR' => 'Android TV', 'ALP' => 'Alpine Linux', 'AMZ' => 'Amazon Linux', 'AMG' => 'AmigaOS', 'ARM' => 'Armadillo OS', 'ARO' => 'AROS', 'ATV' => 'tvOS', 'ARL' => 'Arch Linux', 'AOS' => 'AOSC OS', 'ASP' => 'ASPLinux', 'BTR' => 'BackTrack', 'SBA' => 'Bada', 'BYI' => 'Baidu Yi', 'BEO' => 'BeOS', 'BLB' => 'BlackBerry OS', 'QNX' => 'BlackBerry Tablet OS', 'BOS' => 'Bliss OS', 'BMP' => 'Brew', 'BSN' => 'BrightSignOS', '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', 'CYN' => 'CyanogenMod', 'DEB' => 'Debian', 'DEE' => 'Deepin', 'DFB' => 'DragonFly', 'DVK' => 'DVKBuntu', 'ELE' => 'ElectroBSD', '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', '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', 'KNO' => 'Knoppix', 'KTV' => 'KreaTV', 'KBT' => 'Kubuntu', 'LIN' => 'GNU/Linux', 'LND' => 'LindowsOS', 'LNS' => 'Linspire', 'LEN' => 'Lineage OS', 'LIR' => 'Liri OS', 'LOO' => 'Loongnix', 'LBT' => 'Lubuntu', 'LOS' => 'Lumin OS', 'LUN' => 'LuneOS', 'VLN' => 'VectorLinux', 'MAC' => 'Mac', 'MAE' => 'Maemo', 'MAG' => 'Mageia', 'MDR' => 'Mandriva', 'SMG' => 'MeeGo', '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', 'OS2' => 'OS/2', 'T64' => 'OSF1', 'OBS' => 'OpenBSD', 'OVS' => 'OpenVMS', 'OVZ' => 'OpenVZ', 'OWR' => 'OpenWrt', 'OTV' => 'Opera TV', 'ORA' => 'Oracle Linux', 'ORD' => 'Ordissimo', 'PAR' => 'Pardus', 'PCL' => 'PCLinuxOS', 'PIC' => 'PICO OS', 'PLA' => 'Plasma Mobile', 'PSP' => 'PlayStation Portable', 'PS3' => 'PlayStation', 'PVE' => 'Proxmox VE', 'PUR' => 'PureOS', 'QTP' => 'Qtopia', 'PIO' => 'Raspberry Pi OS', 'RAS' => 'Raspbian', 'RHT' => 'Red Hat', 'RST' => 'Red Star', 'RED' => 'RedOS', 'REV' => 'Revenge OS', 'ROS' => 'RISC OS', 'ROC' => 'Rocky Linux', 'ROK' => 'Roku OS', 'RSO' => 'Rosa', 'ROU' => 'RouterOS', 'REM' => 'Remix OS', 'RRS' => 'Resurrection Remix OS', 'REX' => 'REX', 'RZD' => 'RazoDroiD', 'SAB' => 'Sabayon', 'SSE' => 'SUSE', 'SAF' => 'Sailfish OS', 'SCI' => 'Scientific Linux', 'SEE' => 'SeewoOS', 'SER' => 'SerenityOS', 'SIR' => 'Sirin OS', 'SLW' => 'Slackware', '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', 'TIZ' => 'Tizen', 'TIV' => 'TiVo OS', 'TOS' => 'TmaxOS', 'TUR' => 'Turbolinux', 'UBT' => 'Ubuntu', 'ULT' => 'ULTRIX', 'UOS' => 'UOS', 'VID' => 'VIDAA', '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' }.freeze DOWNCASED_OPERATING_SYSTEMS = OPERATING_SYSTEMS.each_with_object({}) do |(short, long), h| h[long.downcase] = short end.freeze APPLE_OS_NAMES = Set.new(%w[iPadOS tvOS watchOS iOS Mac]).freeze # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/OperatingSystem.php#L227-L269 OS_FAMILIES = { 'Android' => %w[ AND CYN FIR REM RZD MLD MCD YNS GRI HAR ADR CLR BOS REV LEN SIR RRS WER PIC ARM HEL BYI], 'AmigaOS' => %w[AMG MOR ARO], 'BlackBerry' => %w[BLB QNX], 'Brew' => ['BMP'], 'BeOS' => %w[BEO HAI], 'Chrome OS' => %w[COS CRS FYD SEE], 'Firefox OS' => %w[FOS KOS], 'Gaming Console' => %w[WII PS3], 'Google TV' => ['GTV'], 'IBM' => ['OS2'], 'iOS' => %w[IOS ATV WAS IPA], 'RISC OS' => ['ROS'], 'GNU/Linux' => %w[ 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 ], 'Mac' => ['MAC'], 'Mobile Gaming Console' => %w[PSP NDS XBX], 'OpenVMS' => ['OVS'], 'Real-time OS' => %w[MTK TDX MRE JME REX], 'Other Mobile' => %w[WOS POS SBA TIZ SMG MAE LUN GEO], 'Symbian' => %w[SYM SYS SY3 S60 S40], 'Unix' => %w[ SOS AIX HPX BSD NBS OBS DFB SYL IRI T64 INF ELE GNX ULT NWS NXT SBL ], 'WebTV' => ['WTV'], 'Windows' => ['WIN'], 'Windows Mobile' => %w[WPH WMO WCE WRT WIO KIN], 'Other Smart TV' => ['WHS'] }.freeze FAMILY_TO_OS = OS_FAMILIES.each_with_object({}) do |(family, oss), h| oss.each { |os| h[os] = family } end.freeze # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/OperatingSystem.php#L295-L308 FIRE_OS_VERSION_MAPPING = { '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', }.freeze # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/OperatingSystem.php#L315-L337 LINEAGE_OS_VERSION_MAPPING = { '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' }.freeze def filenames ['oss.yml'] end end end device_detector-1.1.3/lib/device_detector/client_hint.rb0000644000004100000410000001704114656360041023427 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector class ClientHint ROOT = File.expand_path('../..', __dir__) REGEX_CACHE = ::DeviceDetector::MemoryCache.new({}) private_constant :REGEX_CACHE class HintBrowser < Struct.new(:name, :version) end def initialize(headers) return if headers.nil? @headers = headers @full_version = extract_full_version @browser_list = extract_browser_list @app_name = extract_app_name @platform = extract_platform @platform_version = extract_platform_version @mobile = extract_mobile @model = extract_model end attr_reader :app_name, :browser_list, :full_version, :headers, :mobile, :model, :platform, :platform_version def browser_name return 'Iridium' if iridium? return '360 Secure Browser' if secure_browser? browser_name_from_list || app_name end def os_version return windows_version if platform == 'Windows' return lineage_version if lineage_os_app? return fire_os_version if fire_os_app? platform_version end def os_name return 'Android' if android_app? return 'Lineage OS' if lineage_os_app? return 'Fire OS' if fire_os_app? return unless ['Windows', 'Chromium OS'].include?(platform) platform end def os_short_name return if os_name.nil? DeviceDetector::OS::DOWNCASED_OPERATING_SYSTEMS[os_name.downcase] end def os_family return if os_short_name.nil? DeviceDetector::OS::FAMILY_TO_OS[os_short_name] end private # https://github.com/matomo-org/device-detector/blob/28211c6f411528abf41304e07b886fdf322a49b7/Parser/OperatingSystem.php#L330 def android_app? %w[com.hisense.odinbrowser com.seraphic.openinet.pre com.appssppa.idesktoppcbrowser every.browser.inc].include?(app_name_from_headers) end # https://github.com/matomo-org/device-detector/blob/67ae11199a5129b42fa8b985d372ea834104fe3a/Parser/OperatingSystem.php#L449-L456 def fire_os_app? app_name_from_headers == 'org.mozilla.tv.firefox' end # https://github.com/matomo-org/device-detector/blob/67ae11199a5129b42fa8b985d372ea834104fe3a/Parser/OperatingSystem.php#L439-L447 def lineage_os_app? app_name_from_headers == 'org.lineageos.jelly' end # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/Client/Browser.php#L1076-L1079 def browser_name_from_list @browser_name_from_list ||= browser_list&.reject do |b| ['Chromium', 'Microsoft Edge'].include?(b.name) end&.last&.name end def available_browsers DeviceDetector::Browser::AVAILABLE_BROWSERS.values end def available_osses DeviceDetector::OS::OPERATING_SYSTEMS.values end # https://github.com/matomo-org/device-detector/blob/28211c6f411528abf41304e07b886fdf322a49b7/Parser/OperatingSystem.php#L434 def windows_version return if platform_version.nil? major_version = platform_version.split('.').first.to_i return if major_version < 1 major_version < 11 ? '10' : '11' end def lineage_version DeviceDetector::OS .mapped_os_version(platform_version, DeviceDetector::OS::LINEAGE_OS_VERSION_MAPPING) end def fire_os_version DeviceDetector::OS .mapped_os_version(platform_version, DeviceDetector::OS::FIRE_OS_VERSION_MAPPING) end # https://github.com/matomo-org/device-detector/blob/67ae11199a5129b42fa8b985d372ea834104fe3a/Parser/Client/Browser.php#L923-L929 # If the version reported from the client hints is YYYY or YYYY.MM (e.g., 2022 or 2022.04), # then it is the Iridium browser # https://iridiumbrowser.de/news/ def iridium? return if browser_list.nil? !browser_list.find do |browser| browser.name == 'Chromium' && browser.version =~ /^202[0-4]/ end.nil? end # https://github.com/matomo-org/device-detector/blob/67ae11199a5129b42fa8b985d372ea834104fe3a/Parser/Client/Browser.php#L931-L937 # https://bbs.360.cn/thread-16096544-1-1.html def secure_browser? return if browser_list.nil? !browser_list.find do |browser| browser.name == 'Chromium' && browser.version =~ /^15/ end.nil? end def app_name_from_headers return if headers.nil? headers['http-x-requested-with'] || headers['X-Requested-With'] || headers['x-requested-with'] end def extract_app_name requested_with = app_name_from_headers return if requested_with.nil? hint_app_names[requested_with] end def hint_app_names DeviceDetector.cache.get_or_set('hint_app_names') do load_hint_app_names.flatten.reduce({}, :merge) end end def hint_filenames %w[client/hints/browsers.yml client/hints/apps.yml] end def hint_filepaths hint_filenames.map do |filename| [filename.to_sym, File.join(ROOT, 'regexes', filename)] end end def load_hint_app_names hint_filepaths.map { |_, full_path| YAML.load_file(full_path) } end def extract_browser_list extract_browser_list_from_full_version_list || extract_browser_list_from_header('Sec-CH-UA') || extract_browser_list_from_header('Sec-CH-UA-Full-Version-List') end def extract_browser_list_from_header(header) return if headers[header].nil? headers[header].split(', ').map do |component| name_and_version = extract_browser_name_and_version(component) next if name_and_version[:name].nil? HintBrowser.new(name_and_version[:name], name_and_version[:version]) end.compact end def extract_browser_name_and_version(component) component_and_version = component.gsub('"', '').split("\;v=") name = name_from_known_browsers(component_and_version.first) browser_version = full_version&.gsub('"', '') || component_and_version.last { name: name, version: browser_version } end def extract_browser_list_from_full_version_list return if headers['fullVersionList'].nil? && headers['brands'].nil? (headers['brands'] || headers['fullVersionList']).map do |item| name = name_from_known_browsers(item['brand']) next if name.nil? HintBrowser.new(name, full_version || item['version']) end.compact end # https://github.com/matomo-org/device-detector/blob/be1c9ef486c247dc4886668da5ed0b1c49d90ba8/Parser/Client/Browser.php#L865 def name_from_known_browsers(name) DeviceDetector::Browser::KNOWN_BROWSER_TO_NAME.fetch(name) do available_browsers.find do |i| i == name || i.gsub(' ', '') == name.gsub(' ', '') || i == name.gsub('Browser', '') || i == name.gsub(' Browser', '') || i == "#{name} Browser" end end end def extract_from_header(header) return if headers[header].nil? || headers[header] == '' headers[header] end def extract_full_version extract_from_header('Sec-CH-UA-Full-Version') || extract_from_header('uaFullVersion') end def extract_platform extract_from_header('Sec-CH-UA-Platform') || extract_from_header('platform') end def extract_platform_version extract_from_header('Sec-CH-UA-Platform-Version') || extract_from_header('platformVersion') end def extract_mobile extract_from_header('Sec-CH-UA-Mobile') || extract_from_header('mobile') end def extract_model extract_from_header('Sec-CH-UA-Model') || extract_from_header('model') end end end device_detector-1.1.3/lib/device_detector/version.rb0000644000004100000410000000011414656360041022605 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector VERSION = '1.1.3' end device_detector-1.1.3/lib/device_detector/client.rb0000644000004100000410000000104614656360041022403 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector class Client < Parser def known? regex_meta.any? end def browser? regex_meta[:path] == :"client/browsers.yml" end def mobile_only_browser? DeviceDetector::Browser.mobile_only_browser?(name) end private def filenames [ 'client/feed_readers.yml', 'client/mobile_apps.yml', 'client/mediaplayers.yml', 'client/pim.yml', 'client/browsers.yml', 'client/libraries.yml' ] end end end device_detector-1.1.3/lib/device_detector/browser.rb0000644000004100000410000005011514656360041022611 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector class Browser # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/Client/Browser.php#L48-L680 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', '4A' => 'Acoo Browser', 'BW' => 'AdBlock Browser', 'A7' => 'Adult Browser', 'A9' => 'Airfind Secure Browser', 'AF' => 'ANT Fresco', 'AG' => 'ANTGalio', 'AL' => 'Aloha Browser', 'AH' => 'Aloha Browser Lite', 'A8' => 'ALVA', 'AM' => 'Amaya', 'A3' => 'Amaze Browser', 'A5' => 'Amerigo', 'AO' => 'Amigo', 'AN' => 'Android Browser', '3A' => 'AOL Explorer', 'AE' => 'AOL Desktop', 'AD' => 'AOL Shield', 'A4' => 'AOL Shield Pro', '2A' => 'Aplix', 'A6' => 'AppBrowzer', 'AP' => 'APUS Browser', 'AR' => 'Arora', 'AX' => 'Arctic Fox', 'AV' => 'Amiga Voyager', 'AW' => 'Amiga Aweb', 'PN' => 'APN Browser', '6A' => 'Arachne', 'RA' => 'Arc', 'AI' => 'Arvin', 'AK' => 'Ask.com', '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', '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', 'BH' => 'BlackHawk', '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', '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', 'CQ' => 'Cliqz', 'CC' => 'Coc Coc', 'C4' => 'CoolBrowser', 'C2' => 'Colibri', '6C' => 'Columbus Browser', 'CD' => 'Comodo Dragon', 'C1' => 'Coast', 'CX' => 'Charon', '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', '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', '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', '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', 'FW' => 'Fireweb', 'FN' => 'Fireweb Navigator', 'FH' => 'Flash Browser', 'FS' => 'Flast', 'F5' => 'Flyperlink', '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', 'HB' => 'Harman Browser', 'HS' => 'HasBrowser', 'HA' => 'Hawk Turbo Browser', 'HQ' => 'Hawk Quick Browser', 'HE' => 'Helio', 'HX' => 'Hexa Web Browser', 'HI' => 'Hi Browser', 'HO' => 'hola! Browser', 'H4' => 'Holla Web Browser', 'H5' => 'HotBrowser', 'HJ' => 'HotJava', 'HT' => 'HTC Browser', 'HU' => 'Huawei Browser Mobile', 'HP' => 'Huawei Browser', 'H3' => 'HUB Browser', 'IO' => 'iBrowser', 'IS' => 'iBrowser Mini', 'IB' => 'IBrowse', 'I6' => 'iDesktop PC Browser', 'IC' => 'iCab', 'I2' => 'iCab Mobile', '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', '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', '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', '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', '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' => 'MIUI Browser', 'MS' => 'Mobile Silk', 'MK' => 'Mogok Browser', 'MN' => 'Minimo', 'MT' => 'Mint Browser', 'MX' => 'Maxthon', 'M4' => 'MaxTube Browser', 'MA' => 'Maelstrom', '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', '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', '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', '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', 'O7' => 'Open TV Browser', 'OW' => 'OmniWeb', 'OT' => 'Otter Browser', '4O' => 'Owl Browser', 'PL' => 'Palm Blazer', 'PM' => 'Pale Moon', 'PY' => 'Polypane', 'PP' => 'Oppo Browser', 'P6' => 'Opus Browser', 'PR' => 'Palm Pre', 'PU' => 'Puffin', '2P' => 'Puffin Web Browser', 'PW' => 'Palm WebPro', 'PA' => 'Palmscape', 'P7' => 'Pawxy', 'PE' => 'Perfect Browser', 'P1' => 'Phantom.me', 'PH' => 'Phantom Browser', 'PX' => 'Phoenix', 'PB' => 'Phoenix Browser', '5P' => 'Photon', 'P9' => 'PirateBrowser', 'P8' => 'PICO Browser', 'PF' => 'PlayFree Browser', 'PK' => 'PocketBook Browser', 'PO' => 'Polaris', 'PT' => 'Polarity', 'LY' => 'PolyBrowser', 'PI' => 'PrivacyWall', 'P4' => 'Privacy Explorer Fast Safe', 'P3' => 'Private Internet Browser', 'P5' => 'Proxy Browser', '7P' => 'Proxyium', '6P' => 'Proxynet', 'P2' => 'Pi Browser', 'P0' => 'PronHub Browser', 'PC' => 'PSI Secure Browser', 'RW' => 'Reqwireless WebViewer', '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', 'QZ' => 'QupZilla', 'QM' => 'Qwant Mobile', 'QW' => 'QtWebEngine', 'R3' => 'Rakuten Browser', 'R4' => 'Rakuten Web Search', 'R2' => 'Raspbian Chromium', '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', 'SY' => 'Sizzy', 'K3' => 'Skye', 'SK' => 'Skyfire', 'KL' => 'SkyLeap', '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', 'SN' => 'Snowshoe', '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', '5A' => 'Stealth Browser', 'S4' => 'Steam In-Game Overlay', 'ST' => 'Streamy', 'SX' => 'Swiftfox', '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', 'TI' => 'Tint Browser', 'TL' => 'TrueLocation Browser', 'TC' => 'TUC Mini Browser', 'TU' => 'Tungsten', 'TG' => 'ToGate', 'TS' => 'TweakStyle', 'TV' => 'TV Bro', 'U0' => 'U Browser', 'UB' => 'UBrowser', 'UC' => 'UC Browser', 'UH' => 'UC Browser HD', 'UM' => 'UC Browser Mini', 'UT' => 'UC Browser Turbo', 'UI' => 'Ui Browser Mini', 'UR' => 'UR Browser', 'UZ' => 'Uzbl', 'UE' => 'Ume Browser', 'V0' => 'vBrowser', 'VA' => 'Vast Browser', 'V3' => 'VD Browser', 'VE' => 'Venus Browser', 'WD' => 'Vewd Browser', 'V5' => 'VibeMate', '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', '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', 'WO' => 'wOSBrowser', '3W' => 'w3m', 'WT' => 'WeTab Browser', '1W' => 'World Browser', 'WL' => 'Wolvic', 'WY' => 'Wyzo', 'YG' => 'YAGI', 'YJ' => 'Yahoo! Japan Browser', 'YA' => 'Yandex Browser', 'YL' => 'Yandex Browser Lite', 'YN' => 'Yaani Browser', 'Y2' => 'Yo Browser', 'YB' => 'Yolo Browser', 'YO' => 'YouCare', 'Y3' => 'YouBrowser', 'YZ' => 'Yuzu Browser', 'XR' => 'xBrowser', 'XB' => 'X Browser Lite', 'X0' => 'X-VPN', 'X1' => 'xBrowser Pro Super Fast', 'XN' => 'XNX Browser', 'XT' => 'XtremeCast', 'XS' => 'xStand', 'XI' => 'Xiino', 'XO' => 'Xooloo Internet', 'XV' => 'Xvast', 'ZE' => 'Zetakey', 'ZV' => 'Zvu', 'ZI' => 'Zirco Browser', 'ZR' => 'Zordo Browser' # detected browsers in older versions # 'IA' => 'Iceape', => pim # 'SM' => 'SeaMonkey', => pim }.freeze BROWSER_FULL_TO_SHORT = AVAILABLE_BROWSERS.invert.freeze # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/Client/Browser.php#L746-L768 MOBILE_ONLY_BROWSERS = Set.new( %w[ 36 AH AI BL C1 C4 CB CW DB DD DT EU EZ FK FM FR FX GH GI GR HA HU IV JB KD M1 MF MN MZ NX OC OI OM OZ PU PI PE QU RE S0 S7 SA SB 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 D3 IG HW 4O OU 5P KE 5A TT 6P G3 7P VU F8 L4 DK DP KL K4 N6 KU ] ).freeze # https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/Client/Browser.php#L775-L783 NAME_TO_KNOWN_BROWSERS = { 'Chrome' => ['Google Chrome'], 'Chrome Webview' => ['Android WebView'], 'DuckDuckGo Privacy Browser' => ['DuckDuckGo'], 'Edge WebView' => ['Microsoft Edge WebView2'], 'Microsoft Edge' => ['Edge'], 'Norton Private Browser' => ['Norton Secure Browser'], 'Vewd Browser' => ['Vewd Core'] }.freeze KNOWN_BROWSER_TO_NAME = NAME_TO_KNOWN_BROWSERS.each_with_object({}) do |(name, browsers), h| browsers.each { |b| h[b] = name } end.freeze def self.mobile_only_browser?(name) return true if MOBILE_ONLY_BROWSERS.include?(name) short = BROWSER_FULL_TO_SHORT[name] MOBILE_ONLY_BROWSERS.include?(short) end end end device_detector-1.1.3/lib/device_detector/vendor_fragment.rb0000644000004100000410000000066114656360041024307 0ustar www-datawww-data# frozen_string_literal: true require 'set' class DeviceDetector class VendorFragment < Parser def name vendor_fragment_info end private def vendor_fragment_info from_cache(['vendor_fragment', self.class.name, user_agent]) do return if regex_meta.nil? || regex_meta.empty? regex_meta[:regex_name] end end def filenames ['vendorfragments.yml'] end end end device_detector-1.1.3/lib/device_detector/parser.rb0000644000004100000410000000565614656360041022434 0ustar www-datawww-data# frozen_string_literal: true class DeviceDetector class Parser ROOT = File.expand_path('../..', __dir__) REGEX_CACHE = ::DeviceDetector::MemoryCache.new({}) private_constant :REGEX_CACHE def initialize(user_agent) @user_agent = user_agent end attr_reader :user_agent def name from_cache(['name', self.class.name, user_agent]) do NameExtractor.new(user_agent, regex_meta).call end end def full_version from_cache(['full_version', self.class.name, user_agent]) do VersionExtractor.new(user_agent, regex_meta).call end end private def regex_meta @regex_meta ||= matching_regex || {} end def matching_regex from_cache([self.class.name, user_agent]) do regexes.find { |r| user_agent =~ r[:regex] } end end def regexes @regexes ||= regexes_for(filepaths) end def filenames raise NotImplementedError end def filepaths filenames.map do |filename| [filename.to_sym, File.join(ROOT, 'regexes', filename)] end end def regexes_for(file_paths) REGEX_CACHE.get_or_set(file_paths) do load_regexes(file_paths).flat_map { |path, regex| parse_regexes(path, regex) } end end def load_regexes(file_paths) file_paths.map do |path, full_path| object = YAML.load_file(full_path) object = rewrite_device_object!(object) if device_yml_file?(full_path) object = rewrite_vendor_object!(object) if vendor_yml_file?(full_path) [path, symbolize_keys!(object)] end end def device_yml_file?(file_path) file_path.include?('/regexes/device/') end def vendor_yml_file?(file_path) file_path.include?('/regexes/vendorfragments') end def rewrite_vendor_object!(object) object.map { |key, values| values.map { |v| { 'regex_name' => key, 'regex' => v } } }.flatten end def rewrite_device_object!(object) object.map { |key, value| [key, { 'regex_name' => key }.merge!(value)] }.to_h end def symbolize_keys!(object) case object when Array object.map! { |v| symbolize_keys!(v) } when Hash keys = object.keys keys.each do |k| object[k.to_sym] = symbolize_keys!(object.delete(k)) if k.is_a?(String) end end object end def parse_regexes(path, raw_regexes) raw_regexes.map do |meta| raise "invalid device spec: #{meta.inspect}" unless meta[:regex].is_a? String meta[:regex] = build_regex(meta[:regex]) meta[:versions].each { |v| v[:regex] = build_regex(v[:regex]) } if meta.key?(:versions) meta[:path] = path meta end end def build_regex(src) Regexp.new("(?:^|[^A-Z0-9_-]|[^A-Z0-9-]_|sprd-|MZ-)(?:#{src})", Regexp::IGNORECASE) end def from_cache(key, &block) DeviceDetector.cache.get_or_set(key, &block) end end end device_detector-1.1.3/lib/device_detector.rb0000644000004100000410000002430514656360041021130 0ustar www-datawww-data# frozen_string_literal: true require 'yaml' require 'device_detector/version' require 'device_detector/metadata_extractor' require 'device_detector/version_extractor' require 'device_detector/model_extractor' require 'device_detector/name_extractor' require 'device_detector/memory_cache' require 'device_detector/parser' require 'device_detector/bot' require 'device_detector/client' require 'device_detector/device' require 'device_detector/os' require 'device_detector/browser' require 'device_detector/client_hint' require 'device_detector/vendor_fragment' class DeviceDetector attr_reader :client_hint, :user_agent def initialize(user_agent, headers = nil) @client_hint = ClientHint.new(headers) utf8_user_agent = encode_user_agent_if_needed(user_agent) @user_agent = build_user_agent(utf8_user_agent) end # https://github.com/matomo-org/device-detector/blob/a2535ff3b63e4187f1d3440aed24ff43d74fb7f1/Parser/Device/AbstractDeviceParser.php#L2065-L2073 def build_user_agent(user_agent) return user_agent if client_hint.model.nil? regex = build_regex('Android 10[.\d]*; K(?: Build/|[;)])') return user_agent unless user_agent =~ regex version = client_hint.os_version || '10' user_agent.gsub(/(Android 10[.\d]*; K)/, "Android #{version}; #{client_hint.model}") end def encode_user_agent_if_needed(user_agent) return if user_agent.nil? return user_agent if user_agent.encoding.name == 'UTF-8' user_agent.encode('utf-8', 'binary', undef: :replace) end def name return client.name if mobile_fix? client_hint.browser_name || client.name end def full_version client_hint.full_version || client.full_version end def os_family return 'GNU/Linux' if linux_fix? client_hint.os_family || os.family || client_hint.platform end def os_name return 'GNU/Linux' if linux_fix? client_hint.os_name || os.name || client_hint.platform end def os_full_version return if skip_os_version? return os.full_version if pico_os_fix? return fire_os_version if fire_os_fix? client_hint.os_version || os.full_version end def device_name return if fake_ua? device.name || client_hint.model || fix_for_x_music end def device_brand return if fake_ua? # Assume all devices running iOS / Mac OS are from Apple brand = device.brand brand = 'Apple' if brand.nil? && DeviceDetector::OS::APPLE_OS_NAMES.include?(os_name) brand end def device_type t = device.type t = nil if fake_ua? # Chrome on Android passes the device type based on the keyword 'Mobile' # If it is present the device should be a smartphone, otherwise it's a tablet # See https://developer.chrome.com/multidevice/user-agent#chrome_for_android_user_agent # Note: We do not check for browser (family) here, as there might be mobile apps using Chrome, # that won't have a detected browser, but can still be detected. So we check the useragent for # Chrome instead. if t.nil? && os_family == 'Android' && user_agent =~ build_regex('Chrome\/[\.0-9]*') t = user_agent =~ build_regex('(?:Mobile|eliboM)') ? 'smartphone' : 'tablet' end # Some UA contain the fragment 'Pad/APad', so we assume those devices as tablets t = 'tablet' if t == 'smartphone' && user_agent =~ build_regex('Pad\/APad') # Some UA contain the fragment 'Android; Tablet;' or 'Opera Tablet', so we assume those devices # as tablets t = 'tablet' if t.nil? && (android_tablet_fragment? || opera_tablet?) # Some user agents simply contain the fragment 'Android; Mobile;', so we assume those devices # as smartphones t = 'smartphone' if t.nil? && android_mobile_fragment? # Some UA contains the 'Android; Mobile VR;' fragment t = 'wearable' if t.nil? && android_vr_fragment? # Android up to 3.0 was designed for smartphones only. But as 3.0, # which was tablet only, was published too late, there were a # bunch of tablets running with 2.x With 4.0 the two trees were # merged and it is for smartphones and tablets # # So were are expecting that all devices running Android < 2 are # smartphones Devices running Android 3.X are tablets. Device type # of Android 2.X and 4.X+ are unknown if t.nil? && os_name == 'Android' && os.full_version && !os.full_version.empty? full_version = Gem::Version.new(os.full_version) if full_version < VersionExtractor::MAJOR_VERSION_2 t = 'smartphone' elsif full_version >= VersionExtractor::MAJOR_VERSION_3 && \ full_version < VersionExtractor::MAJOR_VERSION_4 t = 'tablet' end end # All detected feature phones running android are more likely a smartphone t = 'smartphone' if t == 'feature phone' && os_family == 'Android' # All unknown devices under running Java ME are more likely a features phones t = 'feature phone' if t.nil? && os_name == 'Java ME' # According to http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx # Internet Explorer 10 introduces the "Touch" UA string token. If this token is present at the # end of the UA string, the computer has touch capability, and is running Windows 8 (or later). # This UA string will be transmitted on a touch-enabled system running Windows 8 (RT) # # As most touch enabled devices are tablets and only a smaller part are desktops/notebooks we # assume that all Windows 8 touch devices are tablets. if t.nil? && touch_enabled? && (os_name == 'Windows RT' || (os_name == 'Windows' && os_full_version && Gem::Version.new(os_full_version) >= VersionExtractor::MAJOR_VERSION_8)) t = 'tablet' end # All devices running Opera TV Store are assumed to be a tv t = 'tv' if opera_tv_store? # All devices that contain Andr0id in string are assumed to be a tv if user_agent =~ build_regex('Andr0id|(?:Android(?: UHD)?|Google) TV|\(lite\) TV|BRAVIA') t = 'tv' end # All devices running Tizen TV or SmartTV are assumed to be a tv t = 'tv' if t.nil? && tizen_samsung_tv? # Devices running those clients are assumed to be a TV t = 'tv' if ['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'].include?(name) # All devices containing TV fragment are assumed to be a tv t = 'tv' if t.nil? && user_agent =~ build_regex('\(TV;') has_desktop = t != 'desktop' && desktop_string? && desktop_fragment? t = 'desktop' if has_desktop # set device type to desktop for all devices running a desktop os that were not detected as # another device type return t if t || !desktop? 'desktop' end def known? client.known? end def bot? bot.bot? end def bot_name bot.name end class << self class Configuration attr_accessor :max_cache_keys def to_hash { max_cache_keys: max_cache_keys } end end def config @config ||= Configuration.new end def cache @cache ||= MemoryCache.new(config.to_hash) end def configure @config = Configuration.new yield(config) end end private def bot @bot ||= Bot.new(user_agent) end def client @client ||= Client.new(user_agent) end def device @device ||= Device.new(user_agent) end def os @os ||= OS.new(user_agent) end # https://github.com/matomo-org/device-detector/blob/67ae11199a5129b42fa8b985d372ea834104fe3a/DeviceDetector.php#L931-L938 def fake_ua? device.brand == 'Apple' && !DeviceDetector::OS::APPLE_OS_NAMES.include?(os_name) end # https://github.com/matomo-org/device-detector/blob/be1c9ef486c247dc4886668da5ed0b1c49d90ba8/Parser/Client/Browser.php#L772 # Fix mobile browser names e.g. Chrome => Chrome Mobile def mobile_fix? client.name == "#{client_hint.browser_name} Mobile" end def linux_fix? client_hint.platform == 'Linux' && %w[iOS Android].include?(os.name) && %w[?0 0].include?(client_hint.mobile) end # Related to issue mentionned in device.rb#1562 def fix_for_x_music user_agent&.include?('X-music Ⅲ') ? 'X-Music III' : nil end def pico_os_fix? client_hint.os_name == 'Pico OS' end # https://github.com/matomo-org/device-detector/blob/323629cb679c8572a9745cba9c3803fee13f3cf6/Parser/OperatingSystem.php#L398-L403 def fire_os_fix? !client_hint.platform.nil? && os.name == 'Fire OS' end def fire_os_version DeviceDetector::OS .mapped_os_version(client_hint.os_version, DeviceDetector::OS::FIRE_OS_VERSION_MAPPING) end # https://github.com/matomo-org/device-detector/blob/323629cb679c8572a9745cba9c3803fee13f3cf6/Parser/OperatingSystem.php#L378-L383 def skip_os_version? !client_hint.os_family.nil? && client_hint.os_version.nil? && client_hint.os_family != os.family end def android_tablet_fragment? user_agent =~ build_regex('Android( [\.0-9]+)?; Tablet;|Tablet(?! PC)|.*\-tablet$') end def android_mobile_fragment? user_agent =~ build_regex('Android( [\.0-9]+)?; Mobile;|.*\-mobile$') end def android_vr_fragment? user_agent =~ build_regex('Android( [\.0-9]+)?; Mobile VR;| VR ') end def desktop_fragment? user_agent =~ build_regex('Desktop(?: (x(?:32|64)|WOW64))?;') end def touch_enabled? user_agent =~ build_regex('Touch') end def opera_tv_store? user_agent =~ build_regex('Opera TV Store|OMI/') end def opera_tablet? user_agent =~ build_regex('Opera Tablet') end def tizen_samsung_tv? user_agent =~ build_regex('SmartTV|Tizen.+ TV .+$') end def uses_mobile_browser? client.browser? && client.mobile_only_browser? end # This is a workaround until we support detecting mobile only browsers def desktop_string? user_agent =~ /Desktop/ end def desktop? return false if os_name.nil? || os_name == '' || os_name == 'UNK' # Check for browsers available for mobile devices only return false if uses_mobile_browser? DeviceDetector::OS::DESKTOP_OSS.include?(os_family) end def build_regex(src) Regexp.new('(?:^|[^A-Z0-9\_\-])(?:' + src + ')', Regexp::IGNORECASE) end end device_detector-1.1.3/LICENSE.txt0000644000004100000410000001634714656360041016537 0ustar www-datawww-dataCopyright (c) 2014 Podigee GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License. “The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”. The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. device_detector-1.1.3/device_detector.gemspec0000644000004100000410000000633214656360042021403 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: device_detector 1.1.3 ruby lib Gem::Specification.new do |s| s.name = "device_detector".freeze s.version = "1.1.3" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "changelog_uri" => "https://github.com/podigee/device_detector/blob/develop/CHANGELOG.md" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Mati S\u00F3jka".freeze, "Ben Zimmer".freeze] s.date = "2024-07-03" s.description = "Precise and fast user agent parser and device detector, backed by the largest and most up-to-date agent and device database".freeze s.email = ["yagooar@gmail.com".freeze] s.files = ["CHANGELOG.md".freeze, "LICENSE.txt".freeze, "README.md".freeze, "lib/device_detector.rb".freeze, "lib/device_detector/bot.rb".freeze, "lib/device_detector/browser.rb".freeze, "lib/device_detector/client.rb".freeze, "lib/device_detector/client_hint.rb".freeze, "lib/device_detector/device.rb".freeze, "lib/device_detector/memory_cache.rb".freeze, "lib/device_detector/metadata_extractor.rb".freeze, "lib/device_detector/model_extractor.rb".freeze, "lib/device_detector/name_extractor.rb".freeze, "lib/device_detector/os.rb".freeze, "lib/device_detector/parser.rb".freeze, "lib/device_detector/vendor_fragment.rb".freeze, "lib/device_detector/version.rb".freeze, "lib/device_detector/version_extractor.rb".freeze, "regexes/bots.yml".freeze, "regexes/client/browser_engine.yml".freeze, "regexes/client/browsers.yml".freeze, "regexes/client/feed_readers.yml".freeze, "regexes/client/hints/apps.yml".freeze, "regexes/client/hints/browsers.yml".freeze, "regexes/client/libraries.yml".freeze, "regexes/client/mediaplayers.yml".freeze, "regexes/client/mobile_apps.yml".freeze, "regexes/client/pim.yml".freeze, "regexes/device/cameras.yml".freeze, "regexes/device/car_browsers.yml".freeze, "regexes/device/consoles.yml".freeze, "regexes/device/mobiles.yml".freeze, "regexes/device/notebooks.yml".freeze, "regexes/device/portable_media_player.yml".freeze, "regexes/device/shell_tv.yml".freeze, "regexes/device/televisions.yml".freeze, "regexes/oss.yml".freeze, "regexes/vendorfragments.yml".freeze] s.homepage = "http://podigee.github.io/device_detector".freeze s.licenses = ["LGPL-3.0".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.7.5".freeze) s.rubygems_version = "3.3.15".freeze s.summary = "Precise and fast user agent parser and device detector".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0.10"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["= 0.85.1"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0.10"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["= 0.85.1"]) end end device_detector-1.1.3/regexes/0000755000004100000410000000000014656360041016343 5ustar www-datawww-datadevice_detector-1.1.3/regexes/client/0000755000004100000410000000000014656360041017621 5ustar www-datawww-datadevice_detector-1.1.3/regexes/client/libraries.yml0000644000004100000410000003423614656360041022330 0ustar www-datawww-data############### # Device Detector - The Universal Device Detection library for parsing User Agents # # @link https://matomo.org # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later ############### - regex: 'IPinfoClient/.*/(\d+[\.\d]+)' name: 'IPinfo' version: '$1' url: 'https://github.com/ipinfo' - regex: 'kiwi-tcms/(\d+[\.\d]+)' name: 'Kiwi TCMS' version: '$1' url: 'https://kiwitcms.org' - regex: 'tcms-api/(\d+[\.\d]+)' name: 'Kiwi TCMS API' version: '$1' url: 'https://kiwitcms.org' - regex: 'Fuzz Faster U Fool v(\d+[\.\d]+)' name: 'FFUF' version: '$1' url: 'https://github.com/ffuf/ffuf' - regex: 'Slim Framework' name: 'Slim Framework' version: '' url: 'https://www.slimframework.com/' - regex: 'msray-plus' name: 'Msray-Plus' version: '' url: 'https://github.com/super-l/msray' - regex: 'HTMLParser(?:/(\d+[\.\d]+))?' name: 'HTML Parser' version: '$1' url: 'https://htmlparser.sourceforge.net/' # got - a nodejs library - regex: '^got(?:/(\d+\.[.\d]+))? \(' name: 'got' version: '$1' url: 'https://github.com/sindresorhus/got' # Typhoeus - regex: 'Typhoeus' name: 'Typhoeus' version: '' url: 'https://github.com/typhoeus/typhoeus' # req - regex: 'req/v([\.\d]+)' name: 'req' version: '$1' url: 'https://github.com/imroc/req' # quic-go - regex: 'quic-go-HTTP/3' name: 'quic-go' version: '' url: 'https://github.com/lucas-clemente/quic-go' # Azure Data Factory - regex: 'azure-data-factory(?:/(\d+[\.\d]+))?' name: 'Azure Data Factory' version: '$1' url: 'https://azure.microsoft.com/en-us/products/data-factory/' # Dart - regex: 'Dart(?:/(\d+[\.\d]+))?' name: 'Dart' version: '$1' url: 'https://dart.dev/' # r-curl - regex: 'r-curl(?:/(\d+[\.\d]+))?' name: 'r-curl' version: '$1' url: 'https://github.com/jeroen/curl' # HTTPX - regex: 'python-httpx(?:/(\d+[\.\d]+))?' name: 'HTTPX' version: '$1' url: 'https://www.python-httpx.org/' # fasthttp - regex: 'fasthttp(?:/(\d+[\.\d]+))?' name: 'fasthttp' version: '$1' url: 'https://github.com/valyala/fasthttp' # GeoIP Update - regex: 'geoipupdate(?:/(\d+[\.\d]+))?' name: 'GeoIP Update' version: '$1' url: 'https://github.com/maxmind/geoipupdate' # PHP cURL Class - regex: 'PHP-Curl-Class(?:/(\d+[\.\d]+))?' name: 'PHP cURL Class' version: '$1' url: 'https://github.com/php-curl-class/php-curl-class' # cPanel HTTP Client - regex: 'Cpanel-HTTP-Client(?:/(\d+[\.\d]+))?' name: 'cPanel HTTP Client' version: '$1' url: 'https://www.cpanel.net/' # AnyEvent HTTP - regex: 'AnyEvent-HTTP(?:/(\d+[\.\d]+))?' name: 'AnyEvent HTTP' version: '$1' url: 'http://software.schmorp.de/pkg/AnyEvent' # SlimerJS - regex: 'SlimerJS/(\d+[\.\d]+)' name: 'SlimerJS' version: '$1' url: 'https://www.slimerjs.org/' - regex: 'Wget(?:/(\d+[\.\d]+))?' name: 'Wget' version: '$1' - regex: 'Guzzle(?:Http)?(?:/(\d+[\.\d]+))?' name: 'Guzzle (PHP HTTP Client)' version: '$1' # symphony php http client - regex: '^Symfony HttpClient/' name: 'Symfony' version: '$1' - regex: '(?:lib)?curl(?:/(\d+[\.\d]+))?' name: 'curl' version: '$1' - regex: 'python-requests(?:/(\d+[\.\d]+))?' name: 'Python Requests' version: '$1' - regex: 'Python-httplib2(?:/(\d+[\.\d]+))?' name: 'httplib2' version: '$1' url: 'https://pypi.org/project/httplib2/' - regex: 'Python-urllib3?(?:/?(\d+[\.\d]+))?' name: 'Python urllib' version: '$1' - regex: 'Apache-HttpClient(?:/?(\d+[\.\d]+))?' name: 'Apache HTTP Client' version: '$1' - regex: 'Java-http-client(?:/?(\d+[\.\d]+))?' name: 'Java HTTP Client' version: '$1' - regex: 'Java(?:/?(\d+[\.\d]+))?' name: 'Java' version: '$1' - regex: '(?:perlclient|libwww-perl)(?:/?(\d+[\.\d]+))?' name: 'Perl' version: '$1' - regex: 'grpc-java-okhttp/([\d\.]+)' name: 'gRPC-Java' version: '$1' url: 'https://github.com/grpc/grpc-java' # java library - regex: '(?:okhttp|network-okhttp3)/([\d\.]+)' name: 'OkHttp' version: '$1' - regex: 'okhttp3-([\d\.]+)' name: 'OkHttp' version: '$1' - regex: 'HTTP_Request2(?:/(\d+[\.\d]+))?' name: 'HTTP_Request2' version: '$1' - regex: 'HTTP_Request2(?:/(\d+[\.\d]+))?' name: 'HTTP_Request2' version: '$1' url: 'https://pear.php.net/package/http_request2' - regex: 'Mechanize(?:/(\d+[\.\d]+))?' name: 'Mechanize' version: '$1' url: 'https://github.com/sparklemotion/mechanize' - regex: 'aiohttp(?:/(\d+[\.\d]+))?' name: 'aiohttp' version: '$1' - regex: 'Google-HTTP-Java-Client(?:/(\d+[\.\w-]+))?' name: 'Google HTTP Java Client' version: '$1' - regex: 'WWW-Mechanize(?:/(\d+[\.\d]+))?' name: 'WWW-Mechanize' version: '$1' - regex: 'Faraday(?: v(\d+[\.\d]+))?' name: 'Faraday' version: '$1' url: 'https://github.com/lostisland/faraday' - regex: '(?:Go-http-client|Go )/?(?:(\d+[\.\d]+))?(?: package http)?' name: 'Go-http-client' version: '$1' - regex: 'urlgrabber(?:/(\d+[\.\d]+))?' name: 'urlgrabber (yum)' version: '$1' - regex: 'libdnf(?:/(\d+[\.\d]+))?' name: 'libdnf' version: '$1' - regex: 'HTTPie(?:/(\d+[\.\d]+))?' name: 'HTTPie' version: '$1' - regex: 'rest-client/(\d+\.[\.\d]+) .*ruby' name: 'REST Client for Ruby' version: '$1' - regex: 'RestSharp/(\d+[\.\d]+)' name: 'RestSharp' version: '$1' url: 'https://github.com/restsharp/RestSharp' - regex: 'scalaj-http/(\d+[\.\d]+)' name: 'ScalaJ HTTP' version: '$1' url: 'https://github.com/scalaj/scalaj-http' - regex: 'REST::Client/(\d+)' name: 'Perl REST::Client' version: '$1' url: 'https://metacpan.org/pod/REST::Client' - regex: 'node-fetch/?(\d+[\.\d]+)?' name: 'Node Fetch' version: '$1' url: 'https://github.com/node-fetch/node-fetch' - regex: 'electron-fetch/?(\d+[\.\d]+)?' name: 'Electron Fetch' version: '$1' url: 'https://github.com/arantes555/electron-fetch' - regex: 'ReactorNetty/(\d+[\.\d]+)' name: 'ReactorNetty' version: '$1' url: 'https://github.com/reactor/reactor-netty' - regex: 'PostmanRuntime(?:/(\d+[\.\d]+))?' name: 'Postman Desktop' version: '$1' url: 'https://github.com/postmanlabs/postman-runtime' - regex: 'insomnia(?:/(\d+[\.\d]+))?' name: 'Insomnia REST Client' version: '$1' url: 'https://insomnia.rest' - regex: 'Jakarta Commons-HttpClient/([\.\d]+)' name: 'Jakarta Commons HttpClient' version: '$1' url: 'https://hc.apache.org/httpclient-3.x' - regex: 'WinHttp\.WinHttpRequest.+([\.\d]+)' name: 'WinHttp WinHttpRequest' version: '$1' - regex: 'WinHTTP' name: 'Windows HTTP' version: '' # THTTPClient in delphi 10+ default useragent - regex: 'Embarcadero URI Client/([\.\d]+)' name: 'Embarcadero URI Client' version: '$1' - regex: 'Mikrotik/([\.\d]+)' name: 'Mikrotik Fetch' version: '$1' - regex: 'GRequests(?:/(\d+[\.\d]+))?' name: 'GRequests' version: '$1' # https://doc.akka.io/ - regex: 'akka-http/([\.\d]+)' name: 'Akka HTTP' version: '$1' # this added need added tests - regex: 'aria2(?:/(\d+[\.\d]+))?' name: 'Aria2' version: '$1' - regex: '(?:BTWebClient/|^uTorrent/)' name: 'uTorrent' version: '' - regex: 'gvfs/(?:(\d+[\.\d]+))?' name: 'gvfs' version: '$1' # https://openwrt.org/packages/pkgdata/uclient-fetch - regex: 'uclient-fetch' name: 'uclient-fetch' version: '' # https://github.com/microsoft/cpprestsdk - regex: 'cpprestsdk/([\.\d]+)' name: 'C++ REST SDK' version: '$1' - regex: 'lua-resty-http/([\.\d]+).+ngx_' name: 'LUA OpenResty NGINX' version: '$1' # https://github.com/Kong/unirest-java - regex: 'unirest-java/([\.\d]+)' name: 'Unirest for Java' version: '$1' # jsdom (https://github.com/jsdom/jsdom) - regex: 'jsdom/([\.\d]+)' name: 'jsdom' version: '$1' # hackney (https://github.com/benoitc/hackney) (elixir) - regex: 'hackney/([\.\d]+)' name: 'hackney' version: '$1' # Resty (https://github.com/go-resty/resty) - regex: 'go-resty/([\.\d]+)' name: 'Resty' version: '$1' # Pa11y (https://pa11y.org/) - regex: 'pa11y/([\.\d]+)' name: 'Pa11y' version: '$1' # Ultimate Sitemap Parser (https://github.com/mediacloud/ultimate-sitemap-parser) - regex: 'ultimate_sitemap_parser/([\.\d]+)' name: 'Ultimate Sitemap Parser' version: '$1' # Container-related useragents # Artifactory (https://jfrog.com/de/artifactory/) - regex: 'Artifactory/([\.\d]+)' name: 'Artifactory' version: '$1' # Open build service (https://build.opensuse.org/) - regex: 'BSRPC ([\.\d]+)' name: 'Open Build Service' version: '$1' # Buildah (https://github.com/containers/buildah) - regex: 'Buildah/([\.\d]+)' name: 'Buildah' version: '$1' # Buildkit (https://github.com/moby/buildkit) - regex: 'buildkit/v?([\.\d]+)' name: 'BuildKit' version: '$1' # containerd (https://github.com/containerd/containerd) - regex: 'containerd/v?([\.\d]+)' name: 'Containerd' version: '$1' # containers (https://github.com/containers/image) - regex: 'containers/([\.\d]+)' name: 'containers' version: '$1' # cri-o (https://github.com/cri-o/cri-)o - regex: 'cri-o/([\.\d]+)' name: 'cri-o' version: '$1' # docker (https://github.com/moby/moby) - regex: 'docker/([\.\d]+)' name: 'docker' version: '$1' # gcr (https://github.com/google/go-containerregistry) - regex: 'go-containerregistry/v([\.\d]+)' name: 'go-container registry' version: '$1' # libpod (https://github.com/dankohn/libpod) - regex: 'libpod/([\.\d]+)' name: 'libpod' version: '$1' # skopeo (https://github.com/containers/skopeo) - regex: 'skopeo/([\.\d]+)' name: 'Skopeo' version: '$1' # helm (https://github.com/helm/helm) - regex: 'Helm/([\.\d]+)' name: 'Helm' version: '$1' # harbor client (https://goharbor.io/) - regex: 'harbor-registry-client' name: 'Harbor registry client' version: '' # axios http (https://axios-http.com/) - regex: 'axios(?:/?(\d+[\.\d]+))?' name: Axios version: '$1' # Classier solution for file uploads for Rails, Sinatra and other Ruby web frameworks - regex: '^CarrierWave/(\d+\.[.\d]+)' name: 'CarrierWave' version: '$1' - regex: '^Deno/(\d+\.[.\d]+)' name: 'Deno' version: '$1' # Streaming downloads using net/http, http.rb, HTTPX or wget (ruby) - regex: '^Down/(\d+\.[.\d]+)' name: 'Down' version: '$1' # various programs can use this, like vlc, but the underlying lib is ffmpeg - regex: '^Lavf/' name: 'ffmpeg' version: '$1' - regex: '^FileDownloader/(\d+\.[.\d]+)' name: 'FileDownloader' version: '$1' # Allows managing large files with git, without storing the file contents in git - regex: '^git-annex/(\d+\.[.\d]+)' name: 'git-annex' version: '$1' - regex: '^GStreamer(?: souphttpsrc)[ /](\d+\.[.\d]+)?' name: 'GStreamer' version: '$1' # A small, simple, correct HTTP/1.1 client (Perl) - regex: '^HTTP-Tiny/(\d+\.[.\d]+)' name: 'HTTP:Tiny' version: '$1' - regex: 'KaiOS Downloader' name: 'KaiOS Downloader' version: '' # HTTP client/server library for GNOME - regex: '^libsoup/(\d+\.[.\d]+)' name: 'libsoup' version: '$1' - regex: '^Android\.LVLDM$' name: 'Android License Verification Library' version: '$1' # A file downloader library for Android with pause and resume support - regex: '^PRDownloader$' name: 'PRDownloader' version: '' # a rust http library - regex: '^reqwest/(\d+\.[.\d]+)' name: 'reqwest' version: '$1' # lua http library - regex: '^resty-requests' name: 'resty-requests' version: '' # ruby core lib http download - regex: '^Ruby' name: 'ruby' version: '' # SFSafariViewController, some safari service - regex: '^SafariViewService/(\d+\.[.\d]+)' name: 'Safari View Service' version: '$1' # a nodejs lib - regex: '^undici$' name: 'undici' version: '' # URL, an emacs plugin - regex: '^URL/Emacs Emacs/(\d+\.[.\d]+)' name: 'Emacs' version: '$1' - regex: '^FDM[ /]([\d\.]+)' name: 'Free Download Manager' version: '$1' # 'https://github.com/lingochamp/okdownload' - regex: 'OkDownload/([\d\.]+)' name: 'OKDownload Library' version: '$1' # podcast host https://libsyn.com (probably an importer) - regex: '^Libsyn4-?(?:peek|download)$' name: 'Libsyn' version: '' # any ios application that uses apple core media but doesn't set its user # agent will default to this, always with 1.0.0 version. # there was a time when (not even that long ago) apple didn't let you set # a user agent so a ton of random applications still identify themselves this way. - regex: 'AppleCoreMedia/1\.0\.0' name: 'iOS Application' version: '' - regex: 'cpp-httplib(?:/(\d+[\.\d]+))?' name: 'cpp-httplib' version: '$1' url: 'https://github.com/yhirose/cpp-httplib' - regex: 'Definitely-Not-Requests' name: 'Requests' version: '' url: 'https://github.com/psf/requests' - regex: 'Stealer ([\d\.]+)' name: 'Stealer' version: '$1' url: 'https://github.com/hotrush/stealer/' - regex: 'Mandrill-PHP(?:/(\d+[\.\d]+))?' name: 'Mandrill PHP' version: '$1' url: 'https://bitbucket.org/mailchimp/mandrill-api-php/src/master/' - regex: '^Podgrab' name: 'Podgrab' version: '' url: 'https://github.com/akhilrex/podgrab' - regex: '^Podcast Provider.*?Radio Downloader ([\d\.]+)' name: 'Radio Downloader' version: '$1' url: 'https://nerdoftheherd.com/tools/radiodld/' - regex: '^ESP32 HTTP Client/([\d\.]+)' name: 'ESP32 HTTP Client' version: '$1' url: 'https://github.com/espressif/arduino-esp32' - regex: 'babashka\.http-client(?:/(\d+[\.\d]+))?' name: 'Babashka HTTP Client' version: '$1' url: 'https://github.com/babashka/http-client' - regex: 'http\.rb(?:/(\d+[\.\d]+))?' name: 'http.rb' version: '$1' url: 'https://github.com/httprb/http' - regex: 'node-superagent(?:/(\d+[\.\d]+))?' name: 'superagent' version: '$1' url: 'https://github.com/ladjs/superagent' - regex: 'CakePHP' name: 'CakePHP' version: '' url: 'https://www.cakephp.org/' - regex: 'request\.js' name: 'request' version: '' url: 'https://github.com/request/request' - regex: 'qbhttp(?:/(\d+[\.\d]+))?' name: 'QbHttp' version: '$1' url: 'https://github.com/OpenQb/QbHttp' - regex: 'httprs(?:/(\d+[\.\d]+))?' name: 'httprs' version: '$1' url: 'https://github.com/http-server-rs/http-server' - regex: 'Boto3(?:/(\d+[\.\d]+))?' name: 'Boto3' version: '$1' url: 'https://github.com/boto/boto3' - regex: 'Python-xmlrpc(?:/(\d+[\.\d]+))?' name: 'XML-RPC' version: '$1' url: 'https://docs.python.org/3/library/xmlrpc.html' - regex: 'ICAP-Client-Library(?:/(\d+[\.\d]+))?' name: 'ICAP Client' version: '$1' url: 'https://github.com/Peoplecantfly/icapserver' device_detector-1.1.3/regexes/client/pim.yml0000644000004100000410000000740414656360041021136 0ustar www-datawww-data############### # Device Detector - The Universal Device Detection library for parsing User Agents # # @link https://matomo.org # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later ############### - regex: 'Outlook-Express(?:/(\d+[\.\d]+))?' name: 'Outlook Express' version: '$1' # Outlook https://apps.apple.com/ru/app/microsoft-outlook/id951937596 - regex: '^Outlook-iOS/(?:.+\((\d+[\.\d]+)\)$)?' name: 'Microsoft Outlook' version: '$1' - regex: '(?:(?:Microsoft )?Outlook|MacOutlook)(?:[/ ](\d+[\.\d]+))?' name: 'Microsoft Outlook' version: '$1' # Default Mail Client for Windows - regex: 'WindowsMail(?:/(\d+[\.\d]+))' name: 'Windows Mail' version: '$1' - regex: '(?:Thunderbird|Icedove|Shredder)(?:/(\d+[\.\d]+))?' name: 'Thunderbird' version: '$1' # Spicebird (http://www.spicebird.org/) - regex: 'Spicebird/(\d+\.[\.\d]+)' name: 'Spicebird' version: '$1' - regex: 'Airmail(?: (\d+[\.\d]+))?' name: 'Airmail' version: '$1' - regex: 'Lotus-Notes(?:/(\d+[\.\d]+))?' name: 'Lotus Notes' version: '$1' - regex: 'Barca(?:Pro)?(?:[/ ](\d+[\.\d]+))?' name: 'Barca' version: '$1' - regex: 'Postbox(?:[/ ](\d+[\.\d]+))?' name: 'Postbox' version: '$1' - regex: 'MailBar(?:[/ ](\d+[\.\d]+))?' name: 'MailBar' version: '$1' - regex: 'The Bat!(?: Voyager)?(?:[/ ](\d+[\.\d]+))?' name: 'The Bat!' version: '$1' - regex: 'DAVdroid(?:/(\d+[\.\d]+))?' name: 'DAVdroid' version: '$1' # SeaMonkey - regex: '(?:SeaMonkey|Iceape)(?:/(\d+[\.\d]+))?' name: 'SeaMonkey' version: '$1' # Live5ch - regex: 'Live5ch/(\d+[\.\d]+)' name: 'Live5ch' version: '$1' - regex: 'JaneView/' name: 'JaneView' version: '' - regex: 'BathyScaphe/' name: 'BathyScaphe' version: '' # Raindrop.io (https://raindrop.io/) - regex: 'Raindrop\.io/(\d+[\.\d]+)' name: 'Raindrop.io' version: '$1' # Franz (https://meetfranz.com/) - regex: 'Franz/(\d+[\.\d]+)' name: 'Franz' version: '$1' # Mailspring (https://www.electronjs.org/apps/mailspring) - regex: 'Mailspring/(\d+[\.\d]+)' name: 'Mailspring' version: '$1' # Notion (https://www.notion.so/) - regex: 'Notion/(\d+[\.\d]+)' name: 'Notion' version: '$1' # Basecamp (https://basecamp.com/) - regex: 'Basecamp[0-9]/?(\d+[\.\d]+)' name: 'Basecamp' version: '$1' # Evernote (https://evernote.com/) - regex: 'Evernote/?(\d+[\.\d]+)' name: 'Evernote' version: '$1' # Rambox Pro (https://rambox.app/) - regex: 'ramboxpro/(\d+\.[\.\d]+)?' name: 'Rambox Pro' version: '$1' # Mailbird (https://www.getmailbird.com/) - regex: 'Mailbird/(\d+\.[\.\d]+)/' name: 'Mailbird' version: '$1' # Yahoo Mail (https://apps.apple.com/us/app/yahoo-mail-organised-email/id577586159) - regex: 'Yahoo%20Mail' name: 'Yahoo Mail' version: '' # Yahoo! Mail (https://play.google.com/store/apps/details?id=jp.co.yahoo.android.ymail | https://apps.apple.com/jp/app/yahoo-%E3%83%A1%E3%83%BC%E3%83%AB/id669931877) - regex: 'jp.co.yahoo.ymail/([\d\.]+)' name: 'Yahoo! Mail' version: '$1' # eM Client (https://emclient.com/) - regex: 'eM ?Client/(\d+\.[\.\d]+)' name: 'eM Client' version: '$1' # NAVER Mail (https://play.google.com/store/apps/details?id=com.nhn.android.mail) - regex: 'NaverMailApp/(\d+\.[\.\d]+)' name: 'NAVER Mail' version: '$1' - regex: '^Mail/([\d\.]+)' name: 'Apple Mail' version: '$1' # Foxmail (https://www.foxmail.com/) - regex: 'Foxmail/(\d+[\.\d]+)' name: 'Foxmail' version: '$1' # Mail Master (https://apps.apple.com/mw/app/mail-master-by-netease/id897003024) - regex: 'MailMaster(?:PC)?/(\d+[\.\d]+)' name: 'Mail Master' version: '$1' # BlueMail (https://bluemail.me/) - regex: 'BlueMail/(\d+[\.\d]+)' name: 'BlueMail' version: '$1' - regex: 'mailapp/(\d+\.[\.\d]+)' name: 'mailapp' version: '$1' # Gmail - regex: 'Android-Gmail' name: 'Gmail' version: '' device_detector-1.1.3/regexes/client/hints/0000755000004100000410000000000014656360041020746 5ustar www-datawww-datadevice_detector-1.1.3/regexes/client/hints/browsers.yml0000644000004100000410000002741014656360041023343 0ustar www-datawww-data# Browsers 'mark.via.gg': 'Via' 'mark.via.gp': 'Via' 'mark.via.gq': 'Via' 'mark.via.pm': 'Via' 'com.pure.mini.browser': 'Pure Mini Browser' 'pure.lite.browser': 'Pure Lite Browser' 'acr.browser.Hexa': 'Hexa Web Browser' 'acr.browser.raisebrowserfull': 'Raise Fast Browser' 'acr.tez.browse': 'Browspeed Browser' 'com.Fast.BrowserUc.lite': 'Fast Browser UC Lite' 'acr.browser.barebones': 'Lightning Browser' 'anar.app.darkweb': 'Dark Web Browser' 'com.darkbrowser': 'Dark Browser' 'com.kiwibrowser.browser': 'Kiwi' 'com.cloudmosa.puffinFree': 'Puffin Web Browser' 'com.cloudmosa.puffin': 'Puffin Web Browser' # Puffin Cloud Browser or Puffin Web Browser Pro 'com.aloha.browser': 'Aloha Browser' 'com.cake.browser': 'Cake Browser' 'com.UCMobile.intl': 'UC Browser' 'com.iebrowser.fast': 'IE Browser Fast' 'com.internet.browser.secure': 'Internet Browser Secure' 'acr.browser.linxy': 'Vegas Browser' 'com.oh.bro': 'OH Browser' 'com.oh.brop': 'OH Private Browser' 'com.duckduckgo.mobile.android': 'DuckDuckGo Privacy Browser' 'net.onecook.browser': 'Stargon' 'com.mi.globalbrowser.mini': 'Mint Browser' 'com.hisense.odinbrowser': 'Odin Browser' 'com.brave.browser': 'Brave' 'com.brave.browser_beta': 'Brave' 'org.mozilla.klar': 'Firefox Klar' 'phx.hot.browser': 'Anka Browser' 'com.anka.browser': 'Anka Browser' 'org.mozilla.focus': 'Firefox Focus' 'org.mozilla.tv.firefox': 'Firefox Focus' 'com.vivaldi.browser': 'Vivaldi' 'web.browser.dragon': 'Dragon Browser' 'org.easyweb.browser': 'Easy Browser' 'com.xbrowser.play': 'XBrowser Mini' 'com.sharkeeapp.browser': 'Sharkee Browser' 'com.mobiu.browser': 'Lark Browser' 'com.qflair.browserq': 'Pluma' 'com.noxgroup.app.browser': 'Nox Browser' 'com.jio.web': 'JioSphere' 'com.ume.browser.cust': 'Ume Browser' 'com.ume.browser.international': 'Ume Browser' 'com.ume.browser.bose': 'Ume Browser' 'com.ume.browser.euas': 'Ume Browser' 'com.ume.browser.latinamerican': 'Ume Browser' 'com.ume.browser.mexicotelcel': 'Ume Browser' 'com.ume.browser.venezuelavtelca': 'Ume Browser' 'com.ume.browser.northamerica': 'Ume Browser' 'com.ume.browser.newage': 'Ume Browser' 'com.kuto.browser': 'KUTO Mini Browser' 'com.dolphin.browser.zero': 'Dolphin Zero' 'mobi.mgeek.TunnyBrowser': 'Dolphin' # Dolphin + AdBlock 'nextapp.atlas': 'Atlas' 'org.mozilla.rocket': 'Firefox Rocket' # Firefox Lite 'com.mx.browser': 'Maxthon' 'com.ecosia.android': 'Ecosia' 'org.lineageos.jelly': 'Jelly' 'com.opera.gx': 'Opera GX' 'br.marcelo.monumentbrowser': 'Monument Browser' 'com.airfind.deltabrowser': 'Delta Browser' 'com.apusapps.browser': 'APUS Browser' 'com.ask.browser': 'Ask.com' 'com.browser.tssomas': 'Super Fast Browser' 'iron.web.jalepano.browser': 'SuperFast Browser' 'yuce.browser.mini': 'Ui Browser Mini' 'SavySoda.PrivateBrowsing': 'SavySoda' 'savannah.internet.web.browser': 'Savannah Browser' 'com.gl9.cloudBrowser': 'Surf Browser' 'com.ucold.browser.secure.browse': 'UC Browser Mini' 'com.mycompany.app.soulbrowser': 'Soul Browser' 'com.quickbig.browser': 'Indian UC Mini Browser' # (alternative name Splash UC Mini Browser) 'com.opera.browser': 'Opera' 'com.opera.mini.native': 'Opera Mini' 'com.wSilverMobBrowser': 'SilverMob US' 'org.mini.freebrowser': 'CM Mini' 'com.anc.web.browser': 'Comfort Browser' 'fast.explorer.web.browser': 'Fast Explorer' 'net.soti.surf': 'SOTI Surf' 'com.lexi.browser': 'Lexi Browser' 'com.browser.pintar': 'Smart Browser' 'com.belva.safe.browser': 'Belva Browser' 'com.youcare.browser': 'YouCare' 'org.lilo.mobile.android2020': 'Lilo' 'com.opera.cryptobrowser': 'Opera Crypto' 'AlohaBrowser': 'Aloha Browser' 'mark.via': 'Via' 'com.xpp.floatbrowser': 'Float Browser' 'com.kiddoware.kidsafebrowser': 'Kids Safe Browser' 'com.hideitpro.vbrowser': 'vBrowser' 'com.cgbrowser.rn': 'CG Browser' 'com.azka.browser.anti.blokir': 'Azka Browser' 'com.azka.browser': 'Azka Browser' 'com.micromaxinfo.browser': 'Mmx Browser' 'com.zeesitech.bitchutebrowser': 'Bitchute Browser' 'nova.all.video.downloader': 'Nova Video Downloader Pro' 'tukidev.pronhubbrowser.tanpavpn': 'PronHub Browser' 'com.crowbar.beaverlite': 'Frost' 'com.crowbar.beaverbrowser': 'Frost+' 'com.lenovo.browser': 'Lenovo Browser' 'com.transsion.phoenix': 'Phoenix Browser' 'quick.browser.secure': 'Quick Browser' 'com.asus.browser': 'Asus Browser' 'com.opera.touch': 'Opera Touch' 'com.ghostery.android.ghostery': 'Ghostery Privacy Browser' 'com.oceanhero.search': 'OceanHero' 'com.mebrowser.webapp': 'Me Browser' 'info.plateaukao.einkbro': 'EinkBro' 'com.fevdev.nakedbrowser': 'Naked Browser' 'com.fevdev.nakedbrowserlts': 'Naked Browser' 'com.fevdev.nakedbrowserpro': 'Naked Browser Pro' 'com.yasirshakoor.ducbrowser': 'DUC Browser' 'com.wDesiBrowser_13255326': 'Desi Browser' 'com.huawei.browser': 'Huawei Browser Mobile' 'com.phantom.me': 'Phantom.me' 'com.opera.mini.android': 'Opera Mini' 'jp.ejimax.berrybrowser': 'Berry Browser' 'com.fulldive.mobile': 'Fulldive' 'com.talpa.hibrowser': 'Hi Browser' 'org.midorinext.android': 'Midori Lite' 'reactivephone.msearch': 'Smart Search & Web Browser' 'com.sibimobilelab.amazebrowser': 'Amaze Browser' 'com.alohamobile.browser.lite': 'Aloha Browser Lite' 'com.tcl.browser': 'BrowseHere' 'com.seraphic.openinet.pre': 'Open Browser' 'com.seraphic.openinet.cvte': 'Open Browser' 'privatebrowser.securebrowser.com.klar': 'Secure Private Browser' 'in.pokebbrowser.bukablokirsitus': 'HUB Browser' 'com.wOpenBrowser_12576500': 'Open Browser fast 5G' 'com.wOpenbrowser_13506467': 'Open Browser 4U' 'com.MaxTube.browser': 'MaxTube Browser' 'com.ninexgen.chowbo': 'Chowbo' 'net.pertiller.debuggablebrowser': 'Debuggable Browser' 'com.appssppa.idesktoppcbrowser': 'iDesktop PC Browser' 'pi.browser': 'Pi Browser' 'com.xooloo.internet': 'Xooloo Internet' 'com.u_browser': 'U Browser' 'ai.blokee.browser.android': 'Bloket' 'com.vast.vpn.proxy.unblock': 'Vast Browser' 'com.security.xvpn.z35kb': 'X-VPN' 'com.security.xvpn.z35kb.amazon': 'X-VPN' 'com.security.xvpn.z35kb.huawei': 'X-VPN' 'com.yandex.browser.lite': 'Yandex Browser Lite' 'com.yandex.browser.beta': 'Yandex Browser' 'com.yandex.browser.alpha': 'Yandex Browser' 'cz.seznam.sbrowser': 'Seznam Browser' 'com.morrisxar.nav88': 'Office Browser' 'com.rabbit.incognito.browser': 'Rabbit Private Browser' 'arun.com.chromer': 'Lynket Browser' 'jp.hazuki.yuzubrowser': 'Yuzu Browser' 'com.swiftariel.browser.cherry': 'Cherry Browser' 'id.browser.vivid3': 'Vivid Browser Mini' 'com.browser.yo.indian': 'Yo Browser' 'com.mercandalli.android.browser': 'G Browser' 'com.bf.browser': 'BXE Browser' 'com.qihoo.browser': '360 Secure Browser' 'com.qihoo.contents': '360 Secure Browser' 'com.qihoo.haosou': '360 Secure Browser' 'com.qihoo.padbrowser': '360 Secure Browser' 'com.qihoo.sonybrowser': '360 Secure Browser' 'org.zirco': 'Zirco Browser' 'org.tint': 'Tint Browser' 'com.skyfire.browser': 'Skyfire' 'com.sonymobile.smallbrowser': 'Sony Small Browser' 'org.hola': 'hola! Browser' 'it.ideasolutions.amerigo': 'Amerigo' 'org.xbrowser.prosuperfast': 'xBrowser Pro Super Fast' 'org.plus18.android': '18+ Privacy Browser' 'com.beyond.privatebrowser': 'Beyond Private Browser' 'com.blacklion.browser': 'Black Lion Browser' 'com.opera.mini.native.ShonizME': 'Opera Mini' 'com.tuc.mini.st': 'TUC Mini Browser' 'com.roidtechnologies.appbrowzer': 'AppBrowzer' 'com.futuristic.sx': 'SX Browser' 'hot.fiery.browser': 'Fiery Browser' 'in.nismah.yagi': 'YAGI' 'com.apn.mobile.browser.cherry': 'APN Browser' 'com.apn.mobile.browser.umeatt': 'APN Browser' 'com.apn.mobile.browser.zte': 'APN Browser' 'com.tencent.mtt': 'QQ Browser' 'com.wordly.translate.browser': 'NextWord Browser' 'idm.internet.download.manager': '1DM Browser' 'idm.internet.download.manager.plus': '1DM+ Browser' 'com.veeraapps.newadult': 'Adult Browser' 'com.xnxbrowser.rampage': 'XNX Browser' 'com.xtremecast': 'XtremeCast' 'com.xvideobrowserlite.xvideoDownloaderbrowserlite': 'X Browser Lite' 'com.xxnxx.browser.proxy.vpn': 'xBrowser' 'com.sweetbrowser.ice': 'Sweet Browser' 'com.mcent.browser': 'mCent' 'com.htc.sense.browser': 'HTC Browser' 'com.browlser': 'Browlser' 'app.browserhub.download': 'Browser Hup Pro' 'com.flyperinc.flyperlink': 'Flyperlink' 'com.w3engineers.banglabrowser': 'Bangla Browser' 'com.coccoc.trinhduyet': 'Coc Coc' 'com.browser.explore': 'Explore Browser' 'com.microsoft.emmx': 'Microsoft Edge' 'com.explore.web.browser': 'Web Browser & Explorer' 'privacy.explorer.fast.safe.browser': 'Privacy Explorer Fast Safe' 'app.soundy.browser': 'Soundy Browser' 'com.ivvi.browser': 'IVVI Browser' 'com.nomone.vrbrowser': 'NOMone VR Browser' 'com.opus.browser': 'Opus Browser' 'com.arvin.browser': 'Arvin' 'com.pawxy.browser': 'Pawxy' 'com.internet.tvbrowser': 'LUJO TV Browser' 'com.logicui.tvbrowser2': 'LogicUI TV Browser' 'com.opera.browser.afin': 'Opera' 'com.opera.browser.beta': 'Opera' 'com.quark.browser': 'Quark' 'jp.co.yahoo.android.ybrowser': 'Yahoo! Japan Browser' 'com.tv.browser.open': 'Open TV Browser' 'com.ornet.torbrowser': 'OrNET Browser' 'com.browsbit': 'BrowsBit' 'org.mozilla.firefox': 'Firefox Mobile' 'com.yandex.browser': 'Yandex Browser' 'com.opera.mini.native.beta': 'Opera Mini' 'com.sec.android.app.sbrowser': 'Samsung Browser' 'com.sec.android.app.sbrowser.lite': 'Samsung Browser Lite' 'com.browser.elmurzaev': 'World Browser' 'every.browser.inc': 'Every Browser' 'com.mi.globalbrowser': 'MIUI Browser' 'nu.tommie.inbrowser': 'InBrowser' 'com.insta.browser': 'Insta Browser' 'com.alohamobile.vertexsurf': 'Vertex Surf' 'com.hollabrowser.meforce': 'Holla Web Browser' 'org.torbrowser.torproject': 'Tor Browser' 'org.torproject.torbrowser': 'Tor Browser' 'com.marslab.browserz': 'MarsLab Web Browser' 'com.mini.web.browser': 'Sunflower Browser' 'com.cavebrowser': 'Cave Browser' 'com.zordo.browser': 'Zordo Browser' 'freedom.theanarch.org.freedom': 'Freedom Browser' 'com.lechneralexander.privatebrowser': 'Private Internet Browser' 'com.airfind.browser': 'Airfind Secure Browser' 'com.securex.browser': 'SecureX' 'com.sec.android.app.sbrowser.beta': 'Samsung Browser' 'threads.thor': 'Thor' 'com.androidbull.incognito.browser': 'Incognito Browser' 'com.mosoft.godzilla': 'Godzilla Browser' 'com.oceanbrowser.mobile.android': 'Ocean Browser' 'com.qmamu.browser': 'Qmamu' 'com.techlastudio.bfbrowser': 'BF Browser' 'com.befaster.bfbrowser': 'BF Browser' 'app.nextinnovations.brokeep': 'BroKeep Browser' 'org.lilo.app': 'Lilo' 'proxy.browser.unblock.sites.proxybrowser.unblocksites': 'Proxy Browser' 'com.hotsurf.browser': 'HotBrowser' 'vpn.video.downloader': 'VD Browser' 'com.aospstudio.tvsearch': 'Quick Search TV' 'com.go.browser': 'GO Browser' 'com.apgsolutionsllc.APGSOLUTIONSLLC0007': 'Basic Web Browser' 'com.phlox.tvwebbrowser': 'TV Bro' 'com.lovense.vibemate': 'VibeMate' 'dev.sect.lotus.browser.videoapp': 'Lotus' 'com.qjy.browser': 'QJY TV Browser' # http://www.qianjiayue.com/new/?c=index&a=show&id=100 'com.airwatch.browser': 'VMware AirWatch' 'com.microsoft.intune.mam.managedbrowser': 'Intune Managed Browser' 'com.tencent.bang': 'Bang' 'com.outcoder.browser': 'Surfy Browser' 'ginxdroid.gdm': 'GinxDroid Browser' 'on.browser': 'OnBrowser Lite' 'com.pico.browser.overseas': 'PICO Browser' 'com.cliqz.browser': 'Cliqz' 'org.hola.prem': 'hola! Browser' 'com.baidu.browser.inter': 'Baidu Browser' 'org.torproject.torbrowser_alpha': 'Tor Browser' 'com.ilegendsoft.mercury': 'Mercury' 'com.apn.mobile.browser.coolpad': 'APN Browser' 'com.apn.mobile.browser.infosonics': 'APN Browser' 'net.dezor.browser': 'Dezor' 'com.involta.involtago': 'Involta Go' 'jp.ddo.pigsty.HabitBrowser': 'Habit Browser' 'org.browser.owl': 'Owl Browser' 'com.orbitum.browser': 'Orbitum' 'com.appsverse.photon': 'Photon' 'fr.agrange.bbbrowser': 'Keyboard Browser' 'com.stealthmobile.browser': 'Stealth Browser' 'com.wcd.talkto': 'TalkTo' 'com.foxylab.airfox': 'Proxynet' 'io.github.mthli.goodbrowser': 'Good Browser' 'app.proxyiumbrowser.android': 'Proxyium' 'com.vuhuv': 'Vuhuv' 'com.fast.fireBrowser': 'Fire Browser' 'acr.browser.lightning': 'Lightning Browser Plus' 'birapp.dark.web': 'Dark Web' 'birapp.dark.web.private': 'Dark Web Private' device_detector-1.1.3/regexes/client/hints/apps.yml0000644000004100000410000001332214656360041022435 0ustar www-datawww-data# Apps 'org.telegram.messenger': 'Telegram' 'com.snapchat.android': 'Snapchat' 'info.sunista.app': 'Sanista Persian Instagram' 'com.instapro.app': 'InstaPro' 'com.tencent.mm': 'WeChat' 'com.kakao.talk': 'KakaoTalk' 'com.ayoba.ayoba': 'Ayoba' 'snapu2b.com': 'SnapU2B' 'com.facebook.katana': 'Facebook' 'com.facebook.orca': 'Facebook Messenger' 'com.yahoo.onesearch': 'Yahoo OneSearch' 'jp.co.yahoo.android.yjtop': 'Yahoo! Japan' 'it.ideasolutions.kyms': 'KYMS - Keep Your Media Safe' 'it.tolelab.fvd': 'FVD - Free Video Downloader' 'kik.android': 'Kik' 'com.tinder': 'Tinder' 'com.videochat.livu': 'LivU' 'io.metamask': 'MetaMask' 'com.totalav.android': 'TotalAV' 'com.fsecure.ms.saunalahti_m': 'Elisa Turvapaketti' 'com.fsecure.ms.ziggo': 'Ziggo Safe Online' 'com.aol.mobile.aolapp': 'AOL' 'com.fancyclean.security.antivirus': 'Fancy Security' 'com.google.android.gms': 'Google Play' 'com.appsinnova.android.keepclean': 'KeepClean' 'com.turtc': 'TurTc' 'com.sony.nfx.app.sfrc': 'News Suite by Sony' 'com.rcplatform.livechat': 'Tumile' 'jp.gocro.smartnews.android': 'SmartNews' 'com.lenovo.anyshare.gps': 'SHAREit' 'com.espn.score_center': 'ESPN' 'com.active.cleaner': 'Active Cleaner' 'com.hld.anzenbokusucal': 'Calculator Photo Vault' 'com.hld.anzenbokusufake': 'Calculator Hide Photos' 'com.hld.anzenbokusu': 'Sgallery' 'com.huawei.appmarket': 'AppGallery' 'com.michatapp.im': 'MiChat' 'com.michatapp.im.lite': 'MiChat Lite' 'com.noxgroup.app.security': 'Nox Security' 'phone.cleaner.antivirus.speed.booster': 'Super Cleaner' 'com.yy.hiyo': 'Hago' 'com.instagram.android': 'Instagram' 'com.instagram.barcelona': 'Threads' 'com.microsoft.office.outlook': 'Microsoft Outlook' 'com.microsoft.bing': 'Microsoft Bing' 'com.microsoft.bingintl': 'Microsoft Bing' 'com.nhn.android.search': 'Naver' 'com.jb.security': 'GO Security' 'com.fsecure.ms.safe': 'F-Secure SAFE' 'com.jaumo': 'Jaumo' 'com.jaumo.prime': 'Jaumo Prime' 'com.skout.android': 'SKOUT' 'com.hornet.android': 'Hornet' 'com.fsecure.ms.darty': 'Darty Sécurité' 'com.fsecure.ms.dc': 'F-Secure Mobile Security' 'com.fsecure.ms.swisscom.sa': 'Swisscom Internet Security' 'com.andrewshu.android.reddit': 'Reddit is fun' 'com.andrewshu.android.redditdonation': 'Reddit is fun' 'org.quantumbadger.redreader': 'RedReader' 'com.sina.weibo': 'Sina Weibo' 'com.wiseplay': 'Wiseplay' 'com.fsecure.ms.nifty': 'Always Safe Security 24' 'com.zeebusiness.news': 'Zee Business' 'com.awesapp.isp': 'iSafePlay' 'com.baidu.searchbox': 'Baidu Box App' 'hesoft.T2S': 'T2S' 'hippeis.com.photochecker': 'Photo Sherlock' 'com.thinkfree.searchbyimage': 'Reverse Image Search' 'com.tct.launcher': 'Joy Launcher' 'com.tcl.live': 'TCL Live' 'com.harshad.someto': 'Social Media Explorer' 'com.reddit.frontpage': 'Reddit' 'com.opera.app.news': 'Opera News' 'com.palmteam.imagesearch': 'Search By Image' 'com.sharekaro.app': 'ShareKaro' 'com.til.timesnews': 'NewsPoint' 'com.transsion.XOSLauncher': 'XOS Launcher' 'com.transsion.hilauncher': 'HiOS Launcher' 'com.transsion.itel.launcher': 'itel Launcher' 'com.twitter.android': 'Twitter' 'com.waze': 'Waze' 'com.tuya.smartlife': 'Tuya Smart Life' 'com.cleanmaster.mguard': 'Clean Master' 'com.cleanmaster.mguard.huawei': 'Clean Master' 'de.twokit.castbrowsernexusplayer': 'TV Cast' 'de.twokit.video.tv.cast.browser.firetv': 'TV Cast' 'de.twokit.video.tv.cast.browser.lg': 'TV Cast' 'de.twokit.video.tv.cast.browser.samsung': 'TV Cast' 'com.cleanmaster.security': 'CM Security' 'com.antivirus.master.cmsecurity': 'CM Security' 'idm.video.free': 'IDM Video Download Manager' 'mobi.deallauncher.coupons.shopping': 'Coupons & Deals' 'com.wukongtv.wkcast.intl': 'Quick Cast' 'com.tt.android.dm.view': 'Download Manager' 'com.fsecure.ms.kpn.veilig': 'KPN Veilig' 'com.fsecure.ms.actshield': 'ACT Shield' 'com.fsecure.ms.talktalksa': 'TalkTalk SuperSafe' 'com.fsecure.ms.dnafi': 'DNA Digiturva' 'com.fsecure.ms.teliasweden': 'Telia Trygg' 'com.fsecure.ms.upc.ch': 'UPC Internet Security' 'com.fsecure.ms.sfr': 'SFR Sécurité' 'com.fsecure.ms.sonera': 'Telia Turvapaketti' 'com.bifrostwallet.app': 'Bifrost Wallet' 'com.anydesk.anydeskandroid': 'AnyDesk Remote Desktop' 'com.google.android.youtube': 'YouTube' 'io.bluewallet.bluewallet': 'BlueWallet' 'com.google.android.apps.searchlite': 'Google Go' 'com.snaptube.premium': 'SnapTube' 'com.myhomescreen.sms': 'Messenger Home' 'com.myhomescreen.email': 'Email Home' 'com.myhomescreen.weather': 'Weather Home' 'com.myhomescreen.access': 'Big Keyboard' 'com.myhomescreen.messenger.home.emoji.lite': 'Messenger Lite' 'com.myhomescreen.fitness': 'Fit Home' 'com.myhomescreen.news': 'News Home' 'com.amazon.webapps.gms.search': 'Google Search App' 'com.huawei.fastapp': 'Huawei Quick App Center' 'com.flatfish.cal.privacy': 'HideX' 'com.sweep.cleaner.trash.junk': 'Sweep' 'com.google.android.apps.maps': 'Google Maps' 'com.box.video.downloader': 'BOX Video Downloader' 'com.oxoo.kinogo': 'Kinogo.ge' 'com.tradron.hdvideodownloader': 'Download Hub' 'net.daum.android.daum': 'Daum' 'com.massimple.nacion.gcba.es': '+Simple' 'com.massimple.nacion.parana.es': '+Simple' 'com.microsoft.math': 'Microsoft Math Solver' 'com.instabridge.android': 'Instabridge' 'com.repotools.whatplay': 'Whatplay' 'com.saf.seca': 'SearchCraft' 'com.huawei.hwsearch': 'Petal Search' 'com.playit.videoplayer': 'PLAYit' 'com.droidlogic.xlauncher': 'X Launcher' 'nu.bi.moya': 'Moya' 'com.microsoft.copilot': 'Microsoft Copilot' 'com.nate.android.portalmini': 'nate' # Vpns 'org.torproject.android': 'Orbot' 'free.vpn.unblock.proxy.vpnmonster': 'VPN Monster' 'com.udicorn.proxy': 'Blue Proxy' 'com.v2.vpn.security.free': 'V2Free' 'com.surfshark.vpnclient.android': 'Surfshark' 'com.omshyapps.vpn': 'Omshy VPN' 'com.kuto.vpn': 'KUTO VPN' 'com.ezt.vpn': 'EZVPN' 'com.nocardteam.nocardvpn': 'NoCard VPN' 'com.nocardteam.nocardvpn.lite': 'NoCard VPN Lite' device_detector-1.1.3/regexes/client/browser_engine.yml0000644000004100000410000000155514656360041023362 0ustar www-datawww-data############### # Device Detector - The Universal Device Detection library for parsing User Agents # # @link https://matomo.org # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later ############### - regex: 'NetFront' name: 'NetFront' - regex: 'Edge/' name: 'Edge' - regex: 'Trident' name: 'Trident' - regex: 'Chrome/(?!1?\d\.|2[0-7]\.)' name: 'Blink' - regex: '(?:Apple)?WebKit' name: 'WebKit' - regex: 'Presto' name: 'Presto' - regex: 'Goanna' name: 'Goanna' - regex: '(? 'Chrome' client.full_version # => '30.0.1599.69' client.os_name # => 'Windows' client.os_full_version # => '8' # For many devices, you can also query the device name (usually the model name) client.device_name # => 'iPhone 5' # Device types can be one of the following: desktop, smartphone, tablet, # feature phone, console, tv, car browser, smart display, camera, # portable media player, phablet, smart speaker, wearable, peripheral client.device_type # => 'smartphone' ``` `DeviceDetector` will return `nil` on all attributes, if the `user_agent` is unknown. You can make a check to ensure the client has been detected: ```ruby client.known? # => will return false if user_agent is unknown ``` ### Using Client hint Optionally `DeviceDetector` is using the content of `Sec-CH-UA` stored in the headers to improve the accuracy of the detection : ```ruby user_agent = 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36' headers = {"Sec-CH-UA"=>'"Chromium";v="106", "Brave";v="106", "Not;A=Brand";v="99"'} client = DeviceDetector.new(user_agent, headers) client.name # => 'Brave' ``` Same goes with `http-x-requested-with`/`x-requested-with` : ```ruby user_agent = 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36' headers = {"http-x-requested-with"=>"org.mozilla.focus"} client = DeviceDetector.new(user_agent, headers) client.name # => 'Firefox Focus' ``` ### Memory cache `DeviceDetector` will cache up 5,000 user agent strings to boost parsing performance. You can tune the amount of keys that will get saved in the cache. You have to call this code **before** you initialize the Detector. ```ruby DeviceDetector.configure do |config| config.max_cache_keys = 5_000 # increment this if you have enough RAM, proceed with care end ``` If you have a Rails application, you can create an initializer, for example `config/initializers/device_detector.rb`. ## Benchmarks We have measured the parsing speed of almost 200,000 non-unique user agent strings and compared the speed of DeviceDetector with the two most popular user agent parsers in the Ruby community, Browser and UserAgent. ### Testing machine specs - MacBook Pro 15", Late 2013 - 2.6 GHz Intel Core i7 - 16 GB 1600 MHz DDR3 ### Gem versions - DeviceDetector - 0.5.1 - Browser - 0.8.0 - UserAgent - 0.13.1 ### Code ```ruby require 'device_detector' require 'browser' require 'user_agent' require 'benchmark' user_agent_strings = File.read('./tmp/user_agent_strings.txt').split("\n") ## Benchmarks Benchmark.bm(15) do |x| x.report('device_detector') { user_agent_strings.each { |uas| DeviceDetector.new(uas).name } } x.report('browser') { user_agent_strings.each { |uas| Browser.new(ua: uas).name } } x.report('useragent') { user_agent_strings.each { |uas| UserAgent.parse(uas).browser } } end ``` ### Results ``` user system total real device_detector 0.925603 0.020928 0.946531 ( 0.948750) browser 3.555590 0.014877 3.570467 ( 3.575951) useragent 3.264011 0.032327 3.296338 ( 3.301772) user system total real device_detector 0.915578 0.021295 0.936873 ( 0.938698) browser 3.600674 0.022312 3.622986 ( 3.635185) useragent 3.425424 0.054298 3.479722 ( 3.500929) user system total real device_detector 0.916608 0.022739 0.939347 ( 0.940993) browser 3.624404 0.027489 3.651893 ( 3.667863) useragent 3.442139 0.054376 3.496515 ( 3.519747) ``` ## Detectable clients, bots and devices Updated on 2024-06-27 ### Bots 2GDPR, 2ip, 360 Monitoring, 360JK, 360Spider, Abonti, Aboundexbot, AccompanyBot, Acoon, AdAuth, Adbeat, AddThis.com, ADMantX, ADmantX Service Fetcher, Adsbot, Adscanner, AdsTxtCrawler, AdsTxtCrawlerTP, adstxtlab.com, Aegis, aHrefs Bot, AhrefsSiteAudit, aiHitBot, Alexa Crawler, Alexa Site Audit, Allloadin Favicon Bot, AlltheWeb, Amazon AdBot, Amazon Bot, Amazon ELB, Amazon Route53 Health Check, Amorank Spider, Analytics SEO Crawler, Ant, Anthropic AI, ApacheBench, Applebot, AppSignalBot, Arachni, archive.org bot, ArchiveBot, ArchiveBox, Arquivo.pt, ARSNova Filter System, Asana, Ask Jeeves, AspiegelBot, Automattic Analytics, Awario, Backlink-Check.de, BacklinkCrawler, BackupLand, Baidu Spider, Barkrowler, Barracuda Sentinel, BazQux Reader, BBC Forge URL Monitor, BBC Page Monitor, BDCbot, BDFetch, Better Uptime Bot, BingBot, Birdcrawlerbot, BitlyBot, BitSight, Blekkobot, BLEXBot Crawler, Bloglovin, Blogtrottr, BoardReader, BoardReader Blog Indexer, Botify, Bountii Bot, BrandVerity, BrightBot, BrightEdge, Browsershots, BUbiNG, Buck, BuiltWith, Butterfly Robot, Bytespider, CareerBot, Castopod, Castro 2, Catchpoint, CATExplorador, ccBot crawler, CensysInspect, Charlotte, Chartable, ChatGPT, CheckHost, CheckMark Network, Choosito, Chrome Privacy Preserving Prefetch Proxy, Cincraw, CISPA Web Analyzer, ClaudeBot, Clickagy, Cliqzbot, CloudFlare Always Online, CloudFlare AMP Fetcher, Cloudflare Custom Hostname Verification, Cloudflare Diagnostics, Cloudflare Health Checks, Cloudflare Observatory, Cloudflare Security Insights, Cloudflare Smart Transit, Cloudflare SSL Detector, Cloudflare Traffic Manager, Cocolyzebot, Cohere AI, Collectd, colly, CommaFeed, COMODO DCV, Comscore, ContentKing, Cookiebot, Crawldad, Crawlson, Crawly Project, CriteoBot, CrowdTangle, CSS Certificate Spider, CSSCheck, Cyberscan, Cypress, Cốc Cốc Bot, DaspeedBot, Datadog Agent, DataForSeoBot, datagnionbot, Datanyze, Dataprovider, DataXu, Daum, Dazoobot, Deep SEARCH 9, Deepfield Genome, deepnoc, DepSpid, Detectify, Diffbot, Discobot, Discord Bot, Disqus, DNSResearchBot, Domain Re-Animator Bot, Domain Research Project, DomainAppender, DomainCrawler, Domains Project, DomainStatsBot, DomCop Bot, DotBot, Dotcom Monitor, Dubbotbot, DuckDuckGo Bot, ducks.party, DynatraceSynthetic, Easou Spider, eCairn-Grabber, EFF Do Not Track Verifier, Elastic Synthetics, EMail Exractor, EmailWolf, Embedly, Entfer, evc-batch, Everyfeed, ExaBot, ExactSeek Crawler, Example3, Exchange check, Expanse, EyeMonit, eZ Publish Link Validator, Ezgif, Ezooms, Facebook Crawler, FacebookBot, Faveeo, Feed Wrangler, Feedbin, FeedBurner, Feedly, Feedspot, Femtosearch, Fever, Findxbot, Flipboard, FontRadar, fragFINN, FreeWebMonitoring, FreshRSS, Gaisbot, GDNP, GeedoBot, GeedoProductSearch, Generic Bot, Genieo Web filter, Ghost Inspector, Gigablast, Gigabot, GitCrawlerBot, GitHubCopilotChat, Gluten Free Crawler, Gmail Image Proxy, Gobuster, Goo, Google Apps Script, Google Area 120 Privacy Policy Fetcher, Google Cloud Scheduler, Google Favicon, Google PageSpeed Insights, Google Partner Monitoring, Google Search Console, Google Stackdriver Monitoring, Google StoreBot, Google Structured Data Testing Tool, Google Transparency Report, Googlebot, Googlebot News, Gowikibot, Gozle, GPTBot, Grammarly, Grapeshot, Gregarius, GTmetrix, GumGum Verity, hackermention, Hatena Bookmark, Hatena Favicon, Headline, Heart Rails Capture, Heritrix, Heureka Feed, htmlyse, HTTPMon, httpx, HuaweiWebCatBot, HubPages, HubSpot, ICC-Crawler, ichiro, IDG/IT, Iframely, IIS Site Analysis, ImageSift, Inetdex Bot, Infegy, InfoTigerBot, Inktomi Slurp, inoreader, InsytfulBot, Intelligence X, Interactsh, InternetMeasurement, IONOS Crawler, IP-Guide Crawler, IPIP, IPS Agent, IsItWP, iTMS, JobboerseBot, JungleKeyThumbnail, K6, KadoBot, Kaspersky, KeyCDN Tools, Keys.so, Kiwi TCMS GitOps, KlarnaBot, KomodiaBot, Konturbot, Kouio, Kozmonavt, l9explore, l9tcpid, LAC IA Harvester, Larbin web crawler, LastMod Bot, LCC, LeakIX, Let's Encrypt Validation, LetSearch, Lighthouse, Linespider, Linkdex Bot, LinkedIn Bot, LinkpadBot, LinkPreview, LinkWalker, LiveJournal, LTX71, Lumar, LumtelBot, Lycos, MaCoCu, MADBbot, Magpie-Crawler, MagpieRSS, Mail.Ru Bot, MariaDB/MySQL Knowledge Base, masscan, masscan-ng, Mastodon Bot, Matomo, Meanpath Bot, Mediatoolkit Bot, MegaIndex, MeltwaterNews, MetaInspector, MetaJobBot, MicroAdBot, Microsoft Preview, Mixnode, Mixrank Bot, MJ12 Bot, Mnogosearch, MojeekBot, Monitor Backlinks, Monitor.Us, Monsidobot, Montastic Monitor, MoodleBot Linkchecker, Morningscore Bot, MTRobot, Munin, MuscatFerret, Nagios check_http, NalezenCzBot, nbertaupete95, Neevabot, Netcraft Survey Bot, netEstate, NetLyzer FastProbe, Netpeak Checker, NetResearchServer, NetSystemsResearch, NetTrack, Netvibes, NETZZAPPEN, NewsBlur, NewsGator, Newslitbot, NiceCrawler, Nimbostratus Bot, NLCrawler, Nmap, NodePing, Notify Ninja, Nutch-based Bot, Nuzzel, oBot, Octopus, Odin, Odnoklassniki Bot, Omgili bot, OmtrBot, Onalytica, OnlineOrNot Bot, Openindex Spider, OpenLinkProfiler, OpenWebSpider, Orange Bot, OSZKbot, Outbrain, Overcast Podcast Sync, OWLer, Page Modified Pinger, Pageburst, PagePeeker, PageThing, Panscient, PaperLiBot, Paqlebot, parse.ly, PATHspider, PayPal IPN, PDR Labs, PerplexityBot, Petal Bot, Phantomas, PHP Server Monitor, phpMyAdmin, Picsearch bot, PingAdmin.Ru, Pingdom Bot, Pinterest, PiplBot, Plesk Screenshot Service, Plukkie, Pocket, Podroll Analyzer, PodUptime, Pompos, PritTorrent, Probely, Project Patchwatch, Project Resonance, Prometheus, PRTG Network Monitor, Punk Map, Quantcast, QuerySeekerSpider, Quora Bot, Quora Link Preview, Qwantify, Rainmeter, RamblerMail Image Proxy, RavenCrawler, Reddit Bot, RenovateBot, Repo Lookout, ReqBin, Research Scan, Riddler, Robozilla, RocketMonitorBot, Rogerbot, ROI Hunter, RSSRadio Bot, RuxitSynthetic, Ryowl, SabsimBot, SafeDNSBot, Sandoba//Crawler, Scamadviser External Hit, Scooter, ScoutJet, Scraping Robot, Scrapy, Screaming Frog SEO Spider, ScreenerBot, Sectigo DCV, security.txt scanserver, Seekport, Sellers.Guide, Semantic Scholar Bot, Semrush Reputation Management, SemrushBot, Sensika Bot, Sentry Bot, Senuto, Seobility, SEOENGBot, SEOkicks, SEOkicks-Robot, seolyt, Seolyt Bot, Seoscanners.net, Serendeputy Bot, Serenety, serpstatbot, Server Density, Seznam Bot, Seznam Email Proxy, Seznam Zbozi.cz, sfFeedReader, ShopAlike, Shopify Partner, ShopWiki, SilverReader, SimplePie, Sirdata, SISTRIX Crawler, SISTRIX Optimizer, Site24x7 Defacement Monitor, Site24x7 Website Monitoring, SiteAuditBot, Sitebulb, Siteimprove, SitemapParser-VIPnytt, SiteOne Crawler, SiteScore, SiteSucker, Sixy.ch, Skype URI Preview, Slackbot, SMTBot, Snap URL Preview Service, Snapchat Ads, Snapchat Proxy, Sogou Spider, Soso Spider, Sparkler, Spawning AI, SpazioDati, Speedy, Spinn3r, SplitSignalBot, Spotify, Sprinklr, Sputnik Bot, Sputnik Favicon Bot, Sputnik Image Bot, sqlmap, SSL Labs, start.me, Startpagina Linkchecker, Statista, StatOnline.ru, StatusCake, Steve Bot, Stract, Sublinq, Substack Content Fetch, Superfeedr Bot, SurdotlyBot, Survey Bot, Swiftbot, Synapse, t3versions, Taboolabot, TactiScout, Tag Inspector, Tarmot Gezgin, tchelebi, TelegramBot, Tenable.asm, TestCrawler, The Knowledge AI, The Trade Desk Content, theoldreader, ThinkChaos, ThousandEyes, TigerBot, TinEye, TinEye Crawler, Tiny Tiny RSS, TLSProbe, TraceMyFile, Trendiction Bot, Trendsmap, Turnitin, TurnitinBot, TweetedTimes Bot, Tweetmeme Bot, Twingly Recon, Twitterbot, Twurly, UCSB Network Measurement, UkrNet Mail Proxy, uMBot, UniversalFeedParser, Uptime-Kuma, Uptimebot, UptimeRobot, Uptimia, URLAppendBot, URLinspector, URLSuMaBot, Vagabondo, Velen Public Web Crawler, Vercel Bot, VeryHip, Viber Url Downloader, VirusTotal Cloud, Visual Site Mapper Crawler, VK Robot, VK Share Button, Vuhuv Bot, W3C CSS Validator, W3C I18N Checker, W3C Link Checker, W3C Markup Validation Service, W3C MobileOK Checker, W3C P3P Validator, W3C Unified Validator, Wappalyzer, WDG HTML Validator, WebbCrawler, WebCEO, WebDataStats, WebMon, Weborama, WebPageTest, WebPros, Website-info, WebSitePulse, WebThumbnail, webtru, Webwiki, WellKnownBot, WeSEE:Search, WeViKaBot, WhatCMS, WhatsMyIP.org, WhereGoes, Who.is Bot, Wibybot, WikiDo, Willow Internet Crawler, WireReaderBot, WooRank, WordPress, Wotbox, XenForo, XoviBot, YaCy, Yahoo Gemini, Yahoo! Cache System, Yahoo! Japan, Yahoo! Japan ASR, Yahoo! Japan BRW, Yahoo! Japan WSC, Yahoo! Link Preview, Yahoo! Mail Proxy, Yahoo! Slurp, YaK, Yandex Bot, Yeti/Naverbot, Yottaa Site Monitor, YouBot, Youdao Bot, Yourls, Yunyun Bot, Zaldamo, Zao, Ze List, Zeno, zgrab, Zookabot, ZoomBot, ZoominfoBot, ZumBot ### Clients 'sodes, +Simple, 115 Browser, 18+ Privacy Browser, 1Password, 2345 Browser, 2tch, 360 Phone Browser, 360 Secure Browser, 7654 Browser, 7Star, ABrowse, Acoo Browser, ActionExtension, AdBlock Browser, Adobe Creative Cloud, Adobe IPM, Adobe NGL, Adobe Synchronizer, Adori, Agora, Aha Radio 2, AIDA64, aiohttp, Airfind Secure Browser, Airmail, Airr, Airsonic, Akka HTTP, Akregator, Alexa, AliExpress, Alipay, All You Can Books, AllHitMusicRadio, Aloha Browser, Aloha Browser Lite, ALVA, Amarok, Amaya, Amazon Fire, Amazon Music, Amazon Shopping, Ameba, Amiga Aweb, Amiga Voyager, Amigo, AN WhatsApp, Anchor, AnchorFM, Android Browser, Android License Verification Library, AndroidDownloadManager, Anghami, ANT Fresco, AntennaPod, ANTGalio, AntiBrowserSpy, Anybox, AnyEvent HTTP, Anytime Podcast Player, AOL Desktop, AOL Explorer, AOL Shield, AOL Shield Pro, Apache HTTP Client, APK Downloader, Aplix, APN Browser, Apollo, Apple iMessage, Apple Mail, Apple News, Apple Podcasts, Apple PubSub, Apple Reminders, Apple TV, Arachne, Arc, Arctic Fox, Aria2, Arora, Artifactory, Arvin, Arvocast, Ask.com, ASUS Updater, Atom, Atomic Web Browser, Audacious, Audacy, Audials, Audible, Audio, Audio Now, Audiobooks, Autoplius.lt, Avant Browser, Avast Secure Browser, AVG Secure Browser, Avid Link, Avira Secure Browser, Awasu, AwoX, Axios, Azure Data Factory, B-Line, Babashka HTTP Client, Background Intelligent Transfer Service, Baidu Box App, Baidu Browser, Baidu Input, Baidu Spark, Ballz, Bang, Bangla Browser, Bank Millenium, Banshee, Barca, Basecamp, BashPodder, Basilisk, BathyScaphe, Battle.net, BB2C, BBC News, Be Focused, Beaker Browser, Beamrise, Bear, Beonex, BetBull, BeyondPod, Bible, Bible KJV, Binance, Bitcoin Core, Bitsboard, Bitwarden, Biyubi, BizBrowser, BlackBerry Browser, Blackboard, BlackHawk, Blitz, Bloket, Blue Browser, Blue Proxy, Bluefy, BlueMail, BlueStacks, Bolt, BonPrix, Bonsai, Bookmobile, Bookshelf, Boom, Boomplay, Borealis Navigator, Bose Music, Bose SoundTouch, Boto3, Boxee, bPod, Brave, Breaker, Breez, Bridge, BriskBard, Broadcast, Broadway Podcast Network, Browlser, BrowseHere, Browser app, Browser-Anonymizer, BrowserPlus, BrowseX, Browzar, Buildah, BuildKit, Bullhorn, Bunjalloo, BuzzVideo, Byffox, C++ REST SDK, CakePHP, Camino, CamScanner, Capital, capsule.fm, CarrierWave, Castamatic, Castaway, CastBox, castero, castget, Castro, Castro 2, Catalyst, CCleaner, Centaury, CGN, ChanjetCloud, Charon, Chedot, Cheetah Browser, Cheshire, Chim Lac, ChMate, Chrome, Chrome Frame, Chrome Mobile, Chrome Mobile iOS, Chrome Update, Chrome Webview, ChromePlus, Chromium, Chromium GOST, Ciisaa, Citrix Workspace, Classic FM, Classilla, Clementine, Client, Clipbox+, Cliqz, Clovia, CM Browser, COAF SMART Citizen, Coast, Coc Coc, Coinbase, Colibri, Colom Browser, Columbus Browser, CometBird, Comodo Dragon, Conkeror, Containerd, containers, CoolBrowser, Cooler, CoolNovo, Copied, Cornowser, Cortana, COS Browser, Cosmicast, Covenant Eyes, cPanel HTTP Client, CPod, cpp-httplib, CPU-Z, Craving Explorer, Crazy Browser, cri-o, CrosswalkApp, Crusta, Crypto.com DeFi Wallet, CSDN, Cunaguaro, curl, Cyberfox, CyBrowser, Damus, Dart, Daum, DAVdroid, dbrowser, De Standaard, De Telegraaf, Decentr, Deepnet Explorer, Deezer, deg-degan, Deledao, Delta Browser, Deno, DeskBrowse, DevCasts, DeviantArt, DIGA, Diigo Browser, Dillo, DingTalk, DIRECTV, Discord, DManager, docker, DoCoMo, Dogecoin Core, DoggCatcher, Dolphin, Don't Waste My Time!, Dooble, Dorado, Dot Browser, douban App, DoubleTwist CloudPlayer, Doughnut, Down, Downcast, Downie, Downloader, Dr. Watson, DStream Air, DuckDuckGo Privacy Browser, East Browser, Ecosia, Edge Update, Edge WebView, Electron Fetch, Element Browser, Elements Browser, Elinks, eM Client, Emacs, EMAudioPlayer, Embarcadero URI Client, Emby Theater, Eolie, Epic, Epic Games Launcher, ESET Remote Administrator, ESP32 HTTP Client, Espial TV Browser, eToro, EudoraWeb, EUI Browser, Evernote, Evolve Podcast, Expedia, Expo, eZ Browser, F-Secure SAFE, Facebook, Facebook Audience Network, Facebook Groups, Facebook Lite, Facebook Messenger, Facebook Messenger Lite, faidr, Falkon, Faraday, fasthttp, Fathom, Faux Browser, FeedDemon, Feeddler RSS Reader, FeedR, FeedStation, Fennec, ffmpeg, FFUF, fGet, FileDownloader, Files, Firebird, Firefox, Firefox Focus, Firefox Mobile, Firefox Mobile iOS, Firefox Reality, Firefox Rocket, Fireweb, Fireweb Navigator, Flash Browser, Flast, Flipboard App, Flipp, Flock, Floorp, Flow, Flow Browser, Fluid, FlyCast, FM WhatsApp, Focus Keeper, Focus Matrix, foobar2000, Foobar2000, Fountain, Foxmail, Franz, Free Download Manager, Freespoke, FreeU, Gaana, Galeon, Garmin fenix 5X, Garmin Forerunner, GBWhatsApp, GeoIP Update, GetPodcast, Ghostery Privacy Browser, GinxDroid Browser, Git, git-annex, GitHub Desktop, Glass Browser, GlobalProtect, Gmail, GNOME Web, go-container registry, Go-http-client, GoBrowser, GOG Galaxy, GoKu, Gold, GoldenPod, GoLoud, GoNative, Goodpods, GoodReader, Google Assistant, Google Drive, Google Earth, Google Earth Pro, Google Fiber TV, Google Go, Google HTTP Java Client, Google Lens, Google Nest Hub, Google Photos, Google Play Newsstand, Google Plus, Google Podcasts, Google Search App, Google Tag Manager, got, gPodder, GreenBrowser, GRequests, GroupMe, gRPC-Java, GStreamer, Guacamole, Guzzle (PHP HTTP Client), gvfs, hackney, Hago, Hammel, HandBrake, Harbor registry client, HardCast, Hark Audio, Harman Browser, HasBrowser, Hawk Quick Browser, Hawk Turbo Browser, Headless Chrome, Heart, Helio, Helm, HermesPod, HeyTapBrowser, Hi Browser, HiCast, HideX, Hik-Connect, Himalaya, HiSearch, HisThumbnail, HistoryHound, hola! Browser, HotBrowser, Hotels.com, HotJava, HP Smart, HTC Streaming Player, HTML Parser, HTTP request maker, http.rb, HTTP:Tiny, HTTP_Request2, HTTPie, httplib2, httprs, HTTPX, Huawei Browser, Huawei Browser Mobile, Huawei Mobile Services, Hubhopper, HyperCatcher, IBrowse, iBrowser, iBrowser Mini, iCab, iCab Mobile, ICAP Client, iCatcher, IceCat, IceDragon, Iceweasel, IE Mobile, iHeartRadio, IMO HD Video Calls & Chat, IMO International Calls & Chat, Impervious Browser, Insomnia REST Client, Inspect Browser, Instabridge, Instacast, Instagram, Instapaper, Internet Explorer, Intune Managed Browser, iOS Application, IPinfo, iPlayTV, IPTV, IPTV Pro, Iridium, Iron, Iron Mobile, Isivioo, iTunes, iVoox, Jakarta Commons HttpClient, Jam, JaneStyle, JaneView, Japan Browser, Jasmine, Java, Java HTTP Client, JavaFX, JetBrains Omea Reader, JHelioviewer, Jig Browser, Jig Browser Plus, JioSaavn, JioSphere, Jitsi Meet, JJ2GO, JRiver Media Center, jsdom, Juice, Jungle Disk, Just Audio, Just Listen, JUZI Browser, K-meleon, K-Ninja, K.Browser, KaiOS Downloader, Kajabi, KakaoTalk, Kapiko, Kasts, Kazehakase, Keeper Password Manager, Keepsafe Browser, Kids Listen, KidsPod, Kik, Kindle Browser, Kinza, Kitt, Kiwi, Kiwi TCMS, Kiwi TCMS API, KKBOX, Klarna, Kode Browser, Kodi, Konqueror, KPN Veilig, KUN, Kylo, L.A. Times, Ladybird, Lagatos Browser, Landis+Gyr AIM Browser, Lark, Laughable, Lazada, LBC, Legan Browser, Lenovo Browser, Lexi Browser, LG Browser, LG Player, libdnf, libpod, libsoup, Libsyn, LieBaoFast, Liferea, Light, Lilo, Line, LinkedIn, Links, Liri Browser, Listen, LiSTNR, Liulo, Live5ch, Logi Options+, Lolifox, LoseIt!, Lotus, Lotus Notes, Lovense Browser, LT Browser, LUA OpenResty NGINX, LuaKit, Lulumi, Luminary, Lunascape, Lunascape Lite, Lynx, Macrium Reflect, Maelstrom, Mail Master, mailapp, MailBar, Mailbird, Mailspring, Mandarin, Mandrill PHP, MAUI WAP Browser, MaxBrowser, Maxthon, MBolsa, mCent, Mechanize, MediaMonkey, Megaphone, Meizu Browser, MEmpresas, Menucast, Mercantile Bank of Michigan, Mercury, MessengerX, Meta Business Suite, Metacast, MetaMask, MetaTrader, MicroB, Microsoft Bing, Microsoft Copilot, Microsoft Edge, Microsoft Lync, Microsoft Office, Microsoft Office $1, Microsoft Office Mobile, Microsoft OneDrive, Microsoft Outlook, Microsoft Power Query, Microsoft Start, Microsoft Store, Midori, Mikrotik Fetch, Mimir, Minimo, Mint Browser, Miro, MIUI Browser, MixerBox, MixerBox AI, Mobicip, Mobile Safari, Mobile Silk, mobile.de, MobileSMS, Mogok Browser, MOMO, Monument Browser, MoonFM, mowPod, Moya, MPlayer, mpv, Msray-Plus, Music Player Daemon, MusicBee, MX Player, MxNitro, My Bentley, My Watch Party, My World, Mypal, MyTuner, Naenara Browser, nate, Naver, NAVER Dictionary, NAVER Mail, Navigateur Web, NCSA Mosaic, NET.mede, Netflix, NetFront, NetFront Life, NetNewsWire, NetPositive, Netscape, NetSurf, NewsArticle App, Newsbeuter, NewsBlur, NewsBlur Mobile App, Newsboat, Newsly, NexPlayer, Nextcloud, NFS Browser, Nightingale, Ninetails, Node Fetch, Nokia Browser, Nokia OSS Browser, Nokia Ovi Browser, NOOK Browser, Norton Private Browser, Notion, Nox Browser, NPR, NRC, NRC Audio, NTENT Browser, NTV Mobil, Nuanti Meta, NuMuKi Browser, Nuviu, Obigo, OBS Studio, OceanHero, Oculus Browser, Odd Browser, Odin, Odnoklassniki, Odyssey Web Browser, Off By One, OfferUp, OhHai Browser, OKDownload Library, OkHttp, OmniWeb, OnBrowser Lite, ONE Browser, Onion Browser, Opal Travel, Open Build Service, OpenFin, Openwave Mobile Browser, Opera, Opera Devices, Opera GX, Opera Mini, Opera Mini iOS, Opera Mobile, Opera Neon, Opera News, Opera Next, Opera Touch, Opera Updater, Oppo Browser, Orange Radio, Orca, Ordissimo, Oregano, Origin In-Game Overlay, Origyn Web Browser, Otter Browser, Outcast, Outlook Express, Overcast, Overhaul FM, Pa11y, Paint by Number, Palco MP3, Pale Moon, Palm Blazer, Palm Pre, Palm WebPro, Palmscape, Pandora, Papers, PeaCast, Peeps dBrowser, Perfect Browser, Perl, Perl REST::Client, Petal Search, Phantom Browser, Phoenix, Phoenix Browser, PHP cURL Class, Pi Browser, Pic Collage, PICO Browser, Pinterest, PirateBrowser, Playapod, Player FM, PlayFree Browser, PLAYit, Plex Media Server, Pocket Casts, PocketBook Browser, Podbay, Podbean, Podcast & Radio Addict, Podcast App, Podcast Guru, Podcast Player, Podcast Republic, Podcastly, Podcat, Podcatcher Deluxe, Podchaser, Podclipper, PodCruncher, Podeo, Podfriend, Podgrab, Podhero, Podimo, PodKast, Podkicker Pro, Podkicker$1, PodLP, PodMe, PodMN, PodNL, Podopolo, Podplay, PodPuppy, Pods, PodTrapper, podU, Podurama, Podverse, Podvine, Podyssey, Polaris, Polarity, PolyBrowser, Polypane, Postbox, Postman Desktop, PowerShell, PRDownloader, PritTorrent, PrivacyWall, Procast, Proxy Browser, PSI Secure Browser, Puffin, PugPig Bolt, Pulp, Python Requests, Python urllib, Q-municate, Qazweb, QbHttp, qBittorrent, Qiyu, QQ Browser, QQ Browser Lite, QQ Browser Mini, QQMusic, QtWebEngine, Quark, quic-go, Quick Search TV, QuickCast, Quicksilver, QuickTime, QuiteRSS, Quora, QupZilla, Qutebrowser, Qwant Mobile, R, r-curl, Radio Downloader, Radio Italiane, Radio Next, radio.$1, RadioApp, Radioline, RadioPublic, Raindrop.io, Rakuten Browser, Rakuten Web Search, Rambox Pro, Raspbian Chromium, Rave Social, Razer Synapse, RDDocuments, ReactorNetty, ReadKit, Realme Browser, Reddit, Redditor, Reeder, Rekonq, rekordbox, Repod, Report Runner, req, request, Requests, reqwest, Reqwireless WebViewer, REST Client for Ruby, RestSharp, Resty, resty-requests, Rhythmbox, RNPS Action Cards, Roblox, RoboForm, Rocket Chat, RockMelt, Roku Browser, RSS Bandit, RSS Junkie, RSSDemon, RSSOwl, RSSRadio, ruby, Rutube, SachNoi, Safari, Safari Search Helper, Safari Technology Preview, Safari View Service, Safe Exam Browser, SafeIP, Sailfish Browser, SalamWeb, Samsung Browser, Samsung Magician, Samsung Podcasts, SberBrowser, ScalaJ HTTP, SeaMonkey, SearchCraft, Secure Browser, Secure Private Browser, SecureX, Seewo Browser, SEMC-Browser, Seraphic Sraf, ServeStream, Seznam Browser, SFive, Shadow, Shadowrocket, Shiira, Shopee, ShowMe, Signal, SimpleBrowser, Sina Weibo, Siri, SiriusXM, SiteKiosk, Sizzy, Skopeo, Skye, Skyeng, Skyeng Teachers, Skyfire, SkyLeap, Skype, Skype for Business, Slack, Sleipnir, Slim Framework, SlimBoat, SlimerJS, Slimjet, Smart Lenovo Browser, Smooz, Snapchat, Snipd, Snowshoe, SoFi, Sogou Explorer, Sogou Mobile Browser, SogouSearch App, SohuNews, Soldier, Songbird, Sonnet, SONOS, Sony Media Go, Sony PlayStation 5, Soul Browser, SoundOn, SoundWaves, SP Browser, Spectre Browser, Spicebird, Splash, SPORT1, Spotify, Spreaker, Sputnik Browser, Stagefright, Stampy Browser, Stargon, START Internet Browser, Startsiden, Stealer, Steam In-Game Overlay, Stitcher, StoryShots, Stream Master, Streamlabs OBS, Streamy, Strimio, Stringer, StudioDisplay, SubStream, Sunrise, Super Fast Browser, superagent, SuperBird, surf, Surf Browser, Surfshark, Surfy Browser, Sushi Browser, Swiftfox, Swinsian, Swoot, Symfony, T+Browser, T-Browser, t-online.de Browser, Tao Browser, Taobao, tararia, Teams, TenFourFox, Tenta Browser, Tesla Browser, The Bat!, The New York Times, The Wall Street Journal, Theyub, Threads, Thunder, Thunderbird, tieba, TikTok, TiviMate, Tizen Browser, ToGate, TopBuzz, Trade Me, TradingView, Treble.fm, TrueLocation Browser, TuneIn Radio, TuneIn Radio Pro, Tungsten, Turtlecast, Tuya Smart Life, TV Bro, TVirl, TweakStyle, twinkle, Twitch Studio, Twitter, Twitterrific, Typhoeus, U Browser, U-Cursos, Ubook Player, UBrowser, UC Browser, UC Browser HD, UC Browser Mini, UC Browser Turbo, UCast, uclient-fetch, Uconnect LIVE, Uforia, Ultimate Sitemap Parser, undici, Unibox, Unirest for Java, UnityPlayer, UR Browser, urlgrabber (yum), uTorrent, Uzbl, Vast Browser, VD Browser, Venus Browser, Vertex Surf, Viasat Browser, VibeMate, Viber, Victor Reader Stream 3, Victor Reader Stream New Generation, Victor Reader Stream Trek, Virgin Radio, Vision Mobile Browser, Visual Studio Code, Vivaldi, vivo Browser, VLC, VMware AirWatch, Vodacast, Vonkeror, Vuhuv, Vuze, w3m, waipu.tv, Waterfox, Wattpad, Wayback Machine, Wear Internet Browser, Web Explorer, WebDAV, WebDiscover, Webian Shell, WebPositive, WeChat, WeChat Share Extension, Weltweitimnetz Browser, WeTab Browser, Wexond, Wget, WH Questions, Whale Browser, Whatplay, WhatsApp, WhatsApp Business, WhatsApp+2, Whisper, Winamp, Windows Antivirus, Windows CryptoAPI, Windows Delivery Optimization, Windows HTTP, Windows Mail, Windows Media Player, Windows Push Notification Services, Windows Update Agent, WinHttp WinHttpRequest, Wireshark, Wirtschafts Woche, WNYC, Wolvic, Word Cookies!, wOSBrowser, WPS Office, WWW-Mechanize, Wynk Music, Wyzo, XBMC, Xiao Yu Zhou, Xiino, XING, XML-RPC, XSplit Broadcaster, xStand, Xtream Player, Xvast, Y8 Browser, Yaani Browser, YAGI, Yahoo Mail, Yahoo OneSearch, Yahoo! Japan, Yahoo! Japan Browser, Yahoo! Mail, YakYak, Yandex, Yandex Browser, Yandex Browser Lite, Yandex Music, Yapa, Yelp Mobile, Yo WhatsApp, Yolo Browser, YouBrowser, YouCare, YouTube, Youtube Music, YouView, Zalo, Zen, ZEPETO, Zetakey, Zoho Chat, Zune, Zvu ### Devices 10moons, 2E, 360, 3GNET, 3GO, 3Q, 4Good, 4ife, 5IVE, 7 Mobile, 8848, A&K, A1, A95X, AAUW, Accent, Accesstyle, Ace, Aceline, Acer, Acteck, actiMirror, Adronix, Advan, Advance, Advantage Air, AEEZO, AFFIX, AfriOne, AG Mobile, AGM, AIDATA, Ainol, Airis, Airness, AIRON, Airpha, Airtel, Airties, AirTouch, AIS, Aiuto, Aiwa, Ajib, Akai, AKIRA, Alba, Alcatel, Alcor, ALDI NORD, ALDI SÜD, Alfawise, Alienware, Aligator, AllCall, AllDocube, ALLINmobile, Allview, Allwinner, Alps, Altech UEC, Altice, Altimo, altron, Altus, AMA, Amazon, Amazon Basics, AMCV, AMGOO, Amigoo, Amino, Amoi, ANBERNIC, Andowl, Angelcare, AngelTech, Anker, Anry, ANS, ANXONIT, AOC, Aocos, Aocwei, AOpen, Aoro, Aoson, AOYODKG, Apple, Aquarius, Archos, Arian Space, Arival, Ark, ArmPhone, Arnova, ARRIS, Artel, Artizlee, ArtLine, Arçelik, Asano, Asanzo, Ask, Aspera, ASSE, Assistant, Astro, Asus, AT&T, Athesi, Atlantic Electrics, Atmaca Elektronik, ATMAN, ATOL, Atom, Attila, Atvio, Audiovox, AUPO, AURIS, Autan, AUX, Avaya, Avenzo, AVH, Avvio, Awow, AWOX, AXEN, Axioo, AXXA, Axxion, AYA, AYYA, Azeyou, Azumi Mobile, b2m, Backcell, BAFF, BangOlufsen, Barnes & Noble, BARTEC, BASE, BAUHN, BB Mobile, BBK, BDF, BDQ, BDsharing, Beafon, Becker, Beeline, Beelink, Beetel, Beista, Beko, Bellphone, Benco, Benesse, BenQ, BenQ-Siemens, BenWee, Benzo, Beyond, Bezkam, BGH, Bigben, BIHEE, BilimLand, Billion, Billow, BioRugged, Bird, Bitel, Bitmore, Bittium, Bkav, Black Bear, Black Box, Black Fox, Blackpcs, Blackview, Blaupunkt, Bleck, BLISS, Blloc, Blow, Blu, Bluboo, Bluebird, Bluedot, Bluegood, BlueSky, Bluewave, BluSlate, BMAX, Bmobile, BMW, BMXC, Bobarry, bogo, Bolva, Bookeen, Boost, Botech, Boway, bq, BrandCode, Brandt, BRAVE, Bravis, BrightSign, Brigmton, Brondi, BROR, BS Mobile, Bubblegum, Bundy, Bush, BuzzTV, C Idea, C5 Mobile, CADENA, CAGI, Camfone, Canal Digital, Canal+, Canguro, Capitel, Captiva, Carbon Mobile, Carrefour, Casio, Casper, Cat, Cavion, CCIT, Cecotec, Ceibal, Celcus, Celkon, Cell-C, Cellacom, CellAllure, Cellution, CENTEK, Centric, CEPTER, CG Mobile, CGV, Chainway, Changhong, Cherry Mobile, Chico Mobile, ChiliGreen, China Mobile, China Telecom, Chuwi, CipherLab, Citycall, CKK Mobile, Claresta, Clarmin, CLAYTON, ClearPHONE, Clementoni, Cloud, Cloudfone, Cloudpad, Clout, Clovertek, CnM, Cobalt, Coby Kyros, Colors, Comio, Compal, Compaq, COMPUMAX, ComTrade Tesla, Conceptum, Concord, ConCorde, Condor, Connectce, Connex, Conquest, Continental Edison, Contixo, COOD-E, Coolpad, Coopers, CORN, Cosmote, Covia, Cowon, COYOTE, CreNova, Crescent, Cricket, Crius Mea, Crony, Crosscall, Crown, Ctroniq, Cube, CUBOT, Cuiud, CVTE, Cwowdefu, Cyrus, D-Link, D-Tech, Daewoo, Danew, DangcapHD, Dany, Daria, DASS, Datalogic, Datamini, Datang, Datawind, Datsun, Dazen, DbPhone, Dbtel, Dcode, DEALDIG, Dell, Denali, Denver, Desay, DeWalt, DEXP, DEYI, DF, DGTEC, DIALN, Dialog, Dicam, Digi, Digicel, DIGICOM, Digidragon, DIGIFORS, Digihome, Digiland, Digit4G, Digma, DIJITSU, DIKOM, DIMO, Dinalink, Dinax, DING DING, DIORA, DISH, Disney, Ditecma, Diva, DiverMax, Divisat, DIXON, DL, DMM, DNS, DoCoMo, Doffler, Dolamee, Dom.ru, Doogee, Doopro, Doov, Dopod, Doppio, DORLAND, Doro, DPA, DRAGON, Dragon Touch, Dreamgate, DreamStar, DreamTab, Droidlogic, Droxio, DSDevices, DSIC, Dtac, Dune HD, DUNNS Mobile, Durabook, Duubee, Dyon, E-Boda, E-Ceros, E-tel, Eagle, EagleSoar, EAS Electric, Easypix, EBEN, EBEST, Echo Mobiles, ecom, ECON, ECOO, ECS, Edenwood, EE, EFT, EGL, Einstein, EKINOX, EKO, Eks Mobility, EKT, ELARI, Elecson, Electroneum, ELECTRONIA, Elekta, Elektroland, Element, Elenberg, Elephone, Elevate, Elong Mobile, Eltex, Ematic, Emporia, ENACOM, Energizer, Energy Sistem, Engel, ENIE, Enot, eNOVA, Entity, Envizen, Ephone, Epic, Epik One, Epson, Equator, Ergo, Ericsson, Ericy, Erisson, Essential, Essentielb, eSTAR, ETOE, Eton, eTouch, Etuline, Eurocase, Eurostar, Evercoss, Everest, Everex, Evertek, Evolio, Evolveo, Evoo, EVPAD, EvroMedia, EWIS, EXCEED, Exmart, ExMobile, EXO, Explay, Express LUCK, ExtraLink, Extrem, Eyemoo, EYU, Ezio, Ezze, F&U, F+, F150, F2 Mobile, Facebook, Facetel, Facime, Fairphone, Famoco, Famous, Fantec, FaRao Pro, Farassoo, FarEasTone, Fengxiang, Fenoti, FEONAL, Fero, FFF SmartLife, Figgers, FiGi, FiGO, FiiO, Filimo, FILIX, FinePower, Finlux, FireFly Mobile, FISE, FITCO, Fluo, Fly, FLYCAT, FLYCOAY, FMT, FNB, FNF, Fobem, Fondi, Fonos, FOODO, FORME, Formuler, Forstar, Fortis, FOSSiBOT, Four Mobile, Fourel, Foxconn, FoxxD, FPT, free, Freetel, FreeYond, Frunsi, Fuego, Fujitsu, Funai, Fusion5, Future Mobile Technology, Fxtec, G-TiDE, G-Touch, Galactic, Galaxy Innovations, Gamma, Garmin-Asus, Gateway, Gazer, Geanee, Geant, Gear Mobile, Gemini, General Mobile, Genesis, GEOFOX, Geotel, Geotex, GEOZON, Getnord, GFive, Gfone, Ghia, Ghong, Ghost, Gigabyte, Gigaset, Gini, Ginzzu, Gionee, GIRASOLE, Globex, Globmall, Glofiish, GLONYX, GLX, GOCLEVER, Gocomma, GoGEN, Gol Mobile, GOLDBERG, GoldMaster, GoldStar, Goly, Gome, GoMobile, GOODTEL, Google, Goophone, Gooweel, Gplus, Gradiente, Graetz, Grape, Great Asia, Gree, Green Lion, Green Orange, Greentel, Gresso, Gretel, GroBerwert, Grundig, Gtel, GTMEDIA, GTX, Guophone, H133, H96, Hafury, Haier, Haipai, Hamlet, Hammer, Handheld, HannSpree, Hanseatic, HAOQIN, HAOVM, Hardkernel, Harper, Hartens, Hasee, Hathway, HDC, HeadWolf, HEC, Heimat, Helio, HERO, HexaByte, Hezire, Hi, Hi Nova, Hi-Level, Hiberg, HiBy, High Q, Highscreen, HiGrace, HiHi, HiKing, HiMax, HIPER, Hipstreet, Hiremco, Hisense, Hitachi, Hitech, HKC, HKPro, HLLO, HMD, HOFER, Hoffmann, HOLLEBERG, Homatics, Hometech, Homtom, Honeywell, Hoozo, Horizon, Horizont, Hosin, Hot Pepper, Hotel, HOTREALS, Hotwav, How, HP, HTC, Huadoo, Huagan, Huavi, Huawei, Hugerock, Humax, Hurricane, Huskee, Hykker, Hytera, Hyundai, Hyve, i-Cherry, I-INN, i-Joy, i-mate, i-mobile, I-Plus, iBall, iBerry, ibowin, iBrit, IconBIT, iData, iDino, iDroid, iGet, iHunt, Ikea, IKI Mobile, iKoMo, iKon, iKonia, IKU Mobile, iLA, iLepo, iLife, iMan, Imaq, iMars, iMI, IMO Mobile, Imose, Impression, iMuz, iNavi, INCAR, Inch, Inco, iNew, Infiniton, Infinix, InFocus, InfoKit, Infomir, InFone, Inhon, Inka, Inkti, InnJoo, Innos, Innostream, iNo Mobile, Inoi, iNOVA, inovo, INQ, Insignia, INSYS, Intek, Intel, Intex, Invens, Inverto, Invin, iOcean, IOTWE, iOutdoor, iPEGTOP, iPro, iQ&T, IQM, IRA, Irbis, iReplace, Iris, iRobot, iRola, iRulu, iSafe Mobile, iStar, iSWAG, IT, iTel, iTruck, IUNI, iVA, iView, iVooMi, ivvi, iWaylink, iXTech, iYou, iZotron, JAY-Tech, Jedi, Jeep, Jeka, Jesy, JFone, Jiake, Jiayu, Jin Tu, Jinga, Jio, Jivi, JKL, Jolla, Joy, JoySurf, JPay, JREN, Jumper, Juniper Systems, Just5, JVC, JXD, K-Lite, K-Touch, Kaan, Kaiomy, Kalley, Kanji, Kapsys, Karbonn, Kata, KATV1, Kazam, Kazuna, KDDI, Kempler & Strauss, Kenbo, Kendo, Keneksi, KENSHI, Kenxinda, Khadas, Kiano, Kingbox, Kingstar, Kingsun, KINGZONE, Kinstone, Kiowa, Kivi, Klipad, KN Mobile, Kocaso, Kodak, Kogan, Komu, Konka, Konrow, Koobee, Koolnee, Kooper, KOPO, Koridy, Koslam, Kraft, KREZ, KRIP, KRONO, Krüger&Matz, KT-Tech, KUBO, KuGou, Kuliao, Kult, Kumai, Kurio, KVADRA, Kvant, Kydos, Kyocera, Kyowon, Kzen, KZG, L-Max, LAIQ, Land Rover, Landvo, Lanin, Lanix, Lark, Laurus, Lava, LCT, Le Pan, Leader Phone, Leagoo, Leben, LeBest, Lectrus, Ledstar, LeEco, Leelbox, Leff, Legend, Leke, Lemco, LEMFO, Lemhoov, Lenco, Lenovo, Leotec, Lephone, Lesia, Lexand, Lexibook, LG, Liberton, Lifemaxx, Lime, Lingbo, Lingwin, Linnex, Linsar, Linsay, Listo, LNMBBS, Loewe, Logic, Logic Instrument, Logicom, Logik, LOKMAT, Loview, Lovme, LPX-G, LT Mobile, Lumigon, Lumitel, Lumus, Luna, Luxor, Lville, LYF, M-Horse, M-Tech, M.T.T., M3 Mobile, M4tel, MAC AUDIO, Macoox, Mafe, MAG, MAGCH, Magicsee, Magnus, Majestic, Malata, Mango, Manhattan, Mann, Manta Multimedia, Mantra, Mara, Marshal, Mascom, Massgo, Masstel, Master-G, Mastertech, Matco Tools, Matrix, Maunfeld, Maxcom, Maxfone, Maximus, Maxtron, MAXVI, Maxwell, Maxwest, MAXX, Maze, Maze Speed, MBI, MBK, MBOX, MDC Store, MDTV, meanIT, Mecer, Mecool, Mediacom, MediaTek, Medion, MEEG, MEGA VISION, MegaFon, Meitu, Meizu, Melrose, MeMobile, Memup, MEO, Meta, Metz, MEU, MicroMax, Microsoft, Microtech, Minix, Mint, Mintt, Mio, Mione, mipo, Miray, Mitchell & Brown, Mito, Mitsubishi, Mitsui, MIVO, MIWANG, MIXC, MiXzo, MLAB, MLLED, MLS, MMI, Mobell, Mobicel, MobiIoT, Mobiistar, Mobile Kingdom, Mobiola, Mobistel, MobiWire, Mobo, Mobvoi, Modecom, Mofut, Mosimosi, Motiv, Motorola, Movic, MOVISUN, Movitel, Moxee, mPhone, Mpman, MSI, MStar, MTC, MTN, Multilaser, MultiPOS, MwalimuPlus, MYFON, MyGica, MygPad, Mymaga, MyMobile, MyPhone, Myria, Myros, Mystery, MyTab, MyWigo, N-one, Nabi, NABO, Nanho, Naomi Phone, NASCO, National, Navcity, Navitech, Navitel, Navon, NavRoad, NEC, Necnot, Nedaphone, Neffos, NEKO, Neo, neoCore, Neolix, Neomi, Neon IQ, Neoregent, NetBox, Netgear, Netmak, NeuImage, NeuTab, NEVIR, New Balance, New Bridge, Newgen, Newland, Newman, Newsday, NewsMy, Nexa, NEXBOX, Nexian, NEXON, NEXT, Next & NextStar, Nextbit, NextBook, NextTab, NG Optics, NGM, NGpon, Nikon, NINETEC, Nintendo, nJoy, NOA, Noain, Nobby, Noblex, NOBUX, noDROPOUT, NOGA, Nokia, Nomi, Nomu, Noontec, Nordmende, NORMANDE, NorthTech, Nos, Nothing Phone, Nous, Novacom, Novex, Novey, NoviSea, NOVO, NTT West, NuAns, Nubia, NUU Mobile, NuVision, Nuvo, Nvidia, NYX Mobile, O+, O2, Oale, Oangcc, OASYS, Obabox, Ober, Obi, OCEANIC, Odotpad, Odys, OINOM, Ok, Okapia, Oking, OKSI, OKWU, Olax, Olkya, Ollee, OLTO, Olympia, OMIX, Onda, OneClick, OneLern, OnePlus, Onida, Onix, Onkyo, ONN, ONVO, ONYX BOOX, Ookee, Ooredoo, OpelMobile, Openbox, Ophone, OPPO, Opsson, Optoma, Orange, Orava, Orbic, Orbita, Orbsmart, Ordissimo, Orion, OSCAL, OTTO, OUJIA, Ouki, Oukitel, OUYA, Overmax, Ovvi, Owwo, OYSIN, Oysters, Oyyu, OzoneHD, P-UP, Pacific Research Alliance, Packard Bell, Padpro, PAGRAER, Paladin, Palm, Panacom, Panasonic, Panavox, Pano, Panodic, Panoramic, Pantech, PAPYRE, Parrot Mobile, Partner Mobile, PC Smart, PCBOX, PCD, PCD Argentina, PEAQ, Pelitt, Pendoo, Penta, Pentagram, Perfeo, Phicomm, Philco, Philips, Phonemax, phoneOne, Pico, PINE, Pioneer, Pioneer Computers, PiPO, PIRANHA, Pixela, Pixelphone, Pixus, Planet Computers, Platoon, Play Now, Ployer, Plum, PlusStyle, Pluzz, PocketBook, POCO, Point Mobile, Point of View, Polar, PolarLine, Polaroid, Polestar, PolyPad, Polytron, Pomp, Poppox, POPTEL, Porsche, Positivo, Positivo BGH, PPTV, Premier, Premio, Prestigio, PRIME, Primepad, Primux, Pritom, Prixton, PROFiLO, Proline, Prology, ProScan, PROSONIC, Protruly, ProVision, PULID, Punos, Purism, Q-Box, Q-Touch, Q.Bell, QFX, Qilive, QIN, QLink, QMobile, Qnet Mobile, QTECH, Qtek, Quantum, Quatro, Qubo, Quechua, Quest, Quipus, Qumo, Qware, QWATT, R-TV, Rakuten, Ramos, Raspberry, Ravoz, Raylandz, Razer, RCA Tablets, Reach, Readboy, Realme, RED, Redbean, Redfox, RedLine, Redway, Reeder, REGAL, RelNAT, Remdun, Renova, Retroid Pocket, Revo, Revomovil, Ricoh, Rikomagic, RIM, Rinno, Ritmix, Ritzviva, Riviera, Rivo, Rizzen, ROADMAX, Roadrover, Roam Cat, Rocket, ROiK, Rokit, Roku, Rombica, Ross&Moor, Rover, RoverPad, Royole, RoyQueen, RT Project, RugGear, RuggeTech, Ruggex, Ruio, Runbo, Rupa, Ryte, S-Color, S-TELL, S2Tel, Saba, Safaricom, Sagem, Sagemcom, Saiet, SAILF, Salora, Samsung, Samtech, Samtron, Sanei, Sankey, Sansui, Santin, SANY, Sanyo, Savio, Sber, SCBC, Schneider, Schok, Scosmos, Seatel, SEBBE, Seeken, SEEWO, SEG, Sega, SEHMAX, Selecline, Selenga, Selevision, Selfix, SEMP TCL, Sencor, Sendo, Senkatel, Senseit, Senwa, Seuic, Sewoo, SFR, SGIN, Shanling, Sharp, Shift Phones, Shivaki, Shtrikh-M, Shuttle, Sico, Siemens, Sigma, Silelis, Silent Circle, Silva Schneider, Simbans, simfer, Simply, Singtech, Siragon, Sirin Labs, SK Broadband, SKG, SKK Mobile, Sky, Skyline, SkyStream, Skytech, Skyworth, Smadl, Smailo, Smart, Smart Electronic, Smart Kassel, Smartab, SmartBook, SMARTEC, Smartex, Smartfren, Smartisan, Smarty, Smooth Mobile, Smotreshka, SMUX, SNAMI, SobieTech, Soda, Softbank, Soho Style, Solas, SOLE, SOLO, Solone, Sonim, SONOS, Sony, SOSH, SoulLink, Soundmax, Soyes, Spark, Sparx, SPC, Spectralink, Spectrum, Spice, Sprint, SPURT, SQOOL, SSKY, Star, Starlight, Starmobile, Starway, Starwind, STF Mobile, STG Telecom, STK, Stonex, Storex, StrawBerry, Stream, STRONG, Stylo, Subor, Sugar, Sumvision, Sunmax, Sunmi, Sunny, Sunstech, SunVan, Sunvell, SUNWIND, Super General, SuperBOX, SuperSonic, SuperTab, Supra, Supraim, Surfans, Surge, Suzuki, Sveon, Swipe, SWISSMOBILITY, Swisstone, Switel, Syco, SYH, Sylvania, Symphony, Syrox, System76, T-Mobile, T96, TADAAM, TAG Tech, Taiga System, Takara, Talius, Tambo, Tanix, TAUBE, TB Touch, TCL, TD Systems, TD Tech, TeachTouch, Technicolor, Technika, TechniSat, Technopc, TECHNOSAT, TechnoTrend, TechPad, TechSmart, Techstorm, Techwood, Teclast, Tecno Mobile, TecToy, TEENO, Teknosa, Tele2, Telefunken, Telego, Telenor, Telia, Telit, Telkom, Telly, Telma, TeloSystems, Telpo, TENPLUS, Teracube, Tesco, Tesla, TETC, Tetratab, teXet, ThL, Thomson, Thuraya, TIANYU, Tibuta, Tigers, Time2, Timovi, TIMvision, Tinai, Tinmo, TiPhone, TiVo, TJC, TOKYO, Tolino, Tone, TOOGO, Tooky, Top House, TopDevice, TOPDON, Topelotek, Toplux, TOPSHOWS, Topsion, Topway, Torex, Torque, TOSCIDO, Toshiba, Touch Plus, Touchmate, TOX, TPS, Transpeed, TrekStor, Trevi, TriaPlay, Trident, Trifone, Trio, Tronsmart, True, True Slim, Tsinghua Tongfang, TTEC, TTfone, TTK-TV, TuCEL, Tunisie Telecom, Turbo, Turbo-X, TurboKids, TurboPad, Turkcell, Tuvio, TVC, TwinMOS, TWM, Twoe, TWZ, TYD, Tymes, Türk Telekom, U-Magic, U.S. Cellular, UD, UE, UGINE, Ugoos, Uhans, Uhappy, Ulefone, Umax, UMIDIGI, Unblock Tech, Uniden, Unihertz, Unimax, Uniqcell, Uniscope, Unistrong, Unitech, UNIWA, Unknown, Unnecto, Unnion Technologies, UNNO, Unonu, Unowhy, UOOGOU, Urovo, UTime, UTOK, UTStarcom, UZ Mobile, V-Gen, V-HOME, V-HOPE, v-mobile, VAIO, VALE, VALEM, VALTECH, VANGUARD, Vankyo, VANWIN, Vargo, Vastking, VAVA, VC, VDVD, Vega, Vekta, Venso, Venstar, Venturer, VEON, Verico, Verizon, Vernee, Verssed, Versus, Vertex, Vertu, Verykool, Vesta, Vestel, VETAS, Vexia, VGO TEL, ViBox, Victurio, VIDA, Videocon, Videoweb, ViewSonic, VIIPOO, VILLAON, Vinabox, Vinga, Vinsoc, Vios, Viper, Vipro, Virzo, Vision Touch, Visual Land, Vitelcom, Vityaz, Viumee, Vivax, VIVIMAGE, Vivo, VIWA, Vizio, Vizmo, VK Mobile, VKworld, VNPT Technology, VOCAL, Vodacom, Vodafone, VOGA, VOLIA, VOLKANO, Volla, Volt, Vonino, Vontar, Vorago, Vorcom, Vorke, Vormor, Vortex, Voto, VOX, Voxtel, Voyo, Vsmart, Vsun, VUCATIMES, Vue Micro, Vulcan, VVETIME, Völfen, W&O, WAF, Wainyok, Walker, Walton, Waltter, Wanmukang, WANSA, WE, We. by Loewe., Webfleet, WeChip, Wecool, Weelikeit, Weimei, WellcoM, WELLINGTON, Western Digital, Westpoint, Wexler, White Mobile, Whoop, Wieppo, Wigor, Wiko, Wileyfox, Winds, Wink, Winmax, Winnovo, Winstar, Wintouch, Wiseasy, WIWA, WizarPos, Wizz, Wolder, Wolfgang, Wolki, WONDER, Wonu, Woo, Wortmann, Woxter, WS, X-AGE, X-BO, X-Mobile, X-TIGI, X-View, X.Vision, X88, X96, X96Q, Xcell, XCOM, Xcruiser, XElectron, XGEM, XGIMI, Xgody, Xiaodu, Xiaolajiao, Xiaomi, Xion, Xolo, Xoro, Xshitou, Xsmart, Xtouch, Xtratech, Xwave, XY Auto, Yandex, Yarvik, YASIN, YELLYOUTH, YEPEN, Yes, Yestel, Yezz, Yoka TV, Yooz, Yota, YOTOPT, Youin, Youwei, Ytone, Yu, YU Fly, Yuandao, YUHO, YUMKEM, YUNDOO, Yuno, YunSong, Yusun, Yxtel, Z-Kai, Zaith, Zamolxe, Zatec, Zealot, Zeblaze, Zebra, Zeeker, Zeemi, Zen, Zenek, Zentality, Zfiner, ZH&K, Zidoo, ZIFRO, Zigo, ZIK, Zinox, Ziox, Zonda, Zonko, Zoom, ZoomSmart, Zopo, ZTE, Zuum, Zync, ZYQ, Zyrex, öwn ## Maintainers - Mateusz Sojka: https://github.com/matisojka - Ben Zimmer: https://github.com/benzimmer ## Contributors Thanks a lot to the following contributors: - Peter Gao: https://github.com/peteygao - Stefan Kaes: https://github.com/skaes - Dennis Wu: https://github.com/dnswus - Steve Robinson: https://github.com/steverob - Mark Dodwell: https://github.com/mkdynamic - Sean Dilda: https://github.com/seandilda - Stephan Leibelt: https://github.com/sliminas - Rafael Porras Lucena: https://github.com/rporrasluc - Anton Rieder: https://github.com/aried3r - Bruno Arueira: https://github.com/brunoarueira - Nicolas Rodriguez: https://github.com/n-rodriguez - Igor Drozdov: https://github.com/igor-drozdov - Axeleander: https://github.com/Axeleander - Igor Pstyga: https://github.com/opti ## Contributing 1. Open an issue and explain your feature request or bug before writing any code (this can save a lot of time, both the contributor and the maintainers!) 2. Fork the project (https://github.com/podigee/device_detector/fork) 3. Create your feature branch (`git checkout -b my-new-feature`) 4. Commit your changes (`git commit -am 'Add some feature'`) 5. Push to the branch (`git push origin my-new-feature`) 6. Create a new Pull Request (compare with develop) 7. When adding new data to the yaml files, please make sure to open a PR in the original project, as well (https://github.com/piwik/device-detector) device_detector-1.1.3/CHANGELOG.md0000644000004100000410000000564314656360041016522 0ustar www-datawww-data# Change Log ## [1.1.3] - Updated detection rules from upstream on 2024-06-25 ([#124](https://github.com/podigee/device_detector/pull/124)) ## [1.1.2] - Updated detection rules from upstream on 2023-11-27 ## [1.1.1] - Updated detection rules from upstream on 2023-07-01 - Fix issue when user agent is nil ([#104](https://github.com/podigee/device_detector/issues/104)) - Fix issue when user agent is not UTF-8 encoded ([#105](https://github.com/podigee/device_detector/issues/105), [#106](https://github.com/podigee/device_detector/issues/106)) - Improve device brand name detection ## [1.1.0] - Updated detection rules from upstream on 2022-12-09 - Add support for client hints in header - Changed the minimum required Ruby version (>= 2.7.5) ## [1.0.7] - Updated detection rules from upstream on 2022-02-17 - Fixes Ruby warnings when compiling RegExes ([#89](https://github.com/podigee/device_detector/issues/89), [#91](https://github.com/podigee/device_detector/issues/91)) ## [1.0.6] - Updated detection rules from upstream on 2021-10-28 ## [1.0.5] - Updated detection rules from upstream on 2020-10-06 ## [1.0.4] - Updated detection rules from upstream on 2020-06-23 - [Issue #69](https://github.com/podigee/device_detector/issues/69): Performance: RegExp definitions are only loaded once. - [Issue #74](https://github.com/podigee/device_detector/issues/74): Development: Added Rubocop ## [1.0.3] - Updated detection rules from upstream on 2019-12-09 ## [1.0.2] - Updated detection rules from upstream on 2019-08-05 ## [1.0.1] - Updated detection rules from upstream on 2018-04-27 ## [1.0.0] - Boom! The 1.0.0 has landed :) ## [0.9.0] - Preparing for the 1.0.0 release. This version (with minor bumps) will be promoted to 1.0.0 once the release has been proven stable - Updated regex files from upstream - Updated test fixtures from upstream ## [0.8.2] - Added device brand support. Thanks to [dnswus](https://github.com/dnswus) ## [0.8.1] - Added Instacast detection rules - Updated test fixtures ## [0.8.0] - Added a better and more robust device detection. Thanks to [skaes](https://github.com/skaes) - Added test fixture from the piwik project ## [0.7.0] - [Issue #8](https://github.com/podigee/device_detector/issues/8) Fixed Mac OS X full version format. Thanks to [aaronchi](https://github.com/aaronchi) for reporting ## [0.6.0] - [Issue #7](https://github.com/podigee/device_detector/issues/7) Fixed missing name extraction from regexp. Thanks to [janxious](https://github.com/janxious) for reporting - Optimized performance of name and version extraction, by using the built-in memory cache - Move specs from RSpec to the more lightweight Minitest ## [0.5.1] - Added the minimum required Ruby version (>= 1.9.3) ## [0.5.0] - Added rake task for automatic generation of supported and detectable clients and devices - Updated detection rules - Fixed device type detection, when type is specified on top level of a nested regex