seznam / fastrpc Goto Github PK
View Code? Open in Web Editor NEWFastRPC library
Home Page: http://seznam.github.io/frpc
License: GNU Lesser General Public License v2.1
FastRPC library
Home Page: http://seznam.github.io/frpc
License: GNU Lesser General Public License v2.1
A meta issue collecting changes planned/implemented for fastrpc8
I've just found out that at least Flask handler in python/fastrpc/handler/flask.py - probably the other two are affected too - doesn't support base64-encoded data (Content-Type
:application/x-base64-frpc
).
IMHO it should
ContentType
headerDocumentation for Struct_t::erase is wrong - type in @return
section doesn't match signature, returned value description doesn't make sense - probably copy-paste error.
DateTime will contain 8 byte timestamp on wire
Int will get a new encoding scheme, using ZigZag encoding
For version 8.0, this will be opt-in (via serverproxy setting) to ensure this can be deployed easily.
For version 8.1, we'll make it the default.
Which leads to missing FRPC::cleanupFastrpc symbol when importing python3-fastrpc unless libfastrpc8 is installed with the same version manually.
Check the debian packaging and fix.
Remove obsolete constructions of DateTime, as described in python/fastrpcmodule.cc:397 and similar:
python3-fastrpc (7.0.3)
xmlrpc.client.__version__ == '3.4'
fastrpc does not return tuple, when method name is not provided
In [6]: fastrpc.loads(fastrpc.dumps(("test",)))
Out[6]: ('test', None)
In [7]: xmlrpc.client.loads(xmlrpc.client.dumps(("test",)))
Out[7]: (('test',), None)
it is ok when method name is set
In [8]: fastrpc.loads(fastrpc.dumps(("test",), "xxx"))
Out[8]: (('test',), 'xxx')
In [9]: xmlrpc.client.loads(xmlrpc.client.dumps(("test",), "xxx"))
Out[9]: (('test',), 'xxx')
fastrpc raises RuntimeError: Parser error:< Empty document >
but only on strings more than 3 chars long:
In [10]: fastrpc.loads("asda")
RuntimeError: Parser error:< Empty document >
Otherwise no error occures
In [12]: fastrpc.loads("asd")
Out[12]: (None, None)
In [13]: xmlrpc.client.loads("asd")
ExpatError: syntax error: line 1, column 0
So there is no chance how to recognize parse error, or validly returned None with no method name..
# OK
In [52]: fastrpc.loads(fastrpc.dumps((None,), "xxx"))
Out[52]: ((None,), 'xxx')
# Validly returned None
In [53]: fastrpc.loads(fastrpc.dumps((None,), None))
Out[53]: (None, None)
# Invalid, but same as valid None
In [63]: fastrpc.loads("asd")
Out[63]: (None, None)
# OK
In [58]: xmlrpc.client.loads(xmlrpc.client.dumps((None,), "xxx", allow_none=True))
Out[58]: ((None,), 'xxx')
# OK
In [57]: xmlrpc.client.loads(xmlrpc.client.dumps((None,), None, allow_none=True))
Out[57]: ((None,), None)
# OK
In [64]: xmlrpc.client.loads("asd")
ExpatError: syntax error: line 1, column 0
Loading xmlrpc.client.Fault with fastrpc fails to set faultCode - that means it is not possible to use fastrpc on xml documents generated with xmlrpc lib
In [49]: fastrpc.loads(xmlrpc.client.dumps(xmlrpc.client.Fault(504, "Err")))
Fault: <fastrpc.Fault: 0, Err>
In [51]: fastrpc.loads(fastrpc.dumps(fastrpc.Fault(504, "Err")))
Fault: <fastrpc.Fault: 504, Err>
Hi. I've recently encountered an issue where a second call with number that's serialized into <i8>
on ServerProxy object fails with error:
fastrpc.ResponseError: <fastrpc.ResponseError: Number is too big for protocol version 1.0 [method test_func() @ http://localhost:8000/]>
Provided are server and client scripts used to simulate this behavior, run using python2:
import xmlrpclib
from SimpleXMLRPCServer import SimpleXMLRPCServer
def test_func(param):
return "param: {}".format(param)
def main():
server = SimpleXMLRPCServer(("localhost", 8000))
print "Listening on port 8000..."
server.register_function(test_func, "test_func")
server.serve_forever()
if __name__ == '__main__':
main()
fastrpc import ServerProxy
p = ServerProxy("http://localhost:8000")
p.test_func(12)
p.test_func(223124215125125)
Seems to me like fastrpc does not only fallback from using binary when communicating with xmlrpc server but also to a lower protocol version. This is backed up by the fact that making only the call with a large number does not fail, eg. this script runs fine:
from fastrpc import ServerProxy
p = ServerProxy("http://localhost:8000")
# p.test_func(12)
p.test_func(223124215125125
Versions as reported by dpkg:
ii libfastrpc8 8.0.10 amd64 Fastrpc - RPC library, supports binary and XML encoding
ii python-fastrpc 8.0.5 amd64 Fastrpc -- RPC using XML and Binary protocol
V fastrpcmodule.c nejsou definovane __cmp__
metody pro DateTime
, LocalTime
, UTCTime
a Binary
, coz znamena, ze jejich instance nejsou porovnovatelne.
from fastrpc import LocalTime
print LocalTime(1408967234) == LocalTime(1408967234) # => False
it is not possible to access ServerProxy properties via __dict___
(proxy.__dict__["host"]
) with hideAttributes=True
python-fastrpc 5.07
Gusy.. like.. do you even test it once?
Setting up python-fastrpc (8.0.1) ...
File "/usr/lib/python2.7/dist-packages/fastrpc/handler/aiohttp.py", line 42
def register_method(self, method_name: str, func: Callable) -> None:
^
SyntaxError: invalid syntax
File "/usr/lib/python2.7/dist-packages/fastrpc/handler/flask.py", line 43
def __init__(self, app: Flask=None, register_introspection_methods: bool=True,
^
SyntaxError: invalid syntax
dpkg: error processing package python-fastrpc (--configure):
subprocess installed post-installation script returned error exit status 101
Specification says that 2.0 add Null type.
>>> fastrpc.dumps((None,), useBinary=True, protocolVersionMajor=2, protocolVersionMinor=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: Null is not supported by protocol version lower than 2.1
There is no mention of 2.1 protocol version!
this resolution code needs to be moved to the connectSocket method, so that adress resolution happens when keepalive is taken down by remote (which happens in case pods/server instances move addressses)
We have version 3 of the binary protocol with changes to Int and DateTime. Need to reflect that in the documentation.
How to reproduce:
from fastrpc import dumps
x = []
x.append(x)
dumps(x)
There is no documentation or README for this project.
BUILD instructions missing.
INSTALL file contains incorrect procedure for building - does not work on ArchLinux.
No prerequisites file.
python-fastrpc
fails to decode DateTime
object with date in year 2100.
Code to reproduce problem:
from fastrpc import dumps, loads, DateTime
d = DateTime("2100-01-01")
t = dumps((d, ), useBinary=True)
s = loads(t)[0]
assert d.unixTime == s.unixTime
This code raises AssertionError
. Results for inspiration:
d, s == (DateTime("21000101T00:00:00+0000"), DateTime("21000101T00:00:00+0000"))
d.unixTime, s.unixTime == (4102441200, -192526096) # Error here
So let's discuss before any work will be done.
I see two main options:
Which one maintainers prefer?
((python8.0.1)) $ ./setup.py sdist
running sdist
running egg_info
creating fastrpc.egg-info
writing fastrpc.egg-info/PKG-INFO
writing top-level names to fastrpc.egg-info/top_level.txt
writing dependency_links to fastrpc.egg-info/dependency_links.txt
writing manifest file 'fastrpc.egg-info/SOURCES.txt'
reading manifest file 'fastrpc.egg-info/SOURCES.txt'
writing manifest file 'fastrpc.egg-info/SOURCES.txt'
running check
creating fastrpc-8.0.1
creating fastrpc-8.0.1/fastrpc.egg-info
copying files to fastrpc-8.0.1...
copying README -> fastrpc-8.0.1
copying fastrpc.py -> fastrpc-8.0.1
copying fastrpcmodule.cc -> fastrpc-8.0.1
copying pyerrors.cc -> fastrpc-8.0.1
copying pythonbuilder.cc -> fastrpc-8.0.1
copying pythonfeeder.cc -> fastrpc-8.0.1
copying pythonserver.cc -> fastrpc-8.0.1
copying setup.py -> fastrpc-8.0.1
copying fastrpc.egg-info/PKG-INFO -> fastrpc-8.0.1/fastrpc.egg-info
copying fastrpc.egg-info/SOURCES.txt -> fastrpc-8.0.1/fastrpc.egg-info
copying fastrpc.egg-info/dependency_links.txt -> fastrpc-8.0.1/fastrpc.egg-info
copying fastrpc.egg-info/top_level.txt -> fastrpc-8.0.1/fastrpc.egg-info
Writing fastrpc-8.0.1/setup.cfg
creating dist
Creating tar archive
removing 'fastrpc-8.0.1' (and everything under it)
So outgoing tarball doesn't contain any header file. Can be fixed using MANIFEST.in
:
include *.h
Next code reproduces segmentation fault. Tested on versions 7.0.1
and 7.0.2
.
from fastrpc import ServerProxy
str(type(ServerProxy('http://sbox:2825/RPC2').bar))
GDB
backtrace
#0 _PyObject_Str (v=<unknown at remote 0x7ffff6c18e00>) at ../Objects/object.c:423
res = <optimized out>
type_ok = <optimized out>
#1 PyObject_Str (v=<unknown at remote 0x7ffff6c18e00>) at ../Objects/object.c:451
res = <type at remote 0x93cac0>
#2 string_new.lto_priv () at ../Objects/stringobject.c:3709
x = <unknown at remote 0x7ffff6c18e00>
kwlist = {0x6c8d61 "object", 0x0}
#3 0x00000000004ba865 in type_call.lto_priv () at ../Objects/typeobject.c:729
obj = <optimized out>
#4 0x00000000004caaa1 in PyObject_Call (kw=<optimized out>, arg=<optimized out>, func=<optimized out>) at ../Objects/abstract.c:2529
call = 0x4ba840 <type_call.lto_priv>
#5 do_call (nk=<optimized out>, na=<optimized out>, pp_stack=<optimized out>, func=<optimized out>) at ../Python/ceval.c:4251
callargs = (<unknown at remote 0x7ffff6c18e00>,)
kwdict = 0x0
#6 call_function (oparg=<optimized out>, pp_stack=<optimized out>) at ../Python/ceval.c:4056
func = <type at remote 0x93cac0>
w = <type at remote 0x93cac0>
nk = -135697328
n = -9552
pfunc = 0x7ffff7ef0c48
#7 PyEval_EvalFrameEx () at ../Python/ceval.c:2679
sp = 0x7ffff7ef0c50
opcode = 4958272
#8 0x00000000004c87a1 in PyEval_EvalCodeEx () at ../Python/ceval.c:3265
f = 0x0
retval = <code at remote 0x7ffff7ee2a30>
fastlocals = 0x4b3fa7 <vgetargskeywords.lto_priv+87>
tstate = 0x9ae0a0
u = <unknown at remote 0x1>
#9 0x00000000005030ef in PyEval_EvalCode (
locals={'__builtins__': <module at remote 0x7ffff7fa7b08>, '__file__': 'test.py', '__package__': None, '__name__': '__main__', 'ServerProxy': <built-in function ServerProxy>, '__doc__': None},
globals={'__builtins__': <module at remote 0x7ffff7fa7b08>, '__file__': 'test.py', '__package__': None, '__name__': '__main__', 'ServerProxy': <built-in function ServerProxy>, '__doc__': None},
co=0x7ffff7ee2a30) at ../Python/ceval.c:667
No locals.
#10 run_mod.lto_priv () at ../Python/pythonrun.c:1371
co = 0x7ffff7ee2a30
#11 0x00000000004f8c72 in PyRun_FileExFlags () at ../Python/pythonrun.c:1357
ret = <unknown at remote 0x7fffffffe66f>
mod = 0xa51508
arena = 0x9da5c0
#12 0x00000000004f7d77 in PyRun_SimpleFileExFlags () at ../Python/pythonrun.c:949
m = <module at remote 0x7ffff7f69cc8>
d = {'__builtins__': <module at remote 0x7ffff7fa7b08>, '__file__': 'test.py', '__package__': None, '__name__': '__main__', 'ServerProxy': <built-in function ServerProxy>, '__doc__': None}
v = <unknown at remote 0x1>
ret = -6542
#13 0x00000000004982f2 in Py_Main () at ../Modules/main.c:640
sts = 0
command = 0x0
filename = 0x7fffffffe66f "test.py"
stdin_is_interactive = 1
help = -135528320
version = 1
saw_unbuffered_flag = -6545
cf = {cf_flags = 0}
#14 0x00007ffff6f12b45 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
No symbol table info available.
#15 0x0000000000497ca0 in _start ()
No symbol table info available.
Versions:
$ apt-cache policy python-fastrpc
python-fastrpc:
Installed: 7.0.2
Candidate: 7.0.2
Version table:
*** 7.0.2 0
470 http://debian/ jessie-stable/main amd64 Packages
460 http://debian/ jessie-testing/main amd64 Packages
150 /var/lib/dpkg/status
7.0.1 0
470 http://debian/ jessie-stable/main amd64 Packages
460 http://debian/ jessie-testing/main amd64 Packages
6.0.2~1 0
470 http://debian/ jessie-stable/main amd64 Packages
460 http://debian/ jessie-testing/main amd64 Packages
5.0.9 0
470 http://debian/ jessie-stable/main amd64 Packages
460 http://debian/ jessie-testing/main amd64 Packages
5.0.8 0
470 http://debian/ jessie-stable/main amd64 Packages
460 http://debian/ jessie-testing/main amd64 Packages
$ apt-cache policy libfastrpc7
libfastrpc7:
Installed: 7.0.1
Candidate: 7.0.1
Version table:
*** 7.0.1 0
470 http://debian/ jessie-stable/main amd64 Packages
460 http://debian/ jessie-testing/main amd64 Packages
150 /var/lib/dpkg/status
Whenever you try to compare DateTime object to some other type it throws:
TypeError: arg #2 is not a DateTime, it is ...
import fastrpc
d=fastrpc.DateTime()
d =! ''
Reproducible in versions 5.1.0 and higher
This is really unexpected behavior and from my point of view a bug. In version 5.0.9 and lower comparison behaves expectedly, like any other data type in python.
If this is desired behavior, it should be documented and pinpointed for its "non pythonian way" characteristic.
if I get passed a ServerProxy
object to a function, there's no way for me to get it's address other than creating, catching and parsing an exception.
>>> some_server = fastrpc.ServerProxy('http://wanted.com:2250/RPC2')
>>> some_server
<ServerProxy object at 0xe98ea0>
>>> dir(some_server)
['host', 'last_call', 'path', 'port', 'url']
>>> some_server.url
<Method object at 0x7fca6f1b5f10>
>>> some_server.url()
Traceback (most recent call last):
File "<input>", line 1, in <module>
Fault: <fastrpc.Fault: 404, mtd: object does/does not exist: Nor default method nor method of such name are registered: url [method url() @ http://wanted.com:2250/RPC2]>
>>> some_server.host
<Method object at 0xf621f0>
>>> some_server.host()
Traceback (most recent call last):
File "<input>", line 1, in <module>
Fault: <fastrpc.Fault: 404, mtd: object does/does not exist: Nor default method nor method of such name are registered: host [method host() @ http://wanted.com:2250/RPC2]>
>>> repr(some_server)
'<ServerProxy object at 0xe98ea0>'
>>> str(some_server)
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: 'str' object is not callable
# The only solution for now, other than wrapping it
>>> try:
... some_server.no_method()
... except fastrpc.Fault as e:
... print(repr(e).split('@')[1].split(']')[0])
http://wanted.com:2250/RPC2
Last released version on pypi is 8.0.1 (even Seznam internal one)
Hi, we found yesterday problem with binary data handling.
How to reproduce:
str
typeWhen use explicit fastrpc.Binary
type, everything works well. Possible reason is here:
https://github.com/seznam/fastrpc/blob/master/python/pythonfeeder.cc#L212-L214
When str
type is used fastrpc assume utf-8 which is wrong by design of python 2.x where
type(b'') == str -> True
We also try explicitly define stringMode='string'
when loads
, dumps
don't support this option
In [44]: gif = 'GIF89aX\x02X\x02\xf4\x00\x00\xb6\xb0\x9e\x8c\x88y\xa7\xcf\xd0Z\xb5\xd4speY\xa1\xb8\xcb\xc5\xb1\xf7\xa5M\xa0\x9c\x8c\xa9l-\xa5\xa7\xa2\xe8\xe0\xc7\xbf\xd9\xd2\x81\xb4\xbe\x93\x8d~\xdc\xd6\xc0/v\x91\xf1\xc5\x8d\xa6\x82T9\x90\xb0\xee\xd5\xad\xda|\x1bt\xc3\xdb-..\xd4\xdf\xd0@\xa6\xcc\x80\xa1\xa1\x1d\x87\xb1\xfe~\x00'
In [45]: from fastrpc import Binary, loads, dumps
In [46]: bgif = Binary(gif)
In [47]: loads(dumps((gif, ), useBinary=True), useBinary=True, stringMode="string")[0] == gif
Out[47]: True
In [48]: loads(dumps((bgif, ), useBinary=True), useBinary=True)[0].data == bgif.data
Out[48]: True
There's probably a problem with fastrpc packaging, causing transitive dependency on fastrpc not to be versioned in alignment with dev package. I.e. the addition of unMarshallPartial not being a well enough reason to package the binaries with new enough version of fastrpc (in this case, the deb package was built around libfastrpc-dev 8.0.13, but ran with fastrpc 8.0.0, leading to abortions while running due to missing symbols)
System:
$ apt-cache policy python-fastrpc libfastrpc5
python-fastrpc:
Installed: 5.0.8
Candidate: 5.0.8
Version table:
*** 5.0.8 0
450 http://debian/ wheezy-testing/main amd64 Packages
100 /var/lib/dpkg/status
5.0.7 0
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.6 0
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.5 0
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.2 0
700 http://debian/ wheezy-stable/main amd64 Packages
450 http://debian/ wheezy-testing/main amd64 Packages
libfastrpc5:
Installed: 5.0.9-1
Candidate: 5.0.9-1
Version table:
*** 5.0.9-1 0
700 http://debian/ wheezy-stable/main amd64 Packages
450 http://debian/ wheezy-testing/main amd64 Packages
100 /var/lib/dpkg/status
5.0.9 0
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.8 0
700 http://debian/ wheezy-stable/main amd64 Packages
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.7 0
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.6 0
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.5 0
700 http://debian/ wheezy-stable/main amd64 Packages
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.4 0
700 http://debian/ wheezy-stable/main amd64 Packages
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.3-4 0
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.3-3 0
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.3-2 0
450 http://debian/ wheezy-testing/main amd64 Packages
5.0.3 0
700 http://debian/ wheezy-stable/main amd64 Packages
450 http://debian/ wheezy-testing/main amd64 Packages
Test:
In [1]: from fastrpc import dumps
In [2]: dumps((), "foo.bar", useBinary=True, protocolVersionMajor=2, protocolVersionMinor=1)
Out[2]: '<?xml version="1.0"?>\n<methodCall>\n<methodName>foo.bar</methodName>\n<params>\n</params>\n</methodCall>\n'
In [3]: dumps((), "foo.bar", useBinary=True)
Out[3]: '\xca\x11\x02\x01h\x07foo.bar'
Requested output must be equal.
Datetime is not serialized according documentation:
Unix timestamp is stored in little endian order like integer. Other values are in the network order.
Network order = big endian, but output is ordered as little endian.
Tested for protocol v1, but v2,v3 may have same issue.
Please let me know about resulting fix(changed implementation or documentation) so I can implement same behaviour in my library.
There are few issues with fastrpc.Boolean
bool
s:from fastrpc import Boolean
Boolean(True) is True # => False
Boolean(False) is False # => False
Boolean(True).__nonzero__() # raises AttributeError
from fastrpc import Boolean
Boolean(True) != None # 5.x => True
Boolean(True) != None # 7.x raises TypeError: arg #2 is not a Boolean
Bool values should be normalized before being serialized
+we can build the wheel in the future
I think this docs section is relevant https://docs.python.org/3/distutils/setupscript.html#extension-names-and-packages
FastRPC internal structure can't be subclassable (cause of bad PEP-253 implementation, see "Preparing a type for subtyping" paragraph). So programmer literally can't extend any of this structures with some extra properties or methods.
import fastrpc
rpc = fastrpc.ServerProxy("http://0:4111/RPC2",2000,2000,2000,1)
res = rpc.call_method_which_resurts_binary_data()
with installed python-fastrpc version 5.0.9 it works fine and in res are responce with binary data:
{'filter': '\xff\xff\xff\xff\x00\x00\x00\x06'}
but with version 5.1.0 it ends up with exception
UnicodeDecodeError Traceback (most recent call last)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xff in position 0: invalid start byte
my guess is that in 5.1.0 version may be binary data are interpreted as a string, that why UnicodeDecodeError occures
API is inconsistent. You can't do this:
from fastrpc import DateTime
DateTime(u"2016-01-01") # raises TypeError
but DateTime
value is unicode
:
from fastrpc import DateTime
print type(DateTime("2016-01-01").value) # => unicode
so chaining doesn't work well:
from fastrpc import DateTime
DateTime(DateTime("2016-01-01").value) # raises TypeError
c++ version of system.multicall returns array of arrays, each of inner arrays containing response from one method. The python version returns just array of responses (which I suppose is correct).
Plus there is a typo in the name of the handler function in c++, which is named muticall instead of multicall.
Currently (in the fastrpc6 branch) the custom headers are C++ only feature.
We'll introduce new kwarg - headers
usable as both ServerProxy and Method call parameter.
In method call context, this header will only be included in that one call.
...as was reported - the python module dependency on .so is vague (in the deb depends) leading to possible discrepancies in the symbol exports/imports.
Resulting situation was as follows:
ImportError: /usr/lib/python3/dist-packages/_fastrpc.cpython-35m-x86_64-linux-gnu.so: undefined symbol: _ZN4FRPC8HTTPIO_t15waitOnReadyReadEv
Having an equals sign for exact dependency based on version (i.e. depends libfastrpc8 (=8.X.Y)) could be beneficial for the stability of the project.
Boolean type should be removed, python-fastrpc should use native python bool everywhere
create version for Python 3
The root cause is that the constructor of DateTime(time_t, timezone) will ignore the timezone altogether, so the component part of the time specification will be offset.
#include <iostream>
#include <frpcpool.h>
#include <frpcdatetime.h>
int main() {
FRPC::Pool_t pool;
auto &dt = pool.UTCTime(0);
std::cout << dt.isoFormat() << std::endl;
return 0;
}
outputs:
19700101T01:00:00+0000
which should be
19700101T00:00:00+0000
or
19700101T01:00:00+0100
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.