Giter VIP home page Giter VIP logo

varbhat / exatorrent Goto Github PK

View Code? Open in Web Editor NEW
1.9K 12.0 97.0 1.83 MB

Easy to Use Torrent Client. Can be hosted in Cloud. Files can be streamed in Browser/Media Player.

License: GNU General Public License v3.0

Dockerfile 0.65% Makefile 0.55% Go 53.68% JavaScript 0.46% Svelte 38.96% HTML 0.12% TypeScript 5.35% HCL 0.23%
torrent go bittorrent-client self-hosted golang bittorrent qbittorrent cloud svelte typescript

exatorrent's People

Contributors

dependabot[bot] avatar nlevee avatar testwill avatar varbhat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

exatorrent's Issues

websocket configuration with nginx

Hi, I am using exatorrent with nginx. The config looks like this:

server {
  server_name torrent.example.com;

  location / {
    proxy_pass http://localhost:8080;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
 }
}

While trying to log in, I get the following error: Firefox can’t establish a connection to the server at wss://torrent.example.com/api/socket.

Any idea how to configure this, in order to run it on the server?

About compiling with mingw in win10

  1. install MSYS2 (Select x86_64 in the wizard)
  2. install mingw64(All information refer to 使用 CLion + MSYS2 配置 C 语言编程环境)
    pacman-key --init
    pacman -Syu
    pacman -S mingw-w64-x86_64-cmake mingw-w64-x86_64-extra-cmake-modules
    pacman -S mingw-w64-x86_64-make
    pacman -S mingw-w64-x86_64-gdb
    pacman -S mingw-w64-x86_64-toolchain
    
  3. clone project:git clone https://github.com/ystyle/exatorrent/ (already setup make app-windows-amd64)
  4. compile
    cd ${exatorrent-path}
    make app-windows-amd64

image
image
image
image

It seems to be running normally

api docs

https://github.com/varbhat/exatorrent/blob/main/docs/usage.md are the backend api? (you know i really hate networking dependencies.. so )

cos i only tested the binary release, the build process forces me to use network.. so after reviewed the source of the web part.. noted that is build using Svelte front end compiler that pulls more and more depends..

if the api is core only i can made a more static pure web frond end, that can be used with proper's web servers avoiding fixed endpoints that depends of the domains..

Request: Add torrents by URL of torrent file

When magnet links are not an option, I'd like to paste the URL of the torrent itself into the WebUI instead of having to first download the file, and then uploading it.

If this is also available via API, that would offer a lot of nice possibilities for extensions from things like TamperMonkey

Dlna

Are there any plans to add support dlna?

BaseURL support

I would like to run exatorrent on domain.tld/exatorrent, however there seems to be no flag to set this. I would suppose this is something to add to the flag-based configuration as well.

Reverse Proxy: request origin not allowed by Upgrader.CheckOrigin

I'm trying to setup a reverse proxy, but getting this error:

[WARN] 2021/08/26 11:19:41 websocket: request origin not allowed by Upgrader.CheckOrigin
[INFO] 2021/08/26 11:22:41 User adminuser ([fd42:20cc:9ed:42::80]:8210) Authenticated

So it appears there's some Cross Origin checks or something that are failing. My session then gets unauthenticated, and my browser immediately reauths. The WebUI just gives me the "Disconnected" screen.

This is the request in the reverse proxy (403):

"GET /api/socket HTTP/1.1" 403

Here's my reverse proxy config:

server {
    server_name torrents.example.com;
    listen [::]:80;
    listen 80;
    listen [::]:443 ssl;
    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/torrents.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/torrents.example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    access_log /var/log/nginx/torrents.example.com-access.log;

    # To allow special characters in headers
    ignore_invalid_headers off;
    client_max_body_size 0;
    # To disable buffering
    proxy_buffering off;

    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }

    location / {
        proxy_pass http://192.0.2.1:5000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

integration with....

have you ever in roadmap to make it integrable with radarr lidarr readerr sonarr?

Why are .torrent file uploads limited to 20 MB?

Is there a technical reason, or is 20 MB just a reasonable (but arbitrary) upper limit for file size?
Is it possible for me to remove the 20 MB limit for my instance?

I have a 47 MB .torrent.

arm5l any chance build?

GOOS=linux GOARCH=arm GOARM=5

C:\Users\X\go\pkg\mod\github.com\anacrolix\[email protected]\status.go:9:2: undefined: mu
C:\Users\X\go\pkg\mod\github.com\anacrolix\[email protected]\status.go:10:8: undefined: mu
C:\Users\X\go\pkg\mod\github.com\anacrolix\[email protected]\status.go:11:20: undefined: libContextToSocket
# crawshaw.io/sqlite/sqlitex
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\buffer.go:38:8: undefined: sqlite.Conn
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\buffer.go:51:9: undefined: sqlite.Blob
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\buffer.go:56:22: undefined: sqlite.Conn
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\buffer.go:61:26: undefined: sqlite.Conn
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\exec.go:73:17: undefined: sqlite.Conn
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\exec.go:73:64: undefined: sqlite.Stmt
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\exec.go:91:26: undefined: sqlite.Conn
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\exec.go:91:73: undefined: sqlite.Stmt
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\exec.go:110:17: undefined: sqlite.Stmt
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\exec.go:176:23: undefined: sqlite.Conn
C:\Users\X\go\pkg\mod\crawshaw.io\[email protected]\sqlitex\exec.go:176:23: too many errors

Apache reverse proxy header error when signing in

I'm trying to set up a reverse proxy to point to http://localhost:5001 however, I can't find a guide for it. My current proxy configuration is this:

<VirtualHost *:80>
        ServerName the.domain.tld

        ProxyPass / http://localhost:5001/
        ProxyPassReverse / http://localhost:5001/
        ProxyPass /api/socket http://localhost:5001/api/socket/
        ProxyPassReverse /api/socket http://localhost:5001/api/socket/
        
        ProxyPreserveHost On
        ProxyAddHeaders On
        RequestHeader set X-Forwarded-Proto "http"
</VirtualHost>

However, this causes the following error when attempting to sign in:

[INFO] 2021/09/28 05:08:58 User testuser (127.0.0.1:42484) Authenticated
[WARN] 2021/09/28 05:08:58 websocket: the client is not using the websocket protocol: 'upgrade' token not found in 'Connection' header

If someone is familiar with this, please guide me if possible. Thank you.

EDIT: I tried adding the header and now my config looks like this:

<VirtualHost *:80>
        ServerName the.domain.tld

        ProxyPass / http://localhost:5001/
        ProxyPassReverse / http://localhost:5001/
        ProxyPass /api/socket http://localhost:5001/api/socket/
        ProxyPassReverse /api/socket http://localhost:5001/api/socket/

        RewriteEngine on

        RewriteCond %{HTTP:Upgrade} websocket [NC]
        RewriteCond %{HTTP:Connection} upgrade [NC]
        RewriteRule /(.*) "ws://localhost:5001/$1" [P,L]

        ProxyPreserveHost On
        ProxyAddHeaders On
        RequestHeader set X-Forwarded-Proto "http"
</VirtualHost>

Now, it doesn't show the error anymore. However, I'm still stuck at the sign-in screen with this console spam:

[INFO] 2021/09/28 05:22:17 User testuser (127.0.0.1:59122) Authenticated
[INFO] 2021/09/28 05:22:18 User testuser (127.0.0.1:59492) Authenticated
[INFO] 2021/09/28 05:22:19 User testuser (127.0.0.1:59492) Authenticated
[INFO] 2021/09/28 05:22:21 User testuser (127.0.0.1:59492) Authenticated
[INFO] 2021/09/28 05:22:25 User testuser (127.0.0.1:59492) Authenticated
[INFO] 2021/09/28 05:22:27 User testuser (127.0.0.1:59492) Authenticated
[INFO] 2021/09/28 05:22:31 User testuser (127.0.0.1:59492) Authenticated
[INFO] 2021/09/28 05:22:31 User testuser (127.0.0.1:59492) Authenticated
[INFO] 2021/09/28 05:22:33 User testuser (127.0.0.1:59492) Authenticated
[INFO] 2021/09/28 05:22:33 User testuser (127.0.0.1:59492) Authenticated
[INFO] 2021/09/28 05:22:33 User testuser (127.0.0.1:59492) Authenticated

The nginx reverse proxy config that I'm trying to replicate in apache2 is this:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    ssl_certificate /path/to/tls/tls.crt;
    ssl_certificate_key /path/to/tls/tls.key;
    
    server_name the.domain.tld;
    
    location / {
        proxy_pass http://localhost:5000; 
        # proxy_pass http://unix:/path/to/exatorrent/unixsocket;
    }

    location /api/socket {
        proxy_pass http://localhost:5000/api/socket;
        # proxy_pass http://unix:/path/to/exatorrent/unixsocket:/api/socket; 
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
    }
    
}

Cannot execute arm64 binary

I'm running Ubuntu for Arm on 20.04, and when I download the file and try to execute it, it gives arch error. I'm running this in a Multipass VM on my Apple Silicon, and I can reproduce it in a different ubuntu VM on parallels on the same machine.

root@swiz:/tmp# chmod +x exatorrent-linux-amd64 
root@swiz:/tmp# ./exatorrent-linux-amd64 
bash: ./exatorrent-linux-amd64: cannot execute binary file: Exec format error
root@swiz:/tmp# file ./exatorrent-linux-amd64 
./exatorrent-linux-amd64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=de0620aef7a1f8b7d9f7ab58fd1bee298cf66dd8, stripped

Generate random password instead of using insecure defaults

Note that Username and Password of Default User created on first run are adminuser and adminpassword respectively. You can change Password later but Username of Account can't be changed after creation. Refer Usage.

The password really shouldn't be hardcoded.

After adding a magnet link to the docker version, the system hangs

docker-compose.yaml

version: '3.1'

services:
  torrent:
    image: ghcr.io/varbhat/exatorrent:latest
    restart: always
    volumes:
      - ${HOME}/Downloads:/exa/exadir
    ports:
      - 5000:5000
      - 42069:42069
docker-compose up -d

operation:

  1. add a new admin user
  2. logout and login new user and disabled adminuser
  3. add magnet link

magnet link:

magnet:?xt=urn:btih:787b951c9635c58928260e02a01e2b5434d8bb13&tr=http://tracker.36dm.com:2710/announce

system info:

                   -`                    ystyle@Archlinux 
                  .o+`                   ---------------- 
                 `ooo/                   OS: Arch Linux x86_64 
                `+oooo:                  Host: XPS 13 7390 
               `+oooooo:                 Kernel: 5.13.12-arch1-1 
               -+oooooo+:                Uptime: 7 days, 4 hours, 18 mins 
             `/:-:++oooo+:               Packages: 1627 (pacman) 
            `/++++/+++++++:              Shell: zsh 5.8 
           `/++++++++++++++:             Resolution: 1920x1080 
          `/+++ooooooooooooo/`           DE: Plasma 5.22.4 
         ./ooosssso++osssssso+`          WM: KWin 
        .oossssso-````/ossssss+`         WM Theme: Breeze 
       -osssssso.      :ssssssso.        Theme: Breeze Dark [Plasma], Breeze [GTK2/3] 
      :osssssss/        osssso+++.       Icons: breeze-dark [Plasma], breeze-dark [GTK2/3] 
     /ossssssss/        +ssssooo/-       Terminal: terminator 
   `/ossssso+/:-        -:/+osssso+-     CPU: Intel i7-10710U (12) @ 4.700GHz 
  `+sso+:-`                 `.-/+oso:    GPU: Intel Comet Lake UHD Graphics 
 `++:.                           `-/+/   Memory: 7627MiB / 15695MiB 
 .`                                 `/
 ystyle@Archlinux ~/Downloads  id
uid=1000(ystyle) gid=1000(ystyle) groups=1000(ystyle),972(docker),998(wheel)

cpu: 200%(total 600%) Memory: 100% (16g ram and 20G swap)

Startup error in docker

Hi, running this is docker, i get the following log errors:

Address => :5000
Directory => exadir
[ERR ] 2021/09/03 01:52:25 Error Creating Directory
Address => :5000
Directory => exadir
[ERR ] 2021/09/03 01:52:32 Error Creating Directory

Is there some kind of user permission whic needs to be passed to the container iin an environment variable?

Port Change

How to pass $PORT variable instead of port 5000?

[Docker] Error Creating Directory

Address => :5000
Directory => exadir

[ERR ] 2021/08/25 21:20:56 Error Creating Directory

The user 1000 doesn't have write permission in my mounted volume. Would it be possible to add the option to change the uid/gid?

Web UI title keeps torrent name when navigating back to other pages

Great tool, thanks for building it. One small wrinkle, and it's not an important problem but I thought I'd mention it anyway.

When I navigate to a specific torrent in the Web UI the page title in my browser changes to the torrent name, which is great. But when I navigate back the page title stays the same.

Home page when I first open the Web UI;

Screen Shot 2021-08-26 at 7 35 39 pm

Torrent page when I navigate to the page for a specific torrent;

Screen Shot 2021-08-26 at 7 36 03 pm

Home page when I navigate back after viewing the torrent;

Screen Shot 2021-08-26 at 7 36 17 pm

Failed to deploy

LOG
-----> Building on the Heroku-20 stack
-----> Determining which buildpack to use for this app
-----> Go app detected
-----> Fetching jq... done
-----> Fetching stdlib.sh.v8... done
----->
Detected go modules via go.mod
----->
Detected Module Name: github.com/varbhat/exatorrent
----->
!! The go.mod file for this project does not specify a Go version
!!
!! Defaulting to go1.12.17
!!
!! For more details see: https://devcenter.heroku.com/articles/go-apps-with-modules#build-configuration
!!
-----> New Go Version, clearing old cache
-----> Installing go1.12.17
-----> Fetching go1.12.17.linux-amd64.tar.gz... done
-----> Determining packages to install

   Detected the following main packages to install:
   		github.com/varbhat/exatorrent

-----> Running: go install -v -tags heroku github.com/varbhat/exatorrent
build github.com/varbhat/exatorrent: cannot load crypto/ed25519: cannot find module providing package crypto/ed25519
! Push rejected, failed to compile Go app.
! Push failed

image

websocket: request origin not allowed by Upgrader.CheckOrigin

The error occurs when I use Nginx as a reverse proxy. It doesn't occur when accessing exatorrent directly.

The server is spammed with:

[INFO] 2022/02/28 02:56:24 User username (127.0.0.1:41581) Authenticated
[WARN] 2022/02/28 02:56:28 websocket: request origin not allowed by Upgrader.CheckOrigin

This is my Nginx subdomain config:

server {
    listen 81 ssl http2;

    server_name exa.****.com;

    location / {
        proxy_pass http://localhost:5000;
    }

    location /api/socket {
        proxy_pass http://localhost:5000/api/socket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
    }
}

[BUG] username with five or fewer characters fails silently

Creating an admin username at first start with 5 or fewer characters such as:
exatorrent -admin "12345" does not show any problems in the terminal, but does not allow to log in in the web interface. You just get "invalid credentials".

Download Speed Info

Hello.

I love using exatorrent. I hosted it on my Webdock server. It's running great.

And, could you add a feature where one can see the speed at which the torrent is being downloaded?

Thanks!

wget download link doesn't work

Nice work on your project. GH doesn't have a direct link to releases downloads, sadly.

wget https://github.com/varbhat/exatorrent/releases/download/latest/exatorrent-linux-amd64
--2021-08-25 15:44:10--  https://github.com/varbhat/exatorrent/releases/download/latest/exatorrent-linux-amd64
Resolving github.com (github.com)... 192.30.255.113
Connecting to github.com (github.com)|192.30.255.113|:443... connected.
HTTP request sent, awaiting response... 404 Not Found
2021-08-25 15:44:10 ERROR 404: Not Found.

FreeBSD Support

I would like to suggest including native FreeBSD binaries for future releases or documentation and Make commands to compile on FreeBSD.

Different folder per user

Hi,

it's possible to add a functionality to config a specific download folder for each user ?

Example :
image

image

Thanks.

DOCKER [ERR ] Error Creating Directory

Hi,
I just built exatorrent in docker container following your guide. However, I stumbled upon this issue in container logs as the app won't start.

Any ideas as to why I'm getting this issue? am I or your image in lack of proper permissions to create the directory?

Address => :5000
Directory => exadir
[ERR ] 2021/08/27 23:15:00 Error Creating Directory

Here is my compose:

version: '3.8'

services:
  exatorrent:
    container_name: exatorrent
    image: ghcr.io/varbhat/exatorrent:latest
    restart: unless-stopped
    ports:
      - '5000:5000'
      - '42069:42069'
      - '42069:42069/udp'
    environment:
      - PUID=1000
      - PGID=1000
      - UMASK=002
    volumes:
      - '/etc/timezone:/etc/timezone:ro'
      - '/etc/localtime:/etc/localtime:ro'
      - '/opt/appdata/exatorrent:/exa/exadir'
      - '/mnt:/mnt'

Consider goreleaser for releases

It would make releases much easier on the dev end, and would enable release binaries for basically any OS/arch combo which Go supports.

username or password size too small

I'm getting the following error:
Unable to add admin user to adminless exatorrent instance : username or password size too small

but the username length is 7 chars
and the password lenght is >15 chars

Panic invalid memory address error while using docker

❯ docker run -p 5000:5000 -p 42069:42069 -v /home/torrent/:/exa/exadir  ghcr.io/varbhat/exatorrent:latest

Address => :5000
Directory => exadir

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0xa21e74]

goroutine 1 [running]:
github.com/varbhat/exatorrent/internal/core.checkDir({0xb44806, 0x6})
        github.com/varbhat/exatorrent/internal/core/init.go:33 +0xb4
github.com/varbhat/exatorrent/internal/core.Initialize()
        github.com/varbhat/exatorrent/internal/core/init.go:92 +0x749
main.main()
        ./exatorrent.go:17 +0x2e

I'm running this on Ubuntu 20.04

Heroku

How to run this app on Heroku?

[Feature] Add support for moving torrents to a different directory when completed

It would be useful to be able to have torrents moved to a directory when they have finished downloading. For example, when added, torrents are saved to the directory "incomplete" and when finished they are moved to the directory "complete". It would probably also be prudent to check if a torrent exists in the complete folder when adding in case it has already been downloaded.

Request: Add unix socket path to `clientconfig.json`

I see that you can store the definitions for the webserver in this file, and it would be nice to configure the unix socket the same way. As I'd like to make a [email protected] file in order to allow multiple separeate sessions, this would allow me to do the config with jq in the specific client's config file instead of having to sed into the 'hardcoded' service file if I want to enable it.

Wrong version?

Latest release 0.0.4 is still returning 0.0.3 when issuing the - v flag

Running `./exatorrent -engc -torc` keeps client running

I'd like to create all configs in the exadir, have exa quit, and then edit the config manually. Running the two flags together will keep the client running instead of it quitting after writing the confs.

root@swiz:/tmp# /opt/exatorrent/exatorrent -engc -torc

Address => :5000
Directory => exadir

[INFO] 2021/08/28 11:52:23 Torrent Client Configuration is now loaded from  exadir/config/clientconfig.json
[INFO] 2021/08/28 11:52:23 Engine Configuration {DisableLocalCache:false OnlineCacheURL:https://itorrents.org/torrent/%s.torrent TrackerRefresh:60 TrackerListURLs:[https://ngosang.github.io/trackerslist/trackers_best.txt] DisAllowTrackersUser:false DisAllowTrackersCache:false GlobalSeedRatio:0 SRRefresh:150 DontRemoveCacheInfo:false LockbyDefault:false} is now loaded
[INFO] 2021/08/28 11:52:23 Torrent Client Created
[INFO] 2021/08/28 11:52:23 Starting server on :5000
[INFO] 2021/08/28 11:52:23 Loaded  20  trackers from  https://ngosang.github.io/trackerslist/trackers_best.txt
[INFO] 2021/08/28 11:52:23 Loaded  20  trackers in total , eliminating duplicates
[INFO] 2021/08/28 11:52:23 Added Loaded Trackers to Torrents

MIME type issue on startup of pre-built executable (0.1.2)

On Windows. Running exatorrent amd64 and browsing to localhost:5000 or 127.0.0.1:5000 leads to a blank page with the dev tools console error of

Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/plain". Strict MIME type checking is enforced for module scripts per HTML spec.

The issue is in all modern browsers. The response header of index.js is Content-Type: text/plain; charset=utf-8. Manually setting :5000 or 127.0.01:5000 with -addr did not help.

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.