Coder Social home page Coder Social logo

moneypenny's People

Contributors

michalmytych avatar mmdevcodeclutch avatar

Stargazers

 avatar  avatar

Watchers

 avatar

moneypenny's Issues

Withour pusher credentials provided, saving settings after registrations fails

cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://api-mt1.pusher.com/apps//events?auth_key=&auth_timestamp=1696368135&auth_version=1.0&body_md5=db32474e85fd8323d4020067c21a680d&auth_signature=bba44d7840480c9580cce1a8474882ac854f67e06c308b56fe90e6f84bddec14

Framework agnostic business logic

  • Separate all Laravel elements with adapter Interfaces: eg: LoggerInterface -> Log Laravel facade. Bind interfaces and concretes in AppServiceProvider.
  • Separate ORM from business logic -> Repository pattern (inject Eloquent model in concrete). In repositories map all models to domain entities, ore just use Laravel models as plain PHP object: $model->property, $model->relation (Collection).
  • Introduce own Collection (maybe implementing specific contract). Or use Laravel collection as library-like code.
  • Integrations related code move to separate modules and call through adapter interfaces.
  • Bind Laravel Events to some strings an resolve events in business logic like this:
/* @var EventDispatcherInterface $eventDispatcher Event dispatcher adapter **/
$eventDispatcher->dispatch('transaction_added', $transaction->id);

$eventsBindings = [
     'transaction_added' => [
          \App\Events\TransactionAdded::class,  [ 'transactionId' ]
     ]
];

Add first automatic feature tests

  • Account setup after registration
  • Dispatching certain jobs after registration
  • Properly displaying home page
  • Properly displaying home page
  • Displaying transactions list
  • Displaying specific transaction
  • Filtering transactions
  • Filtering transactions
  • Displaying analytics page
  • Displaying imports page
  • Displaying files page
  • Uploading file - specific jobs are triggered
  • Test validation of upload form
  • Test changing settings form - recalculation jobs are triggered
  • Test month report page
  • Displaying budgets
  • Test editing budgets
  • Test calculating budgets consumption
  • Test displaying institutions list
  • Test displaying details for institution
  • Test sync triggering (mock Nordigen)
  • Test deleting requisition
  • Test listing synchronizations
  • Test listing import settings
  • Test listing columns mappings
  • Test listing users
  • Test editing users
  • Test displaying user details
  • Test displaying meta data about server
  • Test changing profile picture
  • Test displaying devices
  • Test sending notifications when device hijacked
  • Test synchronization process
  • Test transactions import process
  • Test if notifs are send to right users
  • Test listing notifications

Add detailed error handling after file upload

  • Validate input
  • Validate file against selected import settings and columns mappings
  • Skip bad rows - display them to user so he can decide what to do with them
  • Check encoding of strings
  • Add validation rules for different columns
  • Gather statistics on errors etc. (data + row number)

Add devices icons by device type

Use Device types from this class:

<?php

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

declare(strict_types=1);

namespace DeviceDetector\Parser\Device;

use DeviceDetector\Parser\AbstractParser;

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

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

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

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

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

    /**
     * Known device brands
     *
     * Note: Before using a new brand in on of the regex files, it needs to be added here
     *
     * @var array
     */
    public static $deviceBrands = [
        '5E'  => '2E',
        '2F'  => 'F2 Mobile',
        '3Q'  => '3Q',
        'J7'  => '7 Mobile',
        '2Q'  => '3GNET',
        '4G'  => '4Good',
        '27'  => '3GO',
        '04'  => '4ife',
        '36'  => '360',
        '88'  => '8848',
        '10M' => '10moons',
        '41'  => 'A1',
        '00'  => 'Accent',
        'AE'  => 'Ace',
        'AC'  => 'Acer',
        '3K'  => 'Acteck',
        'ACT' => 'actiMirror',
        'A9'  => 'Advan',
        'AD'  => 'Advance',
        'ADV' => 'Advantage Air',
        '76'  => 'Adronix',
        'AF'  => 'AfriOne',
        'FY'  => 'AFFIX',
        'A3'  => 'AGM',
        'J0'  => 'AG Mobile',
        'AZ'  => 'Ainol',
        'AIR' => 'Airis',
        'AI'  => 'Airness',
        'ARP' => 'Airpha',
        'AT'  => 'Airties',
        '7U'  => 'Airtel',
        'U0'  => 'AIRON',
        '0A'  => 'AIS',
        'AW'  => 'Aiwa',
        '85'  => 'Aiuto',
        'U7'  => 'AIDATA',
        'AK'  => 'Akai',
        'Q3'  => 'AKIRA',
        '1A'  => 'Alba',
        'AL'  => 'Alcatel',
        '20'  => 'Alcor',
        'XY'  => 'Alps',
        'XYA' => 'XY Auto',
        '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',
        'A5'  => 'altron',
        'KN'  => 'Amazon',
        'AMA' => 'AMA',
        'AG'  => 'AMGOO',
        '9A'  => 'Amigoo',
        'AO'  => 'Amoi',
        '3J'  => 'Amino',
        '54'  => 'AMCV',
        '60'  => 'Andowl',
        'ANX' => 'ANXONIT',
        '6J'  => 'Angelcare',
        '7A'  => 'Anry',
        'A0'  => 'ANS',
        '74'  => 'Anker',
        '3N'  => 'Aoson',
        'O8'  => 'AOC',
        'J2'  => 'AOYODKG',
        '55'  => 'AOpen',
        'RW'  => 'Aoro',
        '9Y'  => 'Aocos',
        'AP'  => 'Apple',
        'AR'  => 'Archos',
        'AB'  => 'Arian Space',
        'A6'  => 'Ark',
        '5A'  => 'ArmPhone',
        'AN'  => 'Arnova',
        'AS'  => 'ARRIS',
        'AQ'  => 'Aspera',
        'HJ'  => 'Aquarius',
        '40'  => 'Artel',
        '21'  => 'Artizlee',
        '59'  => 'ArtLine',
        '8A'  => 'Asano',
        '90'  => 'Asanzo',
        '1U'  => 'Astro',
        'A4'  => 'Ask',
        'A8'  => 'Assistant',
        'ASS' => 'ASSE',
        'AU'  => 'Asus',
        '6A'  => 'AT&T',
        'ATH' => 'Athesi',
        '5Q'  => 'Atmaca Elektronik',
        'YH'  => 'ATMAN',
        '2A'  => 'Atom',
        'ATO' => 'ATOL',
        'Z2'  => 'Atvio',
        'ATI' => 'Attila',
        'AX'  => 'Audiovox',
        'AJ'  => 'AURIS',
        'YZ'  => 'Autan',
        'ZA'  => 'Avenzo',
        'AH'  => 'AVH',
        'AV'  => 'Avvio',
        'AVA' => 'Avaya',
        'AY'  => 'Axxion',
        'AXX' => 'AXXA',
        'YR'  => 'AYYA',
        'XA'  => 'Axioo',
        'AM'  => 'Azumi Mobile',
        'WW'  => 'Awow',
        'XU'  => 'AUX',
        'BAC' => 'Backcell',
        'BO'  => 'BangOlufsen',
        'BN'  => 'Barnes & Noble',
        'BB'  => 'BBK',
        '0B'  => 'BB Mobile',
        'B6'  => 'BDF',
        'QD'  => 'BDQ',
        '8Z'  => 'BDsharing',
        'BEF' => 'Beafon',
        'BE'  => 'Becker',
        'B5'  => 'Beeline',
        'B0'  => 'Beelink',
        'BL'  => 'Beetel',
        '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',
        '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',
        'BW'  => 'Boway',
        'BOO' => 'Boost',
        'BOK' => 'Bookeen',
        'BX'  => 'bq',
        '8B'  => 'Brandt',
        'BRA' => 'BrandCode',
        'BV'  => 'Bravis',
        'BRV' => 'BRAVE',
        'BRG' => 'Brigmton',
        'BR'  => 'Brondi',
        'XF'  => 'BROR',
        'BJ'  => 'BrightSign',
        'B1'  => 'Bush',
        '4Q'  => 'Bundy',
        'Y8'  => 'Bubblegum',
        'C9'  => 'CAGI',
        'CT'  => 'Capitel',
        'G3'  => 'CG Mobile',
        '37'  => 'CGV',
        'CP'  => 'Captiva',
        'CF'  => 'Carrefour',
        'CA1' => 'Carbon Mobile',
        'CS'  => 'Casio',
        'R4'  => 'Casper',
        'CA'  => 'Cat',
        'BC'  => 'Camfone',
        'CJ'  => 'Cavion',
        '4D'  => 'Canal Digital',
        'CEI' => 'Ceibal',
        '02'  => 'Cell-C',
        'CEL' => 'Cellacom',
        '34'  => 'CellAllure',
        '7C'  => 'Celcus',
        'CE'  => 'Celkon',
        'CG'  => 'Cellution',
        '62'  => 'Centric',
        'C2'  => 'Changhong',
        'CHA' => 'Chainway',
        'CHG' => 'ChiliGreen',
        'CH'  => 'Cherry Mobile',
        'C3'  => 'China Mobile',
        'U9'  => 'China Telecom',
        'CI'  => 'Chico Mobile',
        'CIP' => 'CipherLab',
        'CIT' => 'Citycall',
        '1C'  => 'Chuwi',
        'L8'  => 'Clarmin',
        '25'  => 'Claresta',
        '1J'  => 'Cloud',
        'CD'  => 'Cloudfone',
        '6C'  => 'Cloudpad',
        'C0'  => 'Clout',
        'CN'  => 'CnM',
        'CY'  => 'Coby Kyros',
        'XC'  => 'Cobalt',
        'C6'  => 'Comio',
        'CL'  => 'Compal',
        'CQ'  => 'Compaq',
        'C7'  => 'ComTrade Tesla',
        '7Z'  => 'COMPUMAX',
        'C8'  => 'Concord',
        'CC'  => 'ConCorde',
        'C5'  => 'Condor',
        'C5M' => 'C5 Mobile',
        '4C'  => 'Conquest',
        '3C'  => 'Contixo',
        '8C'  => 'Connex',
        '53'  => 'Connectce',
        '9C'  => 'Colors',
        'CO'  => 'Coolpad',
        'COO' => 'Coopers',
        '4R'  => 'CORN',
        '1O'  => 'Cosmote',
        'CW'  => 'Cowon',
        '75'  => 'Covia',
        'QG'  => 'COYOTE',
        'YW'  => 'ClearPHONE',
        '33'  => 'Clementoni',
        'CR'  => 'CreNova',
        'CX'  => 'Crescent',
        'CK'  => 'Cricket',
        'CM'  => 'Crius Mea',
        '0C'  => 'Crony',
        'C1'  => 'Crosscall',
        '4W'  => 'Crown',
        'CTR' => 'Ctroniq',
        'CU'  => 'Cube',
        'CB'  => 'CUBOT',
        'CV'  => 'CVTE',
        'CWO' => 'Cwowdefu',
        'C4'  => 'Cyrus',
        'D5'  => 'Daewoo',
        'DA'  => 'Danew',
        'DAN' => 'Dany',
        'DT'  => 'Datang',
        'D7'  => 'Datawind',
        '7D'  => 'Datamini',
        '6D'  => 'Datalogic',
        'D1'  => 'Datsun',
        'DZ'  => 'Dazen',
        'DAS' => 'DASS',
        'DB'  => 'Dbtel',
        'DBP' => 'DbPhone',
        'DCO' => 'Dcode',
        'DL'  => 'Dell',
        'DL0' => 'DL',
        'DE'  => 'Denver',
        'DS'  => 'Desay',
        'DSI' => 'DSIC',
        'DW'  => 'DeWalt',
        'DX'  => 'DEXP',
        'DEY' => 'DEYI',
        'DEN' => 'Denali',
        'DEA' => 'DEALDIG',
        '8D'  => 'DF',
        'DGT' => 'DGTEC',
        'DG'  => 'Dialog',
        'DI'  => 'Dicam',
        'D4'  => 'Digi',
        'D3'  => 'Digicel',
        'DDG' => 'Digidragon',
        'DH'  => 'Digihome',
        'DD'  => 'Digiland',
        'DIG' => 'Digit4G',
        'DIC' => 'DIGICOM',
        'Q0'  => 'DIGIFORS',
        'DQ'  => 'DISH',
        '9D'  => 'Ditecma',
        'D2'  => 'Digma',
        '1D'  => 'Diva',
        'DIV' => 'DiverMax',
        'D6'  => 'Divisat',
        'X6'  => 'DIXON',
        'DIM' => 'DIMO',
        '5D'  => 'DING DING',
        'DIN' => 'Dinax',
        'DM'  => 'DMM',
        'DN'  => 'DNS',
        'DC'  => 'DoCoMo',
        'DF'  => 'Doffler',
        'D9'  => 'Dolamee',
        'DO'  => 'Doogee',
        'D0'  => 'Doopro',
        'DV'  => 'Doov',
        'DOM' => 'Dom.ru',
        'DP'  => 'Dopod',
        'JQ'  => 'Doppio',
        'DR'  => 'Doro',
        'ZD'  => 'DORLAND',
        'D8'  => 'Droxio',
        'DJ'  => 'Dragon Touch',
        'DRA' => 'DRAGON',
        'DY'  => 'Dreamgate',
        'DRE' => 'DreamTab',
        'DR1' => 'DreamStar',
        'DTA' => 'Dtac',
        'DU'  => 'Dune HD',
        'UD'  => 'DUNNS Mobile',
        'DUU' => 'Duubee',
        'DTE' => 'D-Tech',
        'DLI' => 'D-Link',
        'ENO' => 'eNOVA',
        'IN2' => 'iNOVA',
        'INH' => 'Inhon',
        'EB'  => 'E-Boda',
        'EJ'  => 'Engel',
        'ENA' => 'ENACOM',
        'ENI' => 'ENIE',
        '2E'  => 'E-Ceros',
        'E8'  => 'E-tel',
        'EP'  => 'Easypix',
        'EQ'  => 'Eagle',
        'EA'  => 'EBEST',
        'YC'  => 'EBEN',
        'E4'  => 'Echo Mobiles',
        'EQ1' => 'Equator',
        'ES'  => 'ECS',
        '35'  => 'ECON',
        'ECC' => 'ECOO',
        'ZZ'  => 'ecom',
        'E6'  => 'EE',
        'GW'  => 'EGL',
        'EFT' => 'EFT',
        'EK'  => 'EKO',
        'EY'  => 'Einstein',
        'EM'  => 'Eks Mobility',
        'UE'  => 'Ematic',
        'EMR' => 'Emporia',
        '4K'  => 'EKT',
        '7E'  => 'ELARI',
        '03'  => 'Electroneum',
        'Z8'  => 'ELECTRONIA',
        'EL1' => 'Elecson',
        'L0'  => 'Element',
        'EG'  => 'Elenberg',
        'EL'  => 'Elephone',
        'JE'  => 'Elekta',
        'ELE' => 'Elevate',
        '4E'  => 'Eltex',
        'ELM' => 'Elong Mobile',
        'ED'  => 'Energizer',
        'E1'  => 'Energy Sistem',
        '3E'  => 'Enot',
        'ENT' => 'Entity',
        'ENV' => 'Envizen',
        '8E'  => 'Epik One',
        'XP'  => 'Epson',
        'EPH' => 'Ephone',
        'E7'  => 'Ergo',
        'EC'  => 'Ericsson',
        '05'  => 'Erisson',
        'ER'  => 'Ericy',
        'EE'  => 'Essential',
        'E2'  => 'Essentielb',
        '6E'  => 'eSTAR',
        'EN'  => 'Eton',
        'ET'  => 'eTouch',
        '1E'  => 'Etuline',
        'EU'  => 'Eurostar',
        '4J'  => 'Eurocase',
        'E9'  => 'Evercoss',
        'EV'  => 'Evertek',
        'EVE' => 'Everest',
        'EV1' => 'Everex',
        'E3'  => 'Evolio',
        'EO'  => 'Evolveo',
        '0Q'  => 'Evoo',
        '5U'  => 'EVPAD',
        'E0'  => 'EvroMedia',
        'XE'  => 'ExMobile',
        '4Z'  => 'Exmart',
        'EH'  => 'EXO',
        'EX'  => 'Explay',
        'E5'  => 'Extrem',
        'EF'  => 'EXCEED',
        'QE'  => 'EWIS',
        'EI'  => 'Ezio',
        'EZ'  => 'Ezze',
        'UF'  => 'EYU',
        'UE1' => 'UE',
        '5F'  => 'F150',
        'F6'  => 'Facebook',
        'FAC' => 'Facetel',
        'FA1' => 'Facime',
        'FA'  => 'Fairphone',
        'FM'  => 'Famoco',
        'FAM' => 'Famous',
        '17'  => 'FarEasTone',
        '9R'  => 'FaRao Pro',
        'FAR' => 'Farassoo',
        'FB'  => 'Fantec',
        'FE'  => 'Fengxiang',
        'F7'  => 'Fero',
        '67'  => 'FEONAL',
        'FI'  => 'FiGO',
        'J9'  => 'FiGi',
        'FIG' => 'Figgers',
        'F9'  => 'FiiO',
        'F1'  => 'FinePower',
        'FX'  => 'Finlux',
        'F3'  => 'FireFly Mobile',
        'F8'  => 'FISE',
        'FIL' => 'FILIX',
        'FL'  => 'Fly',
        'QC'  => 'FLYCAT',
        'FLU' => 'Fluo',
        'FN'  => 'FNB',
        'FD'  => 'Fondi',
        '0F'  => 'Fourel',
        '44'  => 'Four Mobile',
        'F0'  => 'Fonos',
        'F2'  => 'FORME',
        'F5'  => 'Formuler',
        'FR'  => 'Forstar',
        'RF'  => 'Fortis',
        'FO'  => 'Foxconn',
        'FOD' => 'FoxxD',
        'FJ'  => 'FOODO',
        'FT'  => 'Freetel',
        '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',
        'GTM' => 'GTMEDIA',
        '0G'  => 'GFive',
        'GM'  => 'Garmin-Asus',
        'GA'  => 'Gateway',
        '99'  => 'Galaxy Innovations',
        'GAZ' => 'Gazer',
        'GEA' => 'Geanee',
        'GD'  => 'Gemini',
        'GN'  => 'General Mobile',
        '2G'  => 'Genesis',
        'G2'  => 'GEOFOX',
        'GE'  => 'Geotel',
        'Q4'  => 'Geotex',
        'GEO' => 'GEOZON',
        'GER' => 'Gear Mobile',
        'GH'  => 'Ghia',
        '2C'  => 'Ghong',
        'GJ'  => 'Ghost',
        'GG'  => 'Gigabyte',
        'GS'  => 'Gigaset',
        'GZ'  => 'Ginzzu',
        '1G'  => 'Gini',
        'GI'  => 'Gionee',
        'GIR' => 'GIRASOLE',
        'G4'  => 'Globex',
        '38'  => 'GLONYX',
        'U6'  => 'Glofiish',
        'G7'  => 'GoGEN',
        'GC'  => 'GOCLEVER',
        '5G'  => 'Gocomma',
        'GB'  => 'Gol Mobile',
        'GL'  => 'Goly',
        'GOL' => 'GoldMaster',
        'GX'  => 'GLX',
        'G5'  => 'Gome',
        'G1'  => 'GoMobile',
        'GO'  => 'Google',
        'G0'  => 'Goophone',
        '6G'  => 'Gooweel',
        'GOO' => 'GOODTEL',
        '8G'  => 'Gplus',
        'GR'  => 'Gradiente',
        'GP'  => 'Grape',
        'G6'  => 'Gree',
        'GRA' => 'Great Asia',
        '3G'  => 'Greentel',
        'GF'  => 'Gretel',
        '82'  => 'Gresso',
        'GU'  => 'Grundig',
        'GV'  => 'Gtel',
        'CUO' => 'Guophone',
        'H13' => 'H133',
        '9Z'  => 'H96',
        'HF'  => 'Hafury',
        '9F'  => 'HAOVM',
        'HAQ' => 'HAOQIN',
        'HA'  => 'Haier',
        'XH'  => 'Haipai',
        'HAN' => 'Handheld',
        'HE'  => 'HannSpree',
        'HK'  => 'Hardkernel',
        'HAR' => 'Harper',
        'HA1' => 'Hartens',
        'HS'  => 'Hasee',
        '8H'  => 'Hamlet',
        'HAM' => 'Hammer',
        'H6'  => 'Helio',
        'HQ'  => 'HERO',
        'ZH'  => 'Hezire',
        'HEX' => 'HexaByte',
        'HEW' => 'HeadWolf',
        'HL'  => 'Hi-Level',
        '3H'  => 'Hi',
        'HIB' => 'Hiberg',
        'HIH' => 'HiHi',
        'HIK' => 'HiKing',
        'H2'  => 'Highscreen',
        'Q1'  => 'High Q',
        '1H'  => 'Hipstreet',
        'HI'  => 'Hisense',
        'HIP' => 'HIPER',
        'HC'  => 'Hitachi',
        'H8'  => 'Hitech',
        'W3'  => 'HiMax',
        '8X'  => 'Hi Nova',
        'HLL' => 'HLLO',
        '8W'  => 'HKPro',
        'H1'  => 'Hoffmann',
        'H0'  => 'Hometech',
        'HM'  => 'Homtom',
        'HZ'  => 'Hoozo',
        'H7'  => 'Horizon',
        '4H'  => 'Horizont',
        'HO'  => 'Hosin',
        'H3'  => 'Hotel',
        'HV'  => 'Hotwav',
        'U8'  => 'Hot Pepper',
        'JH'  => 'HOTREALS',
        'HW'  => 'How',
        'WH'  => 'Honeywell',
        'HP'  => 'HP',
        'HDC' => 'HDC',
        'HT'  => 'HTC',
        'QZ'  => 'Huagan',
        'HD'  => 'Huadoo',
        'HG'  => 'Huavi',
        'HU'  => 'Huawei',
        'HX'  => 'Humax',
        'HR'  => 'Hurricane',
        'H5'  => 'Huskee',
        'HUG' => 'Hugerock',
        'HY'  => 'Hyrican',
        'HN'  => 'Hyundai',
        '7H'  => 'Hyve',
        'HYT' => 'Hytera',
        'HYK' => 'Hykker',
        '3I'  => 'i-Cherry',
        'IJ'  => 'i-Joy',
        'IM'  => 'i-mate',
        'IO'  => 'i-mobile',
        'INN' => 'I-INN',
        'OF'  => 'iOutdoor',
        'IB'  => 'iBall',
        'IY'  => 'iBerry',
        '7I'  => 'iBrit',
        'I2'  => 'IconBIT',
        'IC'  => 'iDroid',
        '6Z'  => 'iData',
        'IG'  => 'iGet',
        'IH'  => 'iHunt',
        'IA'  => 'Ikea',
        'IYO' => 'iYou',
        '8I'  => 'IKU Mobile',
        '2K'  => 'IKI Mobile',
        'IK'  => 'iKoMo',
        '58'  => 'iKon',
        'I7'  => 'iLA',
        '2I'  => 'iLife',
        '1I'  => 'iMars',
        'IMI' => 'iMI',
        'U4'  => 'iMan',
        'IL'  => 'IMO Mobile',
        'IM1' => 'Imose',
        'I3'  => 'Impression',
        'FC'  => 'INCAR',
        '2H'  => 'Inch',
        '6I'  => 'Inco',
        'IW'  => 'iNew',
        'IF'  => 'Infinix',
        'INF' => 'Infiniton',
        'I0'  => 'InFocus',
        'IN1' => 'InFone',
        'II'  => 'Inkti',
        '81'  => 'InfoKit',
        'I5'  => 'InnJoo',
        '26'  => 'Innos',
        'IN'  => 'Innostream',
        'I4'  => 'Inoi',
        'INO' => 'iNo Mobile',
        'IQ'  => 'INQ',
        'QN'  => 'iQ&T',
        'IS'  => 'Insignia',
        'YI'  => 'INSYS',
        'IT'  => 'Intek',
        'INT' => 'Intel',
        'IX'  => 'Intex',
        'IV'  => 'Inverto',
        '32'  => 'Invens',
        '4I'  => 'Invin',
        'INA' => 'iNavi',
        'I1'  => 'iOcean',
        'IMU' => 'iMuz',
        'IP'  => 'iPro',
        'X9'  => 'iPEGTOP',
        '8Q'  => 'IQM',
        'Q8'  => 'IRA',
        'I6'  => 'Irbis',
        '5I'  => 'Iris',
        'IRE' => 'iReplace',
        'IR'  => 'iRola',
        'IU'  => 'iRulu',
        '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',
        'JA'  => 'JAY-Tech',
        'KJ'  => 'Jiake',
        'JD'  => 'Jedi',
        'J6'  => 'Jeka',
        'JF'  => 'JFone',
        'JI'  => 'Jiayu',
        'JG'  => 'Jinga',
        'JX'  => 'Jio',
        'VJ'  => 'Jivi',
        'JK'  => 'JKL',
        'JR1' => 'JREN',
        'JO'  => 'Jolla',
        'JP'  => 'Joy',
        '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',
        'KX'  => 'Kenxinda',
        'KEN' => 'Kenbo',
        'KZG' => 'KZG',
        'K1'  => 'Kiano',
        '5W'  => 'Kingbox',
        'KI'  => 'Kingsun',
        'KIS' => 'Kinstone',
        'KF'  => 'KINGZONE',
        'KIN' => 'Kingstar',
        '46'  => 'Kiowa',
        'KV'  => 'Kivi',
        '64'  => 'Kvant',
        '0K'  => 'Klipad',
        'KC'  => 'Kocaso',
        'KK'  => 'Kodak',
        'KG'  => 'Kogan',
        'KM'  => 'Komu',
        'KO'  => 'Konka',
        'KW'  => 'Konrow',
        'KB'  => 'Koobee',
        '7K'  => 'Koolnee',
        'K9'  => 'Kooper',
        'KP'  => 'KOPO',
        'KR'  => 'Koridy',
        'XK'  => 'Koslam',
        'K2'  => 'KRONO',
        'KE'  => 'Krüger&Matz',
        '5K'  => 'KREZ',
        'WK'  => 'KRIP',
        'KRA' => 'Kraft',
        'KH'  => 'KT-Tech',
        'Z6'  => 'KUBO',
        'K8'  => 'Kuliao',
        '8K'  => 'Kult',
        'KU'  => 'Kumai',
        '6K'  => 'Kurio',
        'KY'  => 'Kyocera',
        'KQ'  => 'Kyowon',
        '1K'  => 'Kzen',
        'LQ'  => 'LAIQ',
        'L6'  => 'Land Rover',
        'L2'  => 'Landvo',
        'LA'  => 'Lanix',
        'LA1' => 'Lanin',
        'LK'  => 'Lark',
        'Z3'  => 'Laurus',
        'LEC' => 'Lectrus',
        'LV'  => 'Lava',
        'LC'  => 'LCT',
        'L5'  => 'Leagoo',
        'U3'  => 'Leben',
        'LEB' => 'LeBest',
        'LD'  => 'Ledstar',
        'LEE' => 'Leelbox',
        'L1'  => 'LeEco',
        '4B'  => 'Leff',
        'LEG' => 'Legend',
        'L4'  => 'Lemhoov',
        'W9'  => 'LEMFO',
        'LN'  => 'Lenco',
        'LE'  => 'Lenovo',
        'LT'  => 'Leotec',
        'LP'  => 'Le Pan',
        'ZJ'  => 'Leke',
        'L7'  => 'Lephone',
        'LZ'  => 'Lesia',
        'L3'  => 'Lexand',
        'LX'  => 'Lexibook',
        'LG'  => 'LG',
        '39'  => 'Liberton',
        '5L'  => 'Linsar',
        'LIN' => 'Linsay',
        'LF'  => 'Lifemaxx',
        'LI'  => 'Lingwin',
        'LJ'  => 'L-Max',
        'LW'  => 'Linnex',
        'JJ'  => 'Listo',
        'LNM' => 'LNMBBS',
        'LO'  => 'Loewe',
        'YL'  => 'Loview',
        'LOV' => 'Lovme',
        '1L'  => 'Logic',
        'LH'  => 'Logic Instrument',
        'LM'  => 'Logicom',
        'GY'  => 'LOKMAT',
        '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',
        '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',
        '7M'  => 'Maxcom',
        '7M1' => 'Maxfone',
        'ZM'  => 'Maximus',
        '6X'  => 'Maxtron',
        '0D'  => 'MAXVI',
        'XZ'  => 'MAXX',
        'MW'  => 'Maxwest',
        'M0'  => 'Maze',
        'YM'  => 'Maze Speed',
        '87'  => 'Malata',
        '28'  => 'MBOX',
        'FK'  => 'MBI',
        '3D'  => 'MDC Store',
        '1Y'  => 'MDTV',
        '09'  => 'meanIT',
        'M3'  => 'Mecer',
        'M3M' => 'M3 Mobile',
        '0M'  => 'Mecool',
        'MC'  => 'Mediacom',
        'MK'  => 'MediaTek',
        'MD'  => 'Medion',
        'M2'  => 'MEEG',
        'MP'  => 'MegaFon',
        'X0'  => 'mPhone',
        '3M'  => 'Meitu',
        'M1'  => 'Meizu',
        '0E'  => 'Melrose',
        'MU'  => 'Memup',
        'ME'  => 'Metz',
        'MX'  => 'MEU',
        'MI'  => 'MicroMax',
        'MS'  => 'Microsoft',
        '6Q'  => 'Microtech',
        '1X'  => 'Minix',
        'OM'  => 'Mintt',
        'MIN' => 'Mint',
        'MO'  => 'Mio',
        'X7'  => 'Mione',
        'M7'  => 'Miray',
        '8M'  => 'Mito',
        'MT'  => 'Mitsubishi',
        '0Y'  => 'Mitsui',
        'M5'  => 'MIXC',
        '2D'  => 'MIVO',
        '1Z'  => 'MiXzo',
        'MIW' => 'MIWANG',
        'ML'  => 'MLLED',
        'LS'  => 'MLS',
        '5H'  => 'MMI',
        '4M'  => 'Mobicel',
        'M6'  => 'Mobiistar',
        'MOK' => 'Mobile Kingdom',
        'MH'  => 'Mobiola',
        'MB'  => 'Mobistel',
        'ID'  => 'MobiIoT',
        '6W'  => 'MobiWire',
        '9M'  => 'Mobo',
        'MOB' => 'Mobell',
        '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',
        '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',
        '08'  => 'Nabi',
        'N7'  => 'National',
        'NC'  => 'Navcity',
        '6N'  => 'Navitech',
        '7V'  => 'Navitel',
        'N3'  => 'Navon',
        '7R'  => 'NavRoad',
        'NAS' => 'NASCO',
        'NP'  => 'Naomi Phone',
        'NE'  => 'NEC',
        'NDP' => 'Nedaphone',
        '8N'  => 'Necnot',
        'NF'  => 'Neffos',
        '9X'  => 'Neo',
        'NEK' => 'NEKO',
        '1N'  => 'Neomi',
        '7Q'  => 'Neon IQ',
        '8F'  => 'Neolix',
        'NA'  => 'Netgear',
        'NEM' => 'Netmak',
        'NU'  => 'NeuImage',
        'NEU' => 'NeuTab',
        'NW'  => 'Newgen',
        'N9'  => 'Newland',
        '0N'  => 'Newman',
        'NS'  => 'NewsMy',
        'ND'  => 'Newsday',
        'HB'  => 'New Balance',
        'BRI' => 'New Bridge',
        'XB'  => 'NEXBOX',
        'NX'  => 'Nexian',
        '7X'  => 'Nexa',
        'N8'  => 'NEXON',
        'N2'  => 'Nextbit',
        'NT'  => 'NextBook',
        'NTT' => 'NTT West',
        '4N'  => 'NextTab',
        'NEX' => 'NEXT',
        'NJO' => 'nJoy',
        'NG'  => 'NGM',
        'NZ'  => 'NG Optics',
        'NZP' => 'NGpon',
        'NN'  => 'Nikon',
        'NI'  => 'Nintendo',
        'NIN' => 'NINETEC',
        'N5'  => 'NOA',
        'N1'  => 'Noain',
        'N6'  => 'Nobby',
        'NOV' => 'Novey',
        'NO1' => 'NOVO',
        '57'  => 'Nubia',
        'JN'  => 'NOBUX',
        'NB'  => 'Noblex',
        'OG'  => 'NOGA',
        'NK'  => 'Nokia',
        'NM'  => 'Nomi',
        '2N'  => 'Nomu',
        '6H'  => 'Noontec',
        'NR'  => 'Nordmende',
        '7N'  => 'NorthTech',
        'NOT' => 'Nothing Phone',
        '5N'  => 'Nos',
        'NO'  => 'Nous',
        'NQ'  => 'Novex',
        'NJ'  => 'NuAns',
        'NL'  => 'NUU Mobile',
        'N0'  => 'Nuvo',
        'NUV' => 'NuVision',
        'NV'  => 'Nvidia',
        'NY'  => 'NYX Mobile',
        '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',
        'OLT' => 'OLTO',
        'OJ'  => 'Ookee',
        'OD'  => 'Onda',
        'ON'  => 'OnePlus',
        'ONC' => 'OneClick',
        'ONL' => 'OneLern',
        'OAN' => 'Oangcc',
        'OX'  => 'Onix',
        '3O'  => 'ONYX BOOX',
        'O4'  => 'ONN',
        '9Q'  => 'Onkyo',
        '2O'  => 'OpelMobile',
        'OH'  => 'Openbox',
        '7Y'  => 'Obabox',
        'OP'  => 'OPPO',
        'OO'  => 'Opsson',
        'OPT' => 'Optoma',
        'OPH' => 'Ophone',
        'OR'  => 'Orange',
        'O5'  => 'Orbic',
        'Y6'  => 'Orbita',
        'ORB' => 'Orbsmart',
        'OS'  => 'Ordissimo',
        '8O'  => 'Orion',
        'OTT' => 'OTTO',
        'OK'  => 'Ouki',
        '0O'  => 'OINOM',
        'QK'  => 'OKWU',
        'QQ'  => 'OMIX',
        '56'  => 'OKSI',
        'OE'  => 'Oukitel',
        'OU'  => 'OUYA',
        'JB'  => 'OUJIA',
        'OV'  => 'Overmax',
        '30'  => 'Ovvi',
        'O2'  => 'Owwo',
        'OSC' => 'OSCAL',
        'OY'  => 'Oysters',
        'QF'  => 'OYSIN',
        'O6'  => 'Oyyu',
        'OZ'  => 'OzoneHD',
        'OLL' => 'Ollee',
        '7P'  => 'P-UP',
        'YP'  => 'Paladin',
        'PM'  => 'Palm',
        'PN'  => 'Panacom',
        'PA'  => 'Panasonic',
        'PT'  => 'Pantech',
        'PAN' => 'Pano',
        '94'  => 'Packard Bell',
        'H9'  => 'Parrot Mobile',
        'PAR' => 'Partner Mobile',
        'PAP' => 'PAPYRE',
        'PB'  => 'PCBOX',
        'PCS' => 'PC Smart',
        'PC'  => 'PCD',
        'PD'  => 'PCD Argentina',
        'PE'  => 'PEAQ',
        'PG'  => 'Pentagram',
        'PQ'  => 'Pendoo',
        '93'  => 'Perfeo',
        '8J'  => 'Pelitt',
        '1P'  => 'Phicomm',
        '4P'  => 'Philco',
        'PH'  => 'Philips',
        '5P'  => 'Phonemax',
        'PO'  => 'phoneOne',
        'PI'  => 'Pioneer',
        'PIC' => 'Pioneer Computers',
        'PJ'  => 'PiPO',
        '8P'  => 'Pixelphone',
        '9O'  => 'Pixela',
        'PX'  => 'Pixus',
        'QP'  => 'Pico',
        'PIR' => 'PIRANHA',
        'PIN' => 'PINE',
        '9P'  => 'Planet Computers',
        'PY'  => 'Ployer',
        'P4'  => 'Plum',
        'PLU' => 'PlusStyle',
        '22'  => 'Pluzz',
        'P8'  => 'PocketBook',
        '0P'  => 'POCO',
        'FH'  => 'Point Mobile',
        'PV'  => 'Point of View',
        'PL'  => 'Polaroid',
        'Q6'  => 'Polar',
        '97'  => 'PolarLine',
        'PP'  => 'PolyPad',
        'P5'  => 'Polytron',
        'P2'  => 'Pomp',
        'P0'  => 'Poppox',
        '0X'  => 'POPTEL',
        'PS'  => 'Positivo',
        '3P'  => 'Positivo BGH',
        '3F'  => 'Porsche',
        'P3'  => 'PPTV',
        'FP'  => 'Premio',
        'PR'  => 'Prestigio',
        'P9'  => 'Primepad',
        'PRM' => 'PRIME',
        '6P'  => 'Primux',
        '2P'  => 'Prixton',
        'PRI' => 'Pritom',
        'PF'  => 'PROFiLO',
        'P6'  => 'Proline',
        '5O'  => 'Prology',
        'P1'  => 'ProScan',
        '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',
        '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',
        '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',
        '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',
        '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',
        '4O'  => 'S2Tel',
        '89'  => 'Seatel',
        'SEW' => 'Sewoo',
        'Y7'  => 'Saiet',
        'X1'  => 'Safaricom',
        'SG'  => 'Sagem',
        '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',
        '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',
        '10'  => 'Simbans',
        '98'  => 'Simply',
        '52'  => 'Singtech',
        '31'  => 'Siragon',
        '83'  => 'Sirin Labs',
        '5Z'  => 'SK Broadband',
        'GK'  => 'SKG',
        'SW'  => 'Sky',
        'SK'  => 'Skyworth',
        'SKY' => 'Skyline',
        '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',
        'JR'  => 'Sylvania',
        'SYH' => 'SYH',
        '3Y'  => 'Smarty',
        'HH'  => 'Smooth Mobile',
        '1Q'  => 'Smotreshka',
        'SF'  => 'Softbank',
        '9L'  => 'SOLE',
        'JL'  => 'SOLO',
        'SOS' => 'SOSH',
        'SOD' => 'Soda',
        '16'  => 'Solone',
        'OI'  => 'Sonim',
        'SO'  => 'Sony',
        'SE'  => 'Sony Ericsson',
        'X2'  => 'Soundmax',
        '8S'  => 'Soyes',
        '77'  => 'SONOS',
        '68'  => 'Soho Style',
        'PK'  => 'Spark',
        'FS'  => 'SPC',
        '6S'  => 'Spectrum',
        '43'  => 'Spectralink',
        'SP'  => 'Spice',
        '84'  => 'Sprint',
        'QS'  => 'SQOOL',
        'S4'  => 'Star',
        'OL'  => 'Starlight',
        '18'  => 'Starmobile',
        '2S'  => 'Starway',
        '45'  => 'Starwind',
        'SB'  => 'STF Mobile',
        'S8'  => 'STK',
        'GQ'  => 'STG Telecom',
        'S2'  => 'Stonex',
        'ST'  => 'Storex',
        'STR' => 'Stream',
        '71'  => 'StrawBerry',
        '96'  => 'STRONG',
        '69'  => 'Stylo',
        '9S'  => 'Sugar',
        'SUR' => 'Surge',
        '06'  => 'Subor',
        'SZ'  => 'Sumvision',
        '0H'  => 'Sunstech',
        'S3'  => 'SunVan',
        '5S'  => 'Sunvell',
        '5Y'  => 'Sunny',
        'W8'  => 'SUNWIND',
        'SBX' => 'SuperBOX',
        'SU'  => 'SuperSonic',
        '79'  => 'SuperTab',
        'S5'  => 'Supra',
        'ZS'  => 'Suzuki',
        '2J'  => 'Sunmi',
        'SUN' => 'Sunmax',
        '0W'  => 'Swipe',
        'SWI' => 'Switel',
        'SS'  => 'SWISSMOBILITY',
        '1W'  => 'Swisstone',
        'W7'  => 'SWTV',
        'SSK' => 'SSKY',
        'SYC' => 'Syco',
        'SM'  => 'Symphony',
        '4S'  => 'Syrox',
        'TM'  => 'T-Mobile',
        'T96' => 'T96',
        'TK'  => 'Takara',
        '73'  => 'Tambo',
        '9N'  => 'Tanix',
        'U5'  => 'Taiga System',
        'TAL' => 'Talius',
        '7G'  => 'TAG Tech',
        'T5'  => 'TB Touch',
        'TC'  => 'TCL',
        'T0'  => 'TD Systems',
        'YY'  => 'TD Tech',
        'H4'  => 'Technicolor',
        'TEA' => 'TeachTouch',
        'Z5'  => 'Technika',
        'TX'  => 'TechniSat',
        'TT'  => 'TechnoTrend',
        'TP'  => 'TechPad',
        '9E'  => 'Techwood',
        '7F'  => 'Technopc',
        'T7'  => 'Teclast',
        'TB'  => 'Tecno Mobile',
        'TEC' => 'TecToy',
        '91'  => 'TEENO',
        '2L'  => 'Tele2',
        'TL'  => 'Telefunken',
        'TG'  => 'Telego',
        'T2'  => 'Telenor',
        'TE'  => 'Telit',
        '65'  => 'Telia',
        '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',
        'T9'  => 'Top House',
        'DK'  => 'Topelotek',
        '42'  => 'Topway',
        'TO'  => 'Toplux',
        'TOD' => 'TOPDON',
        'TOP' => 'TopDevice',
        '7T'  => 'Torex',
        'TOR' => 'Torque',
        '6O'  => 'TOSCIDO',
        'TO1' => 'Topsion',
        'TS'  => 'Toshiba',
        'T8'  => 'Touchmate',
        'TOU' => 'Touch Plus',
        '5R'  => 'Transpeed',
        'T6'  => 'TrekStor',
        'T3'  => 'Trevi',
        'TJ'  => 'Trifone',
        'Q5'  => 'Trident',
        '4T'  => 'Tronsmart',
        '11'  => 'True',
        'JT'  => 'True Slim',
        'J1'  => 'Trio',
        '5C'  => 'TTEC',
        'TTK' => 'TTK-TV',
        'TU'  => 'Tunisie Telecom',
        '1T'  => 'Turbo',
        'TR'  => 'Turbo-X',
        '5X'  => 'TurboPad',
        '5T'  => 'TurboKids',
        'UR'  => 'Turkcell',
        '4U'  => 'TuCEL',
        '2U'  => 'Türk Telekom',
        'TV'  => 'TVC',
        'TW'  => 'TWM',
        'Z1'  => 'TWZ',
        '6T'  => 'Twoe',
        '15'  => 'Tymes',
        'UC'  => 'U.S. Cellular',
        'UG'  => 'Ugoos',
        'U1'  => 'Uhans',
        'UH'  => 'Uhappy',
        'UL'  => 'Ulefone',
        'UA'  => 'Umax',
        'UM'  => 'UMIDIGI',
        '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',
        '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',
        'VAT' => 'VALTECH',
        'VB'  => 'VC',
        'VN'  => 'Venso',
        'VEN' => 'Venstar',
        'UV'  => 'Venturer',
        'VQ'  => 'Vega',
        'WC'  => 'VEON',
        '4V'  => 'Verico',
        'V4'  => 'Verizon',
        'VR'  => 'Vernee',
        'VX'  => 'Vertex',
        'VE'  => 'Vertu',
        'VL'  => 'Verykool',
        'QV'  => 'Verssed',
        'VER' => 'Versus',
        'V8'  => 'Vesta',
        'VT'  => 'Vestel',
        '48'  => 'Vexia',
        'V6'  => 'VGO TEL',
        'QJ'  => 'VDVD',
        'VIC' => 'Victurio',
        'VD'  => 'Videocon',
        'VW'  => 'Videoweb',
        'VS'  => 'ViewSonic',
        'V7'  => 'Vinga',
        'V3'  => 'Vinsoc',
        'XD'  => 'Vinabox',
        'FV'  => 'Vios',
        '0V'  => 'Vipro',
        'ZV'  => 'Virzo',
        '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',
        'VK'  => 'VK Mobile',
        'JM'  => 'v-mobile',
        'VHO' => 'V-HOPE',
        'VHM' => 'V-HOME',
        'VGE' => 'V-Gen',
        'V0'  => 'VKworld',
        'VM'  => 'Vodacom',
        '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',
        'VH'  => 'Vsmart',
        'V9'  => 'Vsun',
        'VU'  => 'Vulcan',
        '3V'  => 'VVETIME',
        'ZC'  => 'VUCATIMES',
        'VUE' => 'Vue Micro',
        'WA'  => 'Walton',
        'WAL' => 'Waltter',
        'WHI' => 'White Mobile',
        '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',
        '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',
        'XG'  => 'Xgody',
        'QX'  => 'XGIMI',
        'XL'  => 'Xiaolajiao',
        'XI'  => 'Xiaomi',
        'XW'  => 'Xiaodu',
        'XN'  => 'Xion',
        'XO'  => 'Xolo',
        'XR'  => 'Xoro',
        'XS'  => 'Xshitou',
        '4X'  => 'Xtouch',
        'X8'  => 'Xtratech',
        'XCR' => 'Xcruiser',
        'XCO' => 'XCOM',
        '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',
        'ZE'  => 'Zeemi',
        'WZ'  => 'Zeeker',
        'ZN'  => 'Zen',
        'ZK'  => 'Zenek',
        'ZL'  => 'Zentality',
        'ZF'  => 'Zfiner',
        'ZI'  => 'Zidoo',
        'FZ'  => 'ZIFRO',
        'ZX'  => 'Ziox',
        'ZIK' => 'ZIK',
        'ZIN' => 'Zinox',
        'ZO'  => 'Zonda',
        'ZW'  => 'Zonko',
        'ZP'  => 'Zopo',
        'ZOO' => 'ZoomSmart',
        'ZO1' => 'Zoom',
        'ZT'  => 'ZTE',
        'ZU'  => 'Zuum',
        'ZY'  => 'Zync',
        'ZR'  => 'Zyrex',
        'ZQ'  => 'ZYQ',
        'Z4'  => 'ZH&K',
        'OW'  => 'öwn',
        'WBF' => 'Webfleet',
        // legacy brands, might be removed in future versions
        'WB'  => 'Web TV',
        'XX'  => 'Unknown',
    ];

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

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

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

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

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

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

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

        return '';
    }

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

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

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

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

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

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

            if ($matches) {
                break;
            }
        }

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

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

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

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

        $this->model = '';

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

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

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

                if ($modelMatches) {
                    break;
                }
            }

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

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

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

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

        return $this->getResult();
    }

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

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

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

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

        return \trim($model);
    }

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

        return null;
    }

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

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

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

Without NordigenAPI credentials provided, integrations web route fails

Details:

cURL error 3: (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for /api/v2/token/new/

Occured here:

    /**

     * @throws GuzzleException

     */

    public function getFreshTokenData(): array

    {

        $requestBody = [

            'secret_id' => config('nordigen.secret_id'),

            'secret_key' => config('nordigen.secret_key'),

        ];



        $response = $this->httpClient->post(self::NEW_TOKEN_URI, [

            'json' => $requestBody,

        ]);



        return $this->decodedResponse($response);

    }

Without Exchange Rates API credentials provided TransactionsTableSeeder is failing

 GuzzleHttp\Exception\RequestException 

  cURL error 3:  (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for /exchangerates_data/2023-09-01?base=ZMW&symbols=PLN

  at vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php:211
    207▕
    208▕         // Create a connection exception if it was a specific error code.
    209▕         $error = isset($connectionErrors[$easy->errno])
    210▕             ? new ConnectException($message, $easy->request, null, $ctx)
  ➜ 211▕             : new RequestException($message, $easy->request, $easy->response, null, $ctx);
    212▕
    213▕         return P\Create::rejectionFor($error);
    214▕     }
    215▕

  1   vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php:158
      GuzzleHttp\Handler\CurlFactory::createRejection()

  2   vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php:110
      GuzzleHttp\Handler\CurlFactory::finishError()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.