Code Monkey home page Code Monkey logo

skynet's Introduction

skynet logo

Skynet is a multi-user Lua framework supporting the actor model, often used in games.

It is heavily used in the Chinese game industry, but is also now spreading to other industries, and to English-centric developers. To visit related sites, visit the Chinese pages using something like Google or Deepl translate.

The community is friendly and almost all contributors can speak English, so English speakers are welcome to ask questions in Discussion, or sumbit issues in English.

Build

For Linux, install autoconf first for jemalloc:

git clone https://github.com/cloudwu/skynet.git
cd skynet
make 'PLATFORM'  # PLATFORM can be linux, macosx, freebsd now

Or:

export PLAT=linux
make

For FreeBSD , use gmake instead of make.

Test

Run these in different consoles:

./skynet examples/config	# Launch first skynet node  (Gate server) and a skynet-master (see config for standalone option)
./3rd/lua/lua examples/client.lua 	# Launch a client, and try to input hello.

About Lua version

Skynet now uses a modified version of lua 5.4.6 ( https://github.com/ejoy/lua/tree/skynet54 ) for multiple lua states.

Official Lua versions can also be used as long as the Makefile is edited.

How To Use

skynet's People

Contributors

cloudfreexiao avatar cloudwu avatar cofyc avatar colinsusie avatar davidxifeng avatar dpull avatar gitfancode avatar great90 avatar hanxi avatar hongling0 avatar hqwrong avatar huahua132 avatar jexocn avatar jietrancender avatar kezhuw avatar learno avatar lvzixun avatar mrvon avatar niuys avatar pigparadise avatar qinhanlei avatar rangercyh avatar t0350 avatar whislly avatar xjdrew avatar ykxpb avatar yuanfengyun avatar yxt945 avatar zero-rp avatar zhuilang 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  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

skynet's Issues

some documents?

help add some tutorial wikis
how to use?
tutorial of pingsvr?

skynet abort problem

执行abort服务后socket,worker线程无法退出.
因为socket线程被epoll_wait阻塞(timeout为-1).
worker线程因为在条件等待,也无法wakeup.
可以考虑在timer线程的结束部分加入处理这两个线程.
如果在monitor线程中处理的话有可能造成5s的延迟.

skynet.pack 中分配的内存释放问题

1、建议将 testconnection.lua, watchdog.lua, agent.lua 中的
skynet.register_protocol {
name = "client",
id = 3,
改为
skynet.register_protocol {
name = "client",
id = skynet.PTYPE_SOCKET,
这个应该是之前忘了修改的
2、skynet.pack 中分配的内存是怎样被释放的呢?个人感觉比较容易引起内存泄露,像这样使用: skynet.tostring(skynet.pack(...)) 就出现内存泄露了

can't compile

skynet-src/skynet_timer.c: In function ‘_gettime’:
skynet-src/skynet_timer.c:202: warning: implicit declaration of function ‘clock_gettime’
skynet-src/skynet_timer.c:202: error: ‘CLOCK_MONOTONIC’ undeclared (first use in this function)
skynet-src/skynet_timer.c:202: error: (Each undeclared identifier is reported only once
skynet-src/skynet_timer.c:202: error: for each function it appears in.)
skynet-src/skynet_timer.c: In function ‘skynet_timer_init’:
skynet-src/skynet_timer.c:238: error: ‘CLOCK_REALTIME’ undeclared (first use in this function)
make: *** [skynet] Error 1

freebsd编译出错

在freebsd上编译出现错误,发现是以下3个问题

  1. freebsd系统中dlopen在libc中, makefile中使用 -ldl
  2. freebsd系统中, struct sockaddr_in定义在 #include <netinet/in.h>; 相关的源文件都需要这个头文件, 例如 service-src/service_harbor.c, client-src/client.c等
  3. gate/mread.c 中, #include <sys/types.h>必须在 #include <sys/event.h>之前,否则会报错

gate bug

skynet crash at gate/mread.c:514 assert(0)
原因是在report closed socket 之前,对一个socket执行了两次mread_close_client或者force_close_client,应该加上对socket状态的判断。

gate bugs

gate/main.c:201 if (agent) => if (agent && agent->uid == uid)
gate/mread.c:749 s->fd = self->free_socket => s->fd = self->free_socket ? self->free_socket - self->sockets : -1;

bug in mqueue

if do_func(f, msg) ~= nil then -->
if not do_func(f, msg) then
另外,pcall(f, table.unpack(msg))增加session、addr参数似乎更为合适。
如果需要对send过来的消息序列化执行,mqueue也做不了,服务自己实现更方便些。

memory leak

It seems not release ctx->queue when service exit by using skynet_command "KILL", since ctx->queue may not in global queue at that time.

Question about the CHECK_ABORT macro in _socket

The macro runs if "r<0". I think this means that, in this cycle, sp_wait was not called in socket_server_poll.

Suppose we get several socket events from sp_wait. After the first event is processed, CHECK_ABORT isn't called. But after the second event is processed, the macro will be called.

I had thought that the macro should be called only when ss->ev is empty in order to avoid missing events. But my assumption doesn't match the code logic. So I think maybe I haven't understood it right.

Could you kindly give me some hint on this doubt. Especially, why the macro runs only when "r<0"?

Thank you!

the bug about harbor

service-src/service_harbor.c:554: _connect_master: Assertion `type == 6' failed.
Aborted (core dumped)

skynet-src/skynet_mq.c racing condition

Memory barrier is not properly used, which introduces potential racing condition.
There are several issues listed below:

  1. Full barrier at line 57 CAN be replaced with a write barrier.
  2. Full barrier at line 59 is not needed at all.
  3. Full barrier at line 80 is not needed at all
  4. Read barrier MUST be inserted before line 75.

socket.close bug

socket.close 中的driver.clear只传进一个参数,但是lua-socket.c中的
lclearbuffer -> luaL_checktype(L,2,LUA_TTABLE); 
却检查第二个参数

skynet 可以在cygwin下编译吗

因为开发环境上是windows,所以想尝试windows下编译skynet,可惜没成功,报很多 未定义的引用 的错。

/tmp/cciLXFsR.o:在函数‘bind_socket’中:
/home/Administrator/skynet/skynet-src/socket_server.c:493:对‘sp_nonblocking’
未定义的引用
/tmp/cciLXFsR.o:在函数‘start_socket’中:
/home/Administrator/skynet/skynet-src/socket_server.c:511:对‘sp_add’未定义的
引用
/tmp/cciLXFsR.o:在函数‘report_connect’中:
/home/Administrator/skynet/skynet-src/socket_server.c:651:对‘sp_write’未定义
的引用
/tmp/cciLXFsR.o:在函数‘report_accept’中:
/home/Administrator/skynet/skynet-src/socket_server.c:681:对‘sp_nonblocking’
未定义的引用
/tmp/cciLXFsR.o:在函数‘socket_server_poll’中:
/home/Administrator/skynet/skynet-src/socket_server.c:718:对‘sp_wait’未定义的
引用

我希望去掉一些可能没有人使用的特性

Skynet 目前有些特性可能没有人使用,但会增加维护成本。

我希望去掉它们,让代码简洁一些。

  1. remote object 它本身有无法跨机的限制,而且不容易用好。去掉它可以让 skynet.lua 以及 lua 的序列化代码简短很多。
  2. Trace 时间统计, 对于分析协议的 CPU 时间或许有价值。但目前它为了搜集一个 coroutine 的运行碎片时间,而把 skynet.lua 搞得太复杂。

不知道有人在使用它们吗?

a bug

gate/mread.c:71 if是不是应该改为while (看错了:))

confused method name [to_little_endian]

lua-mongo.c 里的to_little_endian方法写错了.
return u.b[0] | u.b[1] << 8 | u.b[2] << 16 | u.b[3] << 24;
==>
return u.b[3] | u.b[2] << 8 | u.b[1] << 16 | u.b[0] << 24;

compat52.c lua_tounsignedx

在windows上正常工作。在android上 -0x1234转 unsinged int直接为0了,导致luaL_checkversion失败。 应该是undefined behaviour。
先转为int在android也正常工作了。

LUA_API lua_Unsigned
lua_tounsignedx(lua_State *L, int idx, int *isnum) {
lua_Number n = lua_tonumberx(L, idx, isnum);
return (lua_Unsigned)(int)n;
}

socket.write failed

回复太快了..谢谢.
另外,socket.write在失败的时候,没有反馈给应用层,这会导致应用层在不知道连接已经断开的情况下继续发送数据

lua-seri.c _get_buffer Segmentation fault

static void
_get_buffer(lua_State *L, struct read_block *rb, int len) {
char tmp[len];
char * p = rb_read(rb,tmp,len);
// 此处是否忘了以下代码:
// if (p == NULL) {
// _invalid_stream(L,rb);
// }
lua_pushlstring(L,p,len);
}

error on using redis:exec

./lualib/redis.lua:69: attempt to compare number with nil
Bulk应答除了数字外,还可能是+OK

lua-seri bug

把config里的harbor设置为大于127之后,程序在执行到main.lua中 skynet.monitor "simplemonitor"的时候会挂起,跟踪后发现是lua-seri 模块对unsigned integer类型处理不正确引起的:
lua-seri.c:337
case LUA_TNUMBER: {
lua_Integer x = lua_tointeger(L,index);
lua_Number n = lua_tonumber(L,index);
if ((lua_Number)x==n) {
wb_integer(b, x, TYPE_NUMBER);
} else {
wb_number(b,n);
}
lua_integer被定义为ptrdiff_t(在64位机器上为 long int),在类型转换后x==n会成立,从而把unsigned integer当成signed integer处理。

patch:
lua_Integer x = lua_tointeger(L,index); -> int32_t x = (int32_t)lua_tointeger(L,index);

socket.abandon

请问这个API应该怎么用?注释里的socket.accept并不存在。
我想在客户端建立连接后,把这个socket id转发到别的服务里,让别的服务处理后续的数据流。

timer concurrency

在skynet_updatetime和skynet_gettime_fixsec中,TI->current会被并发读写.
这里是否考虑加个读写锁

函数调用有多余的参数

skynet_start.c, _start函数:

151     for (i=0;i<thread;i++) {
152         m->m[i] = skynet_monitor_new(i); // 这里i是多余的参数
153     }

sendname bug

skynet_server.c:624
if (des == 0) {
free(data);
skynet_error(context, "Drop message to %s", addr);
return session;
}
这里可能会free不是在堆上分配的数据.
patch:
int dontcopy = type & PTYPE_TAG_DONTCOPY;
if (dontcopy) {
free(data)
}

bug about redis/socket module

the debug info:
[64000010] lua call [0 to :64000010 : 0 msgsz = 24] error : ./lualib/skynet.lua:81: ./lualib/socket.lua:241: assertion failed!
stack traceback:
[C]: in function 'assert'
./lualib/socket.lua:241: in function 'lock'
./lualib/redis.lua:112: in function 'get'
调用场景:A,B两个service,B有db连接,A 先send消息给 B写数据, A 再call B读取数据,会出现上述bug信息,如果把第一步send改为call方式则正常。如果多次send再call,会读到错误数据。

socket.open failed

socket.open在连接失败的时候直接调用了error(cmd .. "failed"),这会导致后面的应用层代码无法继续执行,这个情况应该返回一个错误码,让应用层决定如何处理,如重新尝试连接

socket.write failed

socket.write失败时没有反馈给应用层,这会导致应用层在连接已经断开的情况下还继续发送数据

内存泄露问题

做了简单的修改 把client改成了持续发包 内存不断上涨 客户端关闭以后内存也没下降

Server crashed under stress test

With the default configuration, the server crashed by this test:

$ while true; do echo -e "SET abc 1 \nGET abc"; done | ./client 127.0.0.1 8888

It seems the function 'expand_queue' failed to allocate enough memory.

An assertion on the return value of malloc(3) was put in the function, and the call-stack is like this:
#0 0x00007f8bda192475 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x00007f8bda1956f0 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x00007f8bda18b621 in __assert_fail () from /lib/x86_64-linux-gnu/libc.so.6
#3 0x00000000004055da in expand_queue (q=0x135ee00)

at skynet-src/skynet_mq.c:153

#4 0x00000000004058c3 in skynet_mq_push (q=0x135ee00, message=0x7f8bd8846c40)

at skynet-src/skynet_mq.c:211

#5 0x000000000040600d in skynet_context_push (handle=16777240,

message=0x7f8bd8846c40) at skynet-src/skynet_server.c:170

#6 0x0000000000407631 in skynet_send (context=0x7f8bd405c670,

source=16777232, destination=16777240, type=65539, session=0, 
data=0xca60e70, sz=50331655) at skynet-src/skynet_server.c:631

#7 0x00007f8bd9858f9b in _forward (g=0x7f8bd405c610, c=0x7f8bd4079ae0, size=7)

at service-src/service_gate.c:175

#8 0x00007f8bd9859131 in dispatch_message (g=0x7f8bd405c610,

c=0x7f8bd4079ae0, id=13, data=0x7f8bc3c52410, sz=16384)
at service-src/service_gate.c:199

#9 0x00007f8bd9859208 in dispatch_socket_message (g=0x7f8bd405c610,

message=0x7f8bc3c00a90, sz=0) at service-src/service_gate.c:214

#10 0x00007f8bd985964b in _cb (ctx=0x7f8bd405c670, ud=0x7f8bd405c610, type=6,

session=0, source=0, msg=0x7f8bc3c00a90, sz=24)
at service-src/service_gate.c:297

#11 0x0000000000406333 in _dispatch_message (ctx=0x7f8bd405c670,

msg=0x7f8bd8846e60) at skynet-src/skynet_server.c:250

#12 0x0000000000406481 in skynet_context_message_dispatch (sm=0x12fbcb0)

at skynet-src/skynet_server.c:288

#13 0x0000000000407b5c in _worker (p=0x7fff5de06dd0)

at skynet-src/skynet_start.c:122

#14 0x00007f8bdadb1b50 in start_thread ()

from /lib/x86_64-linux-gnu/libpthread.so.0
#15 0x00007f8bda23c0ed in clone () from /lib/x86_64-linux-gnu/libc.so.6
#16 0x0000000000000000 in ?? ()

The system is a 64-bit and 4-core computer running Linux.

mongo 使用问题

使用 skynet 中的 mongo 驱动向数据库中插入文档,若文档中包含一个空的 array,则后面更新文档时,使用 $push 或 $addToSet 往该 array 中添加数据会失败(返回操作成功,但数据库中没有数据)
个人觉得,可能是 bson 打包的时候,空数组被认为是空文档造成的,如果是的话,当成空数组可能也有问题,不知道有什么好的解决方案?

测试使用的mongodb 版本:v2.4.6

lua call memory leak

valgrind log:

==23747== HEAP SUMMARY: [12/59790]
==23747== in use at exit: 2,706,935 bytes in 103 blocks
==23747== total heap usage: 3,314 allocs, 3,211 frees, 6,028,122 bytes allocated
==23747==
==23747== 1 bytes in 1 blocks are definitely lost in loss record 1 of 55
==23747== at 0x4C2CD7B: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==23747== by 0x8D6A9F0: ???
==23747== by 0x5469E49: luaD_precall (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5475353: luaV_execute (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x546A098: luaD_call (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5466240: lua_callk (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5480E36: ll_require (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5469E49: luaD_precall (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5475353: luaV_execute (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x546A098: luaD_call (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x54696DA: luaD_rawrunprotected (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x546A2C4: luaD_pcall (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747==
==23747== 264 bytes in 1 blocks are definitely lost in loss record 43 of 55
==23747== at 0x4C2CD7B: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==23747== by 0x8D6ADC4: ???
==23747== by 0x8D6976B: ???
==23747== by 0x5469E49: luaD_precall (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5475353: luaV_execute (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x546A098: luaD_call (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x54696DA: luaD_rawrunprotected (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x546A2C4: luaD_pcall (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x546630E: lua_pcallk (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x6360850: _init (service_lua.c:165)
==23747== by 0x6360976: _launch (service_lua.c:182)
==23747== by 0x405DE5: skynet_context_message_dispatch (skynet_server.c:259)
==23747==
==23747== 2,097,156 bytes in 1 blocks are definitely lost in loss record 55 of 55
==23747== at 0x4C2CD7B: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==23747== by 0x8D6AC29: ???
==23747== by 0x5469E49: luaD_precall (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5475353: luaV_execute (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x546A098: luaD_call (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5466240: lua_callk (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5480E36: ll_require (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5469E49: luaD_precall (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x5475353: luaV_execute (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x546A098: luaD_call (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x54696DA: luaD_rawrunprotected (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747== by 0x546A2C4: luaD_pcall (in /usr/lib/x86_64-linux-gnu/liblua5.2.so.0.0.0)
==23747==
==23747== LEAK SUMMARY:
==23747== definitely lost: 2,097,421 bytes in 3 blocks
==23747== indirectly lost: 0 bytes in 0 blocks
==23747== possibly lost: 0 bytes in 0 blocks
==23747== still reachable: 609,514 bytes in 100 blocks
==23747== suppressed: 0 bytes in 0 blocks
==23747== Reachable blocks (those to which a pointer was found) are not shown.
==23747== To see them, rerun with: --leak-check=full --show-reachable=yes
==23747==
==23747== For counts of detected and suppressed errors, rerun with: -v
==23747== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 2 from 2)

请问上面3个error有可能是哪里引起的?

无法超过两根工作线程同时工作

由于在 shield_start 中的 Wakeup 函数 busy 参数只会被传入 0 或者 1

导致当 sleep 线程的个数小于总工作线程数 2 的时候,就不会再有线程被唤醒,这应该是一个手误,不过不太理解设计这个wakeup调度的初衷。

socket server half close problem

客户端发送一个数据请求包后,紧接着调用shutdown(fd, SHUT_WR)发送一个FIN,
socket server接受到FIN后就马上调用force_close关闭链接,导致响应包无法发送
到客户端,这种情况下,是不是应该让业务逻辑知道这个HALF CLOSE状态,在完成响应包的发送后再由业务逻辑主动关闭链接,而不是让socket server来做这个工作。

启动时候出错

skynet$> ./skynet config_log
[:2000002] launch gate L ! 127.0.0.1:2527 5 256 0
[:2000001] launch harbor 127.0.0.1:2013 127.0.0.1:2527 2
[:2000003] launch logger
[:2000004] launch localcast
[:2000005] launch snlua launcher
[:2000006] launch snlua main_log
Log server start
[:2000007] launch snlua service_mgr
[:2000008] launch snlua lualog
[:2000009] launch snlua console
[2000009] lua call [0 to :2000009 : 1 msgsz = 0] error : ./lualib/skynet.lua:342: ./lualib/skynet.lua:82: ./lualib/skynet.lua:291: attempt to call global 'unpack' (a nil value)
stack traceback:
./lualib/skynet.lua:291: in function 'f'
./lualib/skynet.lua:41: in function <./lualib/skynet.lua:40>
stack traceback:
[C]: in function 'assert'
./lualib/skynet.lua:342: in function <./lualib/skynet.lua:324>[:200000a] launch snlua globallog

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.