Giter Club home page Giter Club logo

nchan.js's People

Contributors

disarticulate avatar slact avatar the-don-himself avatar xon 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nchan.js's Issues

Repeated messages dropped

OK, not sure if it nchan or nchan.js problem, but here it goes:

We are trying to migrate from Faye, and while our chat mostly works fine with nchan, there are several issues. I will describe one as it seems like something you would be able to reproduce

The problem: when chat users are in the same browser process, just different tabs, repeated messages are ignored sometimes.
After I was reported of this, I tried to reproduce and changed out chat backend code to send the message 50 times instead of one.

If I use Chrome + Safari pair, everything works just fine - every time I send a message, I receive it in every browser 50 times.
If I use several Chrome tabs in incognito mode, everything works fine, too.

if I use two tabs in one Chrome window, this is what happens - the "broken" tab will receive the message sent just once, while the good tab will receive it 50 times.

What it a "broken" tab?
The backend injects several channel URLs for the frontend, like this

<script type="text/javascript">var nchanUrls = (nchanUrls || []).concat(['https://dev.company.com//sub/channel/2']);</script>
<script type="text/javascript">var nchanUrls = (nchanUrls || []).concat(['https://dev.company.com//sub/channel/2/private/2']);</script>

and then this simple script listens to messages

Pubsub = {
  init: function () {
    self = this;
    self.online = false;
    for (var i = 0; i < nchanUrls.length; i++ ) {
      var nchanUrl = nchanUrls[i];
      var sub = new NchanSubscriber(nchanUrl, { subscriber: ['websocket', 'longpoll'], shared: true });
      sub.on('message', Pubsub.nchanMessage);
      sub.on('connect', function(evt) {
        self.online = true;
      });
      sub.on('disconnect', function(evt){
        self.online = false;
      });
      sub.start();
    }
  },

  nchanMessage: function(message, message_metadata) {
    // message is a string
    // message_metadata is a hash that may contain 'id' and 'content-type'
    message = JSON.parse(message);
    eval(message.data.eval);
  }
}

So I call a "good" tab a tab that opens exactly the same number of WS connections as the number of URLs passed from the backend.

A "broken" tab will have less connections open than the number of URLs

Some screenshots:
this is a good tab:
screen shot 2017-12-14 at 17 30 33

this is a "broken" tab (it has only one connection open, but 2 URLs were passed from the backend):
screen shot 2017-12-14 at 17 31 22

Another observation - usually, it will always be the same - one tab is broken, another one is good. Not that it randomly both good, both broken, one good and another one broken.

If I enable the reconnect feature, some times they will change sides (broken becomes good, and vice versa).

Same behaviour in both browser I've tested, Safari (9.1.3 (9537.86.7.8)) and Chrome (59.0.3071.115).

Shared connection causes delay and breaks in IE

When creating a new NchanSubscriber with the shared option set to true, the connection takes upwards of 20 seconds to establish. Additionally, it appears to not connect at all in IE11. With the shared option undefined, the connection is established immediately and works fine in IE11. I don't think I'm doing anything unusual, but here's some boiled down example code just in case...

let subscription = new NchanSubscriber('/sub/test', {
	subscriber: ['websocket', 'eventsource'],
	reconnect: 'session',
	shared: true //this is causing trouble. If left out, everything is fine.
});

subscription.on('connect', function(evt) {
	console.log('connect');
	//fired when first connected.
});

subscription.start();

Any idea what could be going on?

Cannot Run in Browser Worker

The hard-coded dependency on the window object throws errors when running this library in a browser worker where the Window is not defined. Specifically, line 81

"use strict"; 
function NchanSubscriber(url, opt) {
  if(this === window) {
    throw "use 'new NchanSubscriber(...)' to initialize";
  }

I think a simple fix would be to check whether window exists first

if (typeof window !== 'undefined' && this === window)

How to pass custom header (auth cookie) to the websocket creation?

My authentication requires a certain header. This seems to work fine with http but with websocket it's not inheriting the headerjar. In socket.io this seems to happen automatically. Is it advisable to use socket.io if we need custom headers? Would it be worth while to implement a socket.io subscriber type in order to get the headers?

By the way. Thank you!

Debugging connections issues

I'm trying to debug strange connections issues and I don't know what step to take next.

Here is all the info I have right now:

  1. overview: the app is a collaboration app, with one (or more) presenter and several viewers. Presenters and viewers are connected to nginx with nchan via websockets using NchanSubscriber.
    Presenters can send simple POST requests to the Rails app, Rails will publish the events via nchan to all connected viewers.

  2. There are several server configs (servers listening on different domains with their own SSL certs), all of them have the same nchan related nginx config

client_max_body_size 128M;

location ~ /sub/(.*)$ {
    nchan_subscriber;
    nchan_channel_id $1;
    #nchan_channel_group test;
    nchan_channel_events_channel_id $1;
    nchan_subscriber_first_message oldest;
    nchan_subscribe_request /upstream/sub;
    nchan_unsubscribe_request /upstream/unsub;
}

location = /upstream/unsub {
    proxy_pass http://main_server/ws/unsub;
    proxy_ignore_client_abort on;  #!!!important!!!!
    proxy_set_header X-Subscriber-Type $nchan_subscriber_type;
    proxy_set_header X-Channel-Id $nchan_channel_id;
    proxy_set_header X-Original-URI $request_uri;
}
location = /upstream/sub {
    proxy_pass http://main_server/ws/sub;
    proxy_set_header X-Subscriber-Type $nchan_subscriber_type;
    proxy_set_header X-Message-Id $nchan_message_id;
    proxy_set_header X-Channel-Id $nchan_channel_id;
    proxy_set_header X-Original-URI $request_uri;
}

And there is a single pub server, available only locally:

server {
  listen   10.0.0.90:80;
  server_name 10.0.0.90;

  access_log  /var/log/nginx/localhost.access.log;

  location ~ /pub/(.*)$ {
    nchan_publisher;
    nchan_channel_id $1;
    #nchan_channel_group test;
    #nchan_channel_events_channel_id $1;
    nchan_message_buffer_length 0;
    nchan_message_timeout 30s;
  }

  location ~ /channel_events/(.*)$ {
    #channel events subscriber location
    nchan_subscriber;
    nchan_channel_group meta; # "meta" is a SPECIAL channel group
    nchan_channel_id $1;
  }

  location /nchan_stub_status {
    nchan_stub_status;
  }

  location / {
    root   /var/www/nginx-default;
    index  index.html index.htm;
  }
}
  1. nginx -V
nginx version: nginx/1.10.1
built with OpenSSL 1.0.1f 6 Jan 2014
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-threads --with-http_addition_module --with-http_flv_module --with-http_geoip_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_mp4_module --with-http_random_index_module --with-http_secure_link_module --with-http_sub_module --with-http_xslt_module --with-mail --with-mail_ssl_module --with-stream --with-stream_ssl_module --add-module=/build/nginx/debian/modules/headers-more-nginx-module --add-module=/build/nginx/debian/modules/nginx-auth-pam --add-module=/build/nginx/debian/modules/nginx-cache-purge --add-module=/build/nginx/debian/modules/nginx-dav-ext-module --add-module=/build/nginx/debian/modules/nginx-development-kit --add-module=/build/nginx/debian/modules/nginx-echo --add-module=/build/nginx/debian/modules/ngx-fancyindex --add-module=/build/nginx/debian/modules/nchan --add-module=/build/nginx/debian/modules/nginx-lua --add-module=/build/nginx/debian/modules/nginx-upload-progress --add-module=/build/nginx/debian/modules/nginx-upstream-fair --add-module=/build/nginx/debian/modules/ngx_http_substitutions_filter_module

OK, to the problem itself.

Here are several logs from client side:

I, [2018-07-09T17:25:39.608787 #4071]  INFO -- : PAGE: First event after page (re)load
I, [2018-07-09T17:25:39.608825 #4071]  INFO -- : PAGE: Browser: Firefox 61.0 (Windows)
I, [2018-07-09T17:25:39.608877 #4071]  INFO -- : PAGE: UA: Mozilla/5.0 (Windows NT 10.0; rv:61.0) Gecko/20100101 Firefox/61.0
I, [2018-07-09T17:25:39.608903 #4071]  INFO -- : PAGE: Resolution: 1583x763
I, [2018-07-09T17:25:39.608925 #4071]  INFO -- : PAGE: Resize, mw: 1100px, md: true, fs: false
I, [2018-07-09T17:25:39.608947 #4071]  INFO -- : PAGE: Using NChan
I, [2018-07-09T17:25:39.608968 #4071]  INFO -- : PUBSUB: Connected
I, [2018-07-09T17:25:39.608989 #4071]  INFO -- : PUBSUB: Connected

and another example

I, [2018-07-09T17:28:14.835192 #25076]  INFO -- : PAGE: First event after page (re)load
I, [2018-07-09T17:28:14.835254 #25076]  INFO -- : PAGE: Browser: Safari 11.0 (iPhone)
I, [2018-07-09T17:28:14.835305 #25076]  INFO -- : PAGE: UA: Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1
I, [2018-07-09T17:28:14.835360 #25076]  INFO -- : PAGE: Resolution: 320x454
I, [2018-07-09T17:28:14.835408 #25076]  INFO -- : PAGE: Resize, mw: 622px, md: false, fs: false
I, [2018-07-09T17:28:14.835457 #25076]  INFO -- : PAGE: Using NChan
I, [2018-07-09T17:28:14.835505 #25076]  INFO -- : PAGE: Mobile device
I, [2018-07-09T17:28:14.835556 #25076]  INFO -- : AUTOPLAY: Not allowed
I, [2018-07-09T17:28:14.835608 #25076]  INFO -- : STREAMS: Set method to JWplayer
I, [2018-07-09T17:28:14.835667 #25076]  INFO -- : PUBSUB: Connected
I, [2018-07-09T17:28:14.835718 #25076]  INFO -- : PUBSUB: Connected

PUBSUB: Connected is emitted by pubsub.js

Pubsub = {
  init: function () {
    self = this;
    self.online = false;
    for (var i = 0; i < nchanUrls.length; i++ ) {
      var nchanUrl = nchanUrls[i];
      var sub = new NchanSubscriber(nchanUrl, { subscriber: ['websocket', 'longpoll'] });

      sub.on('message', Pubsub.nchanMessage);

      sub.on('connect', function(evt) {
        self.online = true;
        ajaxLog('PUBSUB: Connected');
      });

      sub.on('disconnect', function(code, text){
        self.online = false;
        if (!text) {
          var evt = code;
          code = evt.code;
          text = evt.reason;
        }
        ajaxLog('PUBSUB: Disconnected: ' + code + ' desc: ' + text);
      });

      // sub.on('error', function(evt, desc){
      //   ajaxLog('PUBSUB: Error: ' + evt + ' desc: '+ desc);
      // });

      sub.start();
    }
  },

  nchanMessage: function(message, message_metadata) {
    // message is a string
    // message_metadata is a hash that may contain 'id' and 'content-type'
    message = JSON.parse(message);
    eval(message.data.eval);
  }
}

So connect event was triggered, but NchanSubscriber has received no events that were sent to /pub endpoint

Looking at the nginx access.log I see a lot of lines with 499 response code:

212.0.0.226 - - [09/Jul/2018:17:29:35 +0000] "GET /sub/event/62728 HTTP/1.1" 499 11 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1"
212.0.0.226 - - [09/Jul/2018:17:29:35 +0000] "GET /sub/event/62728/private/682916 HTTP/1.1" 499 768 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1"
125.0.0.216 - - [09/Jul/2018:17:39:38 +0000] "GET /sub/event/62728 HTTP/1.1" 101 2 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
125.0.0.216 - - [09/Jul/2018:17:39:38 +0000] "GET /sub/event/62728/admin HTTP/1.1" 101 3720 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
194.0.0.145 - - [09/Jul/2018:17:46:44 +0000] "GET /sub/event/62728 HTTP/1.1" 499 12787 "-" "Mozilla/5.0 (Windows NT 10.0; rv:61.0) Gecko/20100101 Firefox/61.0"
212.0.0.226 - - [09/Jul/2018:17:49:59 +0000] "GET /sub/event/62728 HTTP/1.1" 101 3660 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1"
212.0.0.226 - - [09/Jul/2018:17:49:59 +0000] "GET /sub/event/62728/private/682916 HTTP/1.1" 101 2 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1"
184.0.0.122 - - [09/Jul/2018:17:52:32 +0000] "GET /sub/event/62728 HTTP/1.1" 499 12440 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15F79 [FBAN/FBIOS;FBAV/179.0.0.50.82;FBBV/116150041;FBDV/iPhone7,1;FBMD/iPhone;FBSN/iOS;FBSV/11.4;FBSS/3;FBCR/KPNNL;FBID/phone;FBLC/nl_NL;FBOP/5;FBRV/0]"
184.0.0.122 - - [09/Jul/2018:17:52:32 +0000] "GET /sub/event/62728/private/684856 HTTP/1.1" 499 1546 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15F79 [FBAN/FBIOS;FBAV/179.0.0.50.82;FBBV/116150041;FBDV/iPhone7,1;FBMD/iPhone;FBSN/iOS;FBSV/11.4;FBSS/3;FBCR/KPNNL;FBID/phone;FBLC/nl_NL;FBOP/5;FBRV/0]"
194.0.0.145 - - [09/Jul/2018:17:58:09 +0000] "GET /sub/event/62728/private/674743 HTTP/1.1" 499 1590 "-" "Mozilla/5.0 (Windows NT 10.0; rv:61.0) Gecko/20100101 Firefox/61.0"
212.0.0.226 - - [09/Jul/2018:18:14:51 +0000] "GET /sub/event/62728 HTTP/1.1" 499 17823 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1"
194.0.0.145 - - [09/Jul/2018:18:15:01 +0000] "GET /sub/event/62728 HTTP/1.1" 499 23055 "-" "Mozilla/5.0 (Windows NT 10.0; rv:61.0) Gecko/20100101 Firefox/61.0"
185.0.0.148 - - [09/Jul/2018:18:18:29 +0000] "GET /sub/event/62728 HTTP/1.1" 101 34975 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
185.0.0.148 - - [09/Jul/2018:18:18:29 +0000] "GET /sub/event/62728/admin HTTP/1.1" 101 1312607 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
185.0.0.148 - - [09/Jul/2018:18:18:29 +0000] "GET /sub/event/62728/private/684815 HTTP/1.1" 101 2 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
212.0.0.226 - - [09/Jul/2018:18:33:50 +0000] "GET /sub/event/62728/private/682916 HTTP/1.1" 499 738 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1"
212.0.0.226 - - [09/Jul/2018:18:33:54 +0000] "GET /sub/event/62728/private/682916 HTTP/1.1" 499 738 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1"
212.0.0.226 - - [09/Jul/2018:18:34:06 +0000] "GET /sub/event/62728 HTTP/1.1" 499 4351 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1"
194.0.0.145 - - [09/Jul/2018:18:34:16 +0000] "GET /sub/event/62728 HTTP/1.1" 499 4351 "-" "Mozilla/5.0 (Windows NT 10.0; rv:61.0) Gecko/20100101 Firefox/61.0"

So, long story short: NchanSubscriber says we are connected, but won't receive anything from the server.

The questions I have:

  1. it is a correct config when the pub server is a separate server that listen local IP only? And there is a number of sub locations in different servers
  2. Is there a way to track connection errors within NchanSubscriber?
  3. Is there a way to make NchanSubscriber reconnect when connection is lost?

Error while using the NPM package

Hi,

I'm getting this error when using the NPM package:

(node:12764) UnhandledPromiseRejectionWarning: TypeError: global.addEventListener is not a function
    at new NchanSubscriber (C:\Users\afons\Documents\Projetos\Bots\bot_radioafonsosantos_status\node_modules\nchan\NchanSubscriber.js:353:12)
    at Client.bot.on (C:\Users\afons\Documents\Projetos\Bots\bot_radioafonsosantos_status\index.js:10:13)
    at Client.emit (events.js:203:15)
    at WebSocketConnection.triggerReady (C:\Users\afons\Documents\Projetos\Bots\bot_radioafonsosantos_status\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:125:17)
    at WebSocketConnection.checkIfReady (C:\Users\afons\Documents\Projetos\Bots\bot_radioafonsosantos_status\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:141:61)
    at GuildCreateHandler.handle (C:\Users\afons\Documents\Projetos\Bots\bot_radioafonsosantos_status\node_modules\discord.js\src\client\websocket\packets\handlers\GuildCreate.js:13:31)
    at WebSocketPacketManager.handle (C:\Users\afons\Documents\Projetos\Bots\bot_radioafonsosantos_status\node_modules\discord.js\src\client\websocket\packets\WebSocketPacketManager.js:105:65)
    at WebSocketConnection.onPacket (C:\Users\afons\Documents\Projetos\Bots\bot_radioafonsosantos_status\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:333:35)
    at WebSocketConnection.onMessage (C:\Users\afons\Documents\Projetos\Bots\bot_radioafonsosantos_status\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:296:17)
    at WebSocket.onMessage (C:\Users\afons\Documents\Projetos\Bots\bot_radioafonsosantos_status\node_modules\ws\lib\event-target.js:120:16)
(node:12764) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:12764) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

May I get some support on this?

Thanks!

Message repetition

Greetings!

I initialise nChanSubscriber and listen for messages for a while and everything is OK. But after updating the page I receive all these messages again (no matter that in LocalStorage there is lastMessageId).

Here is my code:

    const nchan = new NchanSubscriber(nChanUrl, {
        subscriber: 'longpoll',
        reconnect: 'persist',
        shared: true
    });

What should I change in order to get rid of this repetition?

There should be an option for EventSource withCredentials (keyword CORS)

Hi, thanks for the great module and the accompanying JS library.

Right now it is not possible to initiate an EventSource connection with the withCredentials: true parameter.

The line 673 looks like this

this.listener = new EventSource(url);

Since the CORS intent must be indicated in the constructor and not later, it must be solved on this line.

this.listener = new EventSource(url, { withCredentials: true });

Users would probably want to have a choice, so maybe pass it through the opt array?

Thank you.

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.