abourget / gevent-socketio Goto Github PK
View Code? Open in Web Editor NEWOfficial repository for gevent-socketio
Home Page: http://readthedocs.org/docs/gevent-socketio/en/latest/
License: BSD 3-Clause "New" or "Revised" License
Official repository for gevent-socketio
Home Page: http://readthedocs.org/docs/gevent-socketio/en/latest/
License: BSD 3-Clause "New" or "Revised" License
If I run my server with n
worker, and I connect n+1
clients, emit_to_room
delivers the same message multiple times to every client.
Steps to reproduce:
n
workers.n+1
clients and make them join the same channelemit_to_room
This is the code that I'm using (please ignore my re-implementation of emit_to_room
there).
I would like for someone to confirm it's actually a bug and not just me. If it's actually a bug, I am ready submit a pull request.
The JS SocketIO server has the notion of backend stores -- an idea we should steal! E.g. here's a RedisStore example: http://www.ranu.com.ar/2011/11/redisstore-and-rooms-with-socketio.html
The idea is that you specify a store and then all emit(), broadcast, etc are pushed through it.
We could allow a Namespace
to specify a store, maybe? I'm not sure of the right place to do this. It looks like we may be able to simply swap out Socket.client_queue
and Socket.server_queue
to accomplish this?
Why _spawn_heartbeat
is never run on xhr-polling
, jsonp-polling
, htmlfile
transports? Sockets are never killed.
Currently connect isn't firing, is this the expected behavior?
Within my app I need to shutdown start/restart gracefully an embedded flask instance.
On the ThreadedWSGIServer counterpart I use shutdown() that works perfectly.
kill() seems to be the equivalent of shutdown() but on SocketIOServer but doesn't work and the serving thread stays in serve_forever
On a local development server, I've recently noticed that I get the following traceback if a socketio-enabled page is refreshed, closed, or I navigate somewhere else - basically, if the browser closes the underlying websocket connection:
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/gevent/greenlet.py", line 390, in run
result = self._run(*self.args, **self.kwargs)
File "/usr/src/gevent-socketio/socketio/transports.py", line 241, in send_into_ws
websocket.send(message)
File "/usr/src/gevent-websocket/geventwebsocket/websocket.py", line 350, in send
return self.send_frame(message, self.OPCODE_TEXT)
File "/usr/src/gevent-websocket/geventwebsocket/websocket.py", line 314, in send_frame
raise WebSocketError('The connection was closed')
WebSocketError: The connection was closed
<Greenlet at 0x467ff50: send_into_ws> failed with WebSocketError
Since gevent-websocket is probably correct in raising WebSocketErrror at line 314 of geventwebsocket/websocket.py (and may depend on that exception elsewhere), I think that gevent-socketio should catch that exception and gracefully dismiss it.
I have a feeling that this behaviour has only been in the last couple of weeks and wonder if it's related to recent commits. What seems a bit puzzling is that line 214 of socketio/transports.py is in the connect() method of WebsocketTransport. How can it be in the connect phase, if the socket has just been closed?
A good thing would also to update the current blog posts, to reflect the new APIs.
More people would be attracted to gevent-socketio if we showed more django support. Currently django-socketio relies on a very old version and is really no longer needed with our new API.
The socket.io client v0.9.8 released just yesterday is causing KeyError exceptions in gevent-socketio, when it disconnects/reconnects (eg. refresh a page, or even just leave a page that has a socketio connection).
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/django/core/handlers/base.py", line 114, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/talk2fs/talk2/core/views.py", line 42, in socketio_serve
}, request)
File "/usr/src/gevent-socketio/socketio/__init__.py", line 60, in socketio_manage
socket = environ['socketio']
KeyError: 'socketio'
Other than that, it seems to be working fine.
We aren't a legit async framework until we have this demo, the Internet says so.
I think it would be valuable to have some french documentation to help non-native english speakers get up and running quickly.
We don't have to translate all our docs but that would be great.
Thinking about using redis/zeromq for messaging dispatch instead of the broadcast mixin and pushing heavy processing to celery are things people need to know to do.
Hi!
I have implementation of the same app using gevent-socketio and node.js
I am trying to test my apps via JMeter. Refering to socket.io-spec I created a test plan, where I:
/socket.io/1/
, fetch session from response097468867931:15:10:websocket,xhr-multipart,htmlfile,jsonp-polling,flashsocket,xhr-polling
5:::{"name":"Auth","args":[{"userId":1,"key":"key"}]}
The problem is that this plan works with node.js, but does not work with gevent-socketio.
No matter what type of event I send I get 1::
in response and event is not triggered on server side. What's even more amazing is that sometimes it works and I get expected 1
result.
The same testplan works with node.js implementation. Both apps operate correctly in browser.
What might be the problem? At first I suspected that session is not created completely at the time of second request. I tried to make a delay of 3 seconds between requests, but this did not help.
Thank you!
How do I serve my Django site using uWSGI with the SocketIOServer? I tried using the following uwsgi config:
[uwsgi]
socket = 127.0.0.1:3031
master = true
processes = 2
env = DJANGO_SETTINGS_MODULE=demo.settings
module = run
and I have run.py
:
from gevent import monkey
from socketio.server import SocketIOServer
import django.core.handlers.wsgi
import os
import sys
monkey.patch_all()
PORT = 3031
os.environ['DJANGO_SETTINGS_MODULE'] = 'demo.settings'
application = django.core.handlers.wsgi.WSGIHandler()
SocketIOServer(('', PORT), application, namespace="socket.io").serve_forever()
but it just keeps on loading. Any ideas on how I might tell uWSGI to use SocketIOServer for serving my app?
We need better test coverage and add nose test runner
For example, when using MongoDB, it is very useful to have the native encoder encode the ObjectIds and datetime objects.
Those things are in packet.py .. it would be neat to be able to configure that on the namespace, or on the socketio_manage() call.
I am using gunicorn with a socketio.sgunicorn.GeventSocketIOWorker worker to run a django project.
When a websocket request arrives, the "socketio" key does not appear in the request.environ dictionary. What can be the reason for that?
The request.environ dictionary:
{'HTTP_COOKIE': 'csrftoken=ou3ptkud0jYBsJ9hKVmQfhQVcI2a9Xiu; sessionid=3cccb6f0e3a18dac0a4b53f9880eea3d', 'SERVER_SOFTWARE': 'gevent/0.13 Python/2.7', 'SCRIPT_NAME': u'', 'REQUEST_METHOD': 'GET', 'PATH_INFO': u'/socket.io/websocket', 'HTTP_ORIGIN': 'http://127.0.0.1:8000', 'SERVER_PROTOCOL': 'HTTP/1.0', 'QUERY_STRING': '', 'HTTP_SEC_WEBSOCKET_EXTENSIONS': 'x-webkit-deflate-frame', 'HTTP_CONNECTION': 'Upgrade', 'SERVER_NAME': 'localhost', 'REMOTE_ADDR': '127.0.0.1', 'wsgi.url_scheme': 'http', 'SERVER_PORT': '8000', 'HTTP_UPGRADE': 'websocket', 'wsgi.input': <gevent.pywsgi.Input object at 0x8da33ec>, 'HTTP_HOST': '127.0.0.1:8000', 'wsgi.multithread': False, 'HTTP_SEC_WEBSOCKET_VERSION': '13', 'wsgi.version': (1, 0), 'GATEWAY_INTERFACE': 'CGI/1.1', 'wsgi.run_once': False, 'wsgi.errors': <open file '', mode 'w' at 0xb74db0d0>, 'wsgi.multiprocess': False, 'HTTP_SEC_WEBSOCKET_KEY': 'PYVCqrOJSn1N90lN0igPuA==', 'CSRF_COOKIE': 'ou3ptkud0jYBsJ9hKVmQfhQVcI2a9Xiu'}
Right now, the mixin broadcasts to EVERYONE including myself. Maybe we want a function not to do that, or a function keyword argument to disable it or something.
We should have the live chat examples and live cpu graph deployed somewhere as a demo of what you can do with gevent-socketio.
yeah, we need that.
All the example directories should have the WebSocketsMain.swf embedded in the static directory and the HTML should be configured to point to it. Otherwise they will all fail under IE. We need a better mechanism to serve that file by the SocketIOServer automagically.
Hello:
The flashsocket transport seems to be broken. I tried running the sample code (chat.py ) with IE 8 and I saw a request for WebSocketMain.swf which is not available in the git repo. And it crashes with the following exception. What I dont understand is that why did it not try alternative transports even if FlashSocket is broken?
Thanks
192.168.121.1 - - [2012-06-28 00:54:49] "GET /socket.io.js HTTP/1.1" 200 95954 0.056004
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 438, in handle_one_response
self.run_application()
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 424, in run_application
self.result = self.application(self.environ, self.start_response)
File "./chat.py", line 58, in __call__
socketio_manage(environ, {'': ChatNamespace})
File "/usr/local/lib/python2.7/dist-packages/gevent_socketio-0.3.5_beta-py2.7.egg/socketio/__init__.py", line 60, in socketio_manage
socket = environ['socketio']
KeyError: 'socketio'
<SocketIOServer fileno=3 address=0.0.0.0:8080>: Failed to handle request:
request = GET /socket.io/static/flashsocket/WebSocketMain.swf HTTP/1.1 from ('192.168.121.1', 2565)
application = <__main__.Application object at 0xb6e9016c>
192.168.121.1 - - [2012-06-28 00:54:49] "GET /socket.io/static/flashsocket/WebSocketMain.swf HTTP/1.1" 500 161 0.048003
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/gevent/greenlet.py", line 390, in run
result = self._run(*self.args, **self.kwargs)
File "/usr/local/lib/python2.7/dist-packages/gevent_socketio-0.3.5_beta-py2.7.egg/socketio/server.py", line 65, in handle
handler.handle()
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 180, in handle
result = self.handle_one_request()
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 314, in handle_one_request
self.handle_one_response()
File "/usr/local/lib/python2.7/dist-packages/gevent_socketio-0.3.5_beta-py2.7.egg/socketio/handler.py", line 123, in handle_one_response
jobs = self.transport.connect(socket, request_method)
File "/usr/local/lib/python2.7/dist-packages/gevent_socketio-0.3.5_beta-py2.7.egg/socketio/transports.py", line 215, in connect
websocket = self.handler.environ['wsgi.websocket']
KeyError: 'wsgi.websocket'
<Greenlet at 0x94d489c: <bound method SocketIOServer.handle of <SocketIOServer at 0xb6e9008cL fileno=3 address=0.0.0.0:8080>>(<socket at 0x958ff4c fileno=[Errno 9] Bad file des, ('192.168.121.1', 2565))> failed with KeyError
Hi!
simple_chat
example is working with websockets in my Chrome browser.
But when I run it with xhr-polling it's not working. Every 10 seconds connection is restarted.
When submitting a nickname callback never runs.
PS: I restricted transports using transports=['xhr-polling']
argument to SocketIOServer
Test with the JavaScript lib, emitting an event with the last parameter being a function()...
The same thing should work from the server, and call a callback when we get back a message associated with a msg_id.
This implies fixing the msg_id things, and incrementing ack_msg_id thing.
Using this code http://paste.ofcode.org/37z2pnKVUDVWB3FQQLZZSF7 with the simple_pyramid_chat gives this traceback --> http://paste.ofcode.org/NkXFNqq5UxKcQvZY2BJC9k
It looks to me from running the simple chat example (and other applications) under Dozer (https://bitbucket.org/bbangert/dozer) that gevent-socketio is leaking a socketio.virtsocket.Socket and geventwebsocket.websocket.WebSocketHybi on every disconnect (along with a host of related/connected gevent/greenlet things).
The problem, as best as I can see, is that although kill() runs when the socket disconnects, the socket itself is never actually disposed of. From looking at the dozer output it seems like the problem may be that the environ dict is never deleted, so references remain to the websocket and socketio objects. I don't know if that's right (or even reasonable), or what to do to fix it.
We should have useful examples of how to do broadcast and room mixins utilizing messaging systems like redis and zeromq as well.
and pointers to the more complex examples in each module's doc.
Gevent-socketio is great, and well maintained !
It's possible and easy to be disconnected from the client side and well documented, but it's not possible (or I didn't found how ) from the server side to disconnect or kill the connection.
In the documentation, there's server.kill() but it doesn't do anything...for example the websocket is still connected and waiting for new data.
The main idea is to check if a user have the rights to be connected with socket.io in realtime or easily integrate gevent-socketio with a rights-based app. If so, the class SocketIOHandler can return a 200 OK, and if not, a 401 Unauthorized, like in the socket.io spec : https://github.com/LearnBoost/socket.io-spec#handshake
Thanks again for your implementation, it's working perfectly with Django :)
Copy and pasted this line into my dev.ini for my test app, pops a module import error for gunicorn.
worker_class = socketio.gunicorn.GeventSocketIOWorker
Noticed the imports above on the page are all for socketio.sgunicorn.GeventSocketIOWorker, changing the line to
worker_class = socketio.sgunicorn.GeventSocketIOWorker
fixed the import error.
http://readthedocs.org/docs/gevent-socketio/en/latest/server_integration.html#server-integration
I'm trying to use gevent-socketio with Django. When 'flashsocket' transport is used, all HttpOnly cookies are excluded from request cookies. Since Django sessions system stores an HttpOnly cookie sessionid
, user is never authenticated inside recv_connect
handler. Also some browsers (at least IE8) cause exceptions when the page is refreshing.
The first is raised immediately after query
"GET /socket.io/1//408631057146/?disconnect=1 HTTP/1.1" 500 53777 0.094426
(Here's another thing that makes me confused: the server fails silently with 500 status every time the page is refreshing, regardless of which transport is used. Is that normal?) Exception is:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/gevent/greenlet.py", line 390, in run
result = self._run(*self.args, **self.kwargs)
File "/usr/local/lib/python2.7/dist-packages/socketio/transports.py", line 242, in read_from_ws
message = websocket.receive()
File "/usr/local/lib/python2.7/dist-packages/geventwebsocket/websocket.py", line 93, in receive
raise WebSocketError("Received an invalid frame_type=%r" % frame_type)
WebSocketError: Received an invalid frame_type=255
<Greenlet at 0x9d3fa2c: read_from_ws> failed with WebSocketError
The second is raised after page loaded and recv_connect
occured:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/gevent/greenlet.py", line 390, in run
result = self._run(*self.args, **self.kwargs)
File "/usr/local/lib/python2.7/dist-packages/socketio/transports.py", line 232, in send_into_ws
websocket.send(message)
File "/usr/local/lib/python2.7/dist-packages/geventwebsocket/websocket.py", line 31, in send
self._write("\x00" + message + "\xFF")
File "/usr/local/lib/python2.7/dist-packages/gevent/socket.py", line 509, in sendall
data_sent += self.send(_get_memory(data, data_sent), flags)
File "/usr/local/lib/python2.7/dist-packages/gevent/socket.py", line 483, in send
return sock.send(data, flags)
error: [Errno 32] Broken pipe
<Greenlet at 0x9d3fa7c: send_into_ws> failed with error
Server code is pretty simple:
from django.http import HttpResponse
from socketio.namespace import BaseNamespace
from socketio import socketio_manage
class MyNamespace(BaseNamespace):
def recv_connect(self):
print 'User %s is now connected' %self.request.user
print self.request.COOKIES
def socketio(request):
socketio_manage(request.environ, {'/my_ns': MyNamespace}, request)
return HttpResponse()
The project runs on plain SocketIOServer
.
Versions of packages I use:
gevent – 0.13.7
gevent-websocket – 0.3.6
gevent-socketio – 0.3.5-rc2
socket.io-client – 0.9.9, also tried 0.9.1-1
The policy server when serving the policy file throws the following exception
'''python
: Invalid HTTP method: '\x00'
192.168.121.1 - - [2012-07-06 01:42:14] "" 400 0 2.997535
'''
We should at least document deployment procedures on heroku, openshift, and dotcloud
I'm wondering if it would be better to make server.sockets
an iterable of Socket
objects (rather than a dict of sessid: sockets) and move the current server.sockets
to server._sockets
. This would clean up some code:
def broadcast_msg(server, tweet):
for socket in server.sockets.values():
if '/tweets' in socket:
socket['/tweets'].emit('tweet', tweet)
becomes
def broadcast_msg(server, tweet):
for socket in server.sockets:
if '/tweets' in socket:
socket['/tweets'].emit('tweet', tweet)
The default port of flash socket policy server is set to 843. This is the original port that flash policy server operates but socket.io library defaults to 10843 according to their code. Further this requires that all unix programs are run as root (port < 1024). Is there any specific reason to use a different port than the socket.io client JS ?
Get the chat.py simple example working.
Here is the error from IE 8 browser - its triggers a JS exception
Webpage error details
User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MS-RTC LM 8; .NET4.0C; InfoPath.2; BOIE8;ENUS)
Timestamp: Fri, 6 Jul 2012 08:24:29 UTC
Message: 'window.G_vmlCanvasManager' is null or not an object
Line: 698
Char: 17
Code: 0
URI: http://localhost:8080/static/jquery.flot.js
I tried to change the namespace from "socket.io" to another string and the framework does not work. Any ideas where are all the places where I have to make changes? I thought it is only the constructor on the server side
SocketIOServer(('127.0.0.1', 8080), app,
namespace="newnamespace", policy_server=False).serve_forever()
And on the client
// socket.io specific code
var socket = io.connect("http://localhost:8080/newnamespace", { resource : "newnamespace"
});
For the pyramid community, as well as the Django community which were using django-socketio.
Hi, all.
When I try to open websocket from chrome/ff via nginx proxy it fails with key error you might look in traceback
127.0.0.1 - - [2012-05-08 03:39:23] "GET /socket.io/1/websocket/896374484054 HTTP/1.1" 500 403720 0.108159
Traceback (most recent call last):
File ".../eggs/gevent-0.13.7-py2.6-linux-x86_64.egg/gevent/greenlet.py", line 390, in run
result = self._run(_self.args, *_self.kwargs)
File ".../eggs/gevent_socketio-0.3.5_beta-py2.6.egg/socketio/server.py", line 65, in handle
handler.handle()
File ".../eggs/gevent-0.13.7-py2.6-linux-x86_64.egg/gevent/pywsgi.py", line 180, in handle
result = self.handle_one_request()
File ".../eggs/gevent-0.13.7-py2.6-linux-x86_64.egg/gevent/pywsgi.py", line 314, in handle_one_request
self.handle_one_response()
File ".../eggs/gevent_socketio-0.3.5_beta-py2.6.egg/socketio/handler.py", line 123, in handle_one_response
jobs = self.transport.connect(socket, request_method)
File ".../eggs/gevent_socketio-0.3.5_beta-py2.6.egg/socketio/transports.py", line 215, in connect
websocket = self.handler.environ['wsgi.websocket']
KeyError: 'wsgi.websocket'
But then I try to connect with application directly it's ok and works fine. As you see nginx proxy module uses http/1.1 connection with my app server.
We should have selenium tests that run against the testbed example that runs against all possible emit calls to verify everything is working for a release.
Hi,
I've already posted about this in the mailing list (https://groups.google.com/d/msg/gevent-socketio/T53jTYc9c2E/bkBoviqAiVsJ), but I don't see much activity there, so forgive me for cross posting in here.
When booting up under Django/Gunicorn, I get:
FAILED to start flash policy server: [Errno 48] Address already in use: ('0.0.0.0', 10843)
Looks like it's trying to start the policy server multiple times. This happens even when I set workers = 1.
This is my config/gunicorn
file:
#!python
from os import environ
from gevent import monkey
monkey.patch_all()
bind = "0.0.0.0:8000"
workers = 1 # fine for dev, you probably want to increase this number in production
worker_class = "socketio.sgunicorn.GeventSocketIOWorker"
def pre_fork(server, worker):
worker.policy_server = True
And I start the server with:
$ ./manage.py run_gunicorn -c config/gunicorn
Complete output is:
2012-08-08 12:09:26 [41273] [INFO] Starting gunicorn 0.14.3
2012-08-08 12:09:26 [41273] [INFO] Listening at: http://0.0.0.0:8000 (41273)
2012-08-08 12:09:26 [41273] [INFO] Using worker: socketio.sgunicorn.GeventSocketIOWorker
2012-08-08 12:09:27 [41274] [INFO] Booting worker with pid: 41274
Traceback (most recent call last):
File "/Users/flavio/working_copies/django-push-demo/lib/python2.7/site-packages/socketio/server.py", line 57, in start_accepting
self.policy_server.start()
File "/Users/flavio/working_copies/django-push-demo/lib/python2.7/site-packages/gevent/baseserver.py", line 145, in start
assert not self.started, '%s already started' % self.__class__.__name__
AssertionError: FlashPolicyServer already started
FAILED to start flash policy server.
Note that the server is up and running and works correctly.
I guess my questions are:
socketio.handler.SocketIOHandler.write_plain_result, called from write_smart/_do_handshake, does not send any of the access control headers, which causes cross-origin requests to fail. It needs to send the same set of access control headers that are set in BaseTransport.
Pyramid, Django, and Flask should be documented on how to integrate with gevent-socketio as well as how to run the servers in production, not just development.
I have a namespace like:
class SomeNamespace(BaseNamespace):
def recv_message(self, message):
self.request.session['foo'] = 1
self.emit('redirect')
and a socketio handler on client to redirect on event which goes to a view like:
def some_view(request):
assert request.session['foo'] == 1
but the test always fails, is there a way to let the session I set inside namespace handler to be retained on other views?
Performed a quick test: open my application in browser (Firefox 15). The recv_connect and my methods has been called successfully, but when I've closed the tab, no recv_disconnect has been triggered.
Is it expected behavior?
If not, I can test it in latest stable versions of popular browsers and add corresponding notes to docs.
Okay, so this may just be my error in some place, but I tried to run with Node socket.io server and it worked well using WS, while gevent-socketio falls back to xhr-polling, even though it responds with this after connecting:
0888503431506:15:10:websocket,xhr-multipart,htmlfile,jsonp-polling,flashsocket,xhr-polling
You can find my code in this gist.
I'm wondering about the naming of broadcast_event
in BroadcastMixin
. Would it make more sense to rename this to emit_broadcast
instead?
Also, I'm wondering if it'd be possible to have a similar callback / ack for broadcast_event
, or if there was a reason to not do that. If it allowed a callback then the API would be more in line, but perhaps there's a good reason it doesn't.
Currently, an individual socket can broadcast using the BroadcastMixin. But what if you want to spin up a greenlet -- independent of a particular connection -- and have it publish to all the sockets on the server? In my case I'm streaming some data from an API and want to send it to all the sockets. Here's what I'm doing:
def broadcast_event(server, ns_name, event, *args):
pkt = dict(type="event",
name=event,
args=args,
endpoint=ns_name)
for sessid, socket in server.sockets.iteritems():
socket.send_packet(pkt)
def send_stuff(server):
for thing in stream:
broadcast_event(server, '/myapp', 'echo', thing)
...
if __name__ == '__main__':
print 'Listening on port http://0.0.0.0:8080 and on port 10843 (flash policy server)'
server = SocketIOServer(('0.0.0.0', 8080), Application(),
resource="socket.io", policy_server=True,
policy_listener=('0.0.0.0', 10843))
gevent.spawn(send_things, server)
server.serve_forever()
Would this broadcast pattern be valuable to include as a method on the SocketIOServer class?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.