我是 Frank Xu (阿阳),生活在广州,工作在腾讯。曾在 淘宝 带过前端,在 QQ邮箱 带过客户端。现在负责 微信读书 的数据运营,用数据驱动增长,用算法驱动内容分发。
技术栈比较泛,享受工程创造价值的过程。偶尔也在这里记录一些 零星的思考。
2022 开启一段新的旅程,尝试去带一个小产品,叫 微信听书,践行自己的产品观,知难行更难。
A DNS Server over Google's HTTPS DNS API in HTTP/2 Protocol
License: MIT License
npm install request spdy dnsd
installing depend as package.js http2": "^3.3.6 didnt solve. it keeps asking for spdy.
`PS C:\app\dns-over-http2-master> node.exe .\index.js
module.js:457
throw err;
^
Error: Cannot find module 'dnsd'
at Function.Module._resolveFilename (module.js:455:15)
at Function.Module._load (module.js:403:25)
at Module.require (module.js:483:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (C:\app\dns-over-http2-master\index.js:1:76)
at Module._compile (module.js:556:32)
at Object.Module._extensions..js (module.js:565:10)
at Module.load (module.js:473:32)
at tryModuleLoad (module.js:432:12)
at Function.Module._load (module.js:424:3)
PS C:\app\dns-over-http2-master> npm install dnsd
[email protected] C:\app\dns-over-http2-master
`-- [email protected]
+-- [email protected]
`-- [email protected]
`-- [email protected]
PS C:\app\dns-over-http2-master> node.exe .\index.js
module.js:457
throw err;
^
Error: Cannot find module 'spdy'
at Function.Module._resolveFilename (module.js:455:15)
at Function.Module._load (module.js:403:25)
at Module.require (module.js:483:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (C:\app\dns-over-http2-master\index.js:2:14)
at Module._compile (module.js:556:32)
at Object.Module._extensions..js (module.js:565:10)
at Module.load (module.js:473:32)
at tryModuleLoad (module.js:432:12)
at Function.Module._load (module.js:424:3)
PS C:\app\dns-over-http2-master> npm install http2
[email protected] C:\app\dns-over-http2-master
`-- [email protected]
PS C:\app\dns-over-http2-master> node.exe .\index.js
module.js:457
throw err;
^
Error: Cannot find module 'spdy'
at Function.Module._resolveFilename (module.js:455:15)
at Function.Module._load (module.js:403:25)
at Module.require (module.js:483:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (C:\app\dns-over-http2-master\index.js:2:14)
at Module._compile (module.js:556:32)
at Object.Module._extensions..js (module.js:565:10)
at Module.load (module.js:473:32)
at tryModuleLoad (module.js:432:12)
at Function.Module._load (module.js:424:3)
PS C:\app\dns-over-http2-master> npm install spdy
[email protected] C:\app\dns-over-http2-master
`-- [email protected]
+-- [email protected]
| `-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
`-- [email protected]
+-- [email protected]
| `-- [email protected]
+-- [email protected]
+-- [email protected]
| +-- [email protected]
| +-- [email protected]
| +-- [email protected]
| +-- [email protected]
| +-- [email protected]
| `-- [email protected]
`-- [email protected]
`-- [email protected]
PS C:\app\dns-over-http2-master> node.exe .\index.js
module.js:457
throw err;
^
Error: Cannot find module 'request'
at Function.Module._resolveFilename (module.js:455:15)
at Function.Module._load (module.js:403:25)
at Module.require (module.js:483:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (C:\app\dns-over-http2-master\index.js:3:36)
at Module._compile (module.js:556:32)
at Object.Module._extensions..js (module.js:565:10)
at Module.load (module.js:473:32)
at tryModuleLoad (module.js:432:12)
at Function.Module._load (module.js:424:3)
PS C:\app\dns-over-http2-master> npm install request
[email protected] C:\app\dns-over-http2-master
`-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
| `-- [email protected]
+-- [email protected]
+-- [email protected]
| `-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
| `-- [email protected]
+-- [email protected]
| +-- [email protected]
| | +-- [email protected]
| | +-- [email protected]
| | +-- [email protected]
| | | `-- [email protected]
| | +-- [email protected]
| | `-- [email protected]
| +-- [email protected]
| | `-- [email protected]
| +-- [email protected]
| | +-- [email protected]
| | +-- [email protected]
| | | `-- [email protected]
| | +-- [email protected]
| | `-- [email protected]
| `-- [email protected]
| `-- [email protected]
+-- [email protected]
| +-- [email protected]
| +-- [email protected]
| +-- [email protected]
| `-- [email protected]
+-- [email protected]
| +-- [email protected]
| +-- [email protected]
| | +-- [email protected]
| | +-- [email protected]
| | `-- [email protected]
| `-- [email protected]
| +-- [email protected]
| +-- [email protected]
| +-- [email protected]
| +-- [email protected]
| | `-- [email protected]
| +-- [email protected]
| +-- [email protected]
| | `-- [email protected]
| +-- [email protected]
| +-- [email protected]
| `-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
| `-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
+-- [email protected]
`-- [email protected]
PS C:\app\dns-over-http2-master> node.exe .\index.js
{ Error: bind EACCES 127.0.0.1:5353
at Object.exports._errnoException (util.js:1036:11)
at exports._exceptionWithHostPort (util.js:1059:20)
at dgram.js:221:18
at _combinedTickCallback (internal/process/next_tick.js:77:11)
at process._tickCallback (internal/process/next_tick.js:98:9)
at Module.runMain (module.js:592:11)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:509:3
code: 'EACCES',
errno: 'EACCES',
syscall: 'bind',
address: '127.0.0.1',
port: 5353 }
events.js:160
throw er; // Unhandled 'error' event
^
Error: getaddrinfo EAI_AGAIN dns.google.com:443
at Object.exports._errnoException (util.js:1036:11)
at errnoException (dns.js:33:15)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:76:26)
i receive this error sometimes:
events.js:182
throw er; // Unhandled 'error' event
^
Error: This socket has been ended by the other party
at Socket.writeAfterFIN [as write] (net.js:355:12)
at Socket.Writable.end (_stream_writable.js:528:10)
at Socket.end (net.js:490:31)
at Response.end (C:\Users\root\AppData\Roaming\npm\node_modules\h2dns\dnsd\server.js:238:21)
at Request.request [as _callback] (C:\Users\root\AppData\Roaming\npm\node_modules\h2dns\h2dns:162:11)
at self.callback (C:\Users\root\AppData\Roaming\npm\node_modules\h2dns\node_modules\request\request.js:188:22)
at emitOne (events.js:120:20)
at Request.emit (events.js:210:7)
at ClientRequest.<anonymous> (C:\Users\root\AppData\Roaming\npm\node_modules\h2dns\node_modules\request\request.js:8
22:16)
at Object.onceWrapper (events.js:312:19)
it tries to resolve dns.google.com and fails, because it can't itself As it is a forwarder only.
suggested solution step:
for spdy, comman Name is required for certificate Validation. simply use Ip only As Host Not work here As wanted.
if timeout occurs, for whatever reason.
Response code is noerror with empty answer.
make dns asking Application understand
Response received from 127.0.0.1:
Answer section:
No A-Records found for github.com
because res.end(); is still called After if (output && output.Answer) {}
can there be added something like
.on('timeout', RETRY Request?
than respond with res.end(); inside end of "if (output && output.Answer) {}"
escaping issues?
there shouldn't be that "\ Look and notice the difference compared in directly and dns-overhttp resolver:
; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @8.8.8.8 TXT google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30417
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;google.com. IN TXT
;; ANSWER SECTION:
google.com. 3599 IN TXT "v=spf1 include:_spf.google.com ~all"
; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @127.0.0.1 -p 6666 TXT google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44263
;; flags: qr rd ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;google.com. IN TXT
;; ANSWER SECTION:
google.com. 3600 IN TXT "\"v=spf1 include:_spf.google.com ~all\""
as mentioned here, #16
nice To see this agentpool. If Connection is good stable, it keeps creating a new Agent just Fine As I watched it now. Makes it more reliable over long time use. Well here is first errors i could reproduce.
Perhaps assume Agent To be faulty if ETIMEDOUT or check agent state before sending request, create new agent when agent Connection Lost.
Issue:
But with Default Setting, if tcp Connection closed two times. timeout kills it.
Note i closed the last Agent Connection i was seeing by Network in tcp manually. Two times each running.
[1477335892459/192/udp4] query dns.google.com IN AAAA: 213.177ms
Exceed pool maxSockets, creating a new Agent
Exceed pool maxSockets, creating a new Agent
[1477335904639/194/udp4] query dns.google.com IN AAAA: 775.732ms
[1477335901508/193/udp4] query dns.google.com IN AAAA: 5002.269ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477335914973/196/udp4] query dns.google.com IN AAAA: 180.633ms
[1477335911100/195/udp4] query dns.google.com IN AAAA: 5017.017ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477335915968/197/udp4] query dns.google.com IN AAAA: 634.341ms
[1477335917612/198/udp4] query dns.google.com IN AAAA: 153.931ms
[1477335918963/199/udp4] query dns.google.com IN AAAA: 144.956ms
[1477335919323/200/udp4] query dns.google.com IN AAAA: 174.744ms
[1477335919600/201/udp4] query dns.google.com IN AAAA: 413.346ms
[1477335920092/202/udp4] query dns.google.com IN AAAA: 188.164ms
[1477335920371/203/udp4] query dns.google.com IN AAAA: 301.873ms
[1477335920907/204/udp4] query dns.google.com IN AAAA: 224.692ms
[1477335921415/205/udp4] query dns.google.com IN AAAA: 577.275ms
[1477335922194/206/udp4] query dns.google.com IN AAAA: 196.912ms
[1477335922499/207/udp4] query dns.google.com IN AAAA: 253.411ms
[1477335922938/208/udp4] query dns.google.com IN AAAA: 225.621ms
[1477335923415/209/udp4] query dns.google.com IN AAAA: 186.591ms
[1477335927859/210/udp4] query dns.google.com IN AAAA: 5001.364ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477335935337/211/udp4] query dns.google.com IN AAAA: 5001.259ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477335941060/212/udp4] query dns.google.com IN AAAA: 5000.766ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477335947215/213/udp4] query dns.google.com IN AAAA: 5001.534ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477335953088/214/udp4] query dns.google.com IN AAAA: 5001.386ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477335959788/215/udp4] query dns.google.com IN AAAA: 5002.692ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
stream.js:74
throw er; // Unhandled stream error in pipe.
^
Error: ETIMEDOUT
at Timeout._onTimeout (C:\app\yyfrankyy\node_modules\request\request.js:759:15)
at ontimeout (timers.js:365:14)
at tryOnTimeout (timers.js:237:5)
at Timer.listOnTimeout (timers.js:207:5)
PS C:\app\yyfrankyy> node .\dns-over-http2\index.js
Exceed pool maxSockets, creating a new Agent
[1477336033348/217/udp4] query dns.google.com IN AAAA: 1201.679ms
[1477336035917/218/udp4] query dns.google.com IN AAAA: 119.984ms
[1477336037250/219/udp4] query dns.google.com IN AAAA: 264.863ms
[1477336038089/220/udp4] query dns.google.com IN AAAA: 172.062ms
[1477336038696/221/udp4] query dns.google.com IN AAAA: 222.884ms
[1477336039202/222/udp4] query dns.google.com IN AAAA: 187.021ms
[1477336039736/223/udp4] query dns.google.com IN AAAA: 141.968ms
[1477336040189/224/udp4] query dns.google.com IN AAAA: 286.275ms
[1477336040639/225/udp4] query dns.google.com IN AAAA: 175.310ms
[1477336041169/226/udp4] query dns.google.com IN AAAA: 219.336ms
[1477336041636/227/udp4] query dns.google.com IN AAAA: 218.828ms
[1477336042116/228/udp4] query dns.google.com IN AAAA: 266.861ms
[1477336044618/229/udp4] query dns.google.com IN AAAA: 252.162ms
[1477336045089/230/udp4] query dns.google.com IN AAAA: 222.127ms
[1477336045581/231/udp4] query dns.google.com IN AAAA: 150.765ms
[1477336047578/232/udp4] query dns.google.com IN AAAA: 383.554ms
[1477336048700/233/udp4] query dns.google.com IN AAAA: 405.680ms
Exceed pool maxSockets, creating a new Agent
[1477336059013/235/udp4] query dns.google.com IN AAAA: 1377.028ms
[1477336056528/234/udp4] query dns.google.com IN AAAA: 5002.261ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477336062387/236/udp4] query dns.google.com IN AAAA: 5001.224ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477336068536/237/udp4] query dns.google.com IN AAAA: 5000.370ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477336075330/238/udp4] query dns.google.com IN AAAA: 5001.855ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477336084832/239/udp4] query dns.google.com IN A: 5001.703ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477336091574/240/udp4] query dns.google.com IN A: 160.410ms
[1477336093342/241/udp4] query dns.google.com IN A: 303.905ms
stream.js:74
throw er; // Unhandled stream error in pipe.
^
Error: ETIMEDOUT
at Timeout._onTimeout (C:\app\yyfrankyy\node_modules\request\request.js:759:15)
at ontimeout (timers.js:365:14)
at tryOnTimeout (timers.js:237:5)
at Timer.listOnTimeout (timers.js:207:5)
PS C:\app\yyfrankyy> node .\dns-over-http2\index.js
Exceed pool maxSockets, creating a new Agent
[1477336168206/242/udp4] query dns.google.com IN A: 1175.152ms
[1477336171339/243/udp4] query dns.google.com IN A: 151.063ms
[1477336172470/244/udp4] query dns.google.com IN A: 142.233ms
[1477336173431/245/udp4] query dns.google.com IN A: 171.075ms
[1477336174352/246/udp4] query dns.google.com IN A: 106.235ms
[1477336175248/247/udp4] query dns.google.com IN A: 145.000ms
Exceed pool maxSockets, creating a new Agent
[1477336239210/248/udp4] query dns.google.com IN A: 1125.833ms
Exceed pool maxSockets, creating a new Agent
[1477336251853/249/udp4] query dns.google.com IN A: 776.282ms
[1477336276844/252/udp4] query dns.google.com IN A: 132.581ms
[1477336280599/253/udp4] query dns.google.com IN A: 134.638ms
[1477336281288/254/udp4] query dns.google.com IN A: 116.424ms
[1477336290051/255/udp4] query dns.google.com IN A: 5002.527ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
stream.js:74
throw er; // Unhandled stream error in pipe.
^
Error: ETIMEDOUT
at Timeout._onTimeout (C:\app\yyfrankyy\node_modules\request\request.js:759:15)
at ontimeout (timers.js:365:14)
at tryOnTimeout (timers.js:237:5)
at Timer.listOnTimeout (timers.js:207:5)
PS C:\app\yyfrankyy> node .\dns-over-http2\index.js
Exceed pool maxSockets, creating a new Agent
[1477336368713/23041/udp4] query dns.google.com IN A: 960.108ms
[1477336372574/279/udp4] query dns.google.com IN A: 132.970ms
[1477336376407/54035/udp4] query dns.google.com IN A: 121.612ms
[1477336379548/13914/udp4] query dns.google.com IN A: 159.797ms
[1477336380345/13784/udp4] query dns.google.com IN A: 112.050ms
[1477336382409/20190/udp4] query dns.google.com IN A: 129.664ms
Exceed pool maxSockets, creating a new Agent
[1477336387686/54992/udp4] query dns.google.com IN A: 5003.602ms
request error Error: ETIMEDOUT
request error Error: ETIMEDOUT
[1477336392686/54992/udp4] query dns.google.com IN A: 615.964ms
[1477336414340/33003/udp4] query dns.google.com IN A: 200.432ms
[1477336416037/38704/udp4] query dns.google.com IN A: 118.119ms
[1477336416917/570/udp4] query dns.google.com IN A: 180.957ms
[1477336418621/2658/udp4] query dns.google.com IN A: 158.877ms
stream.js:74
throw er; // Unhandled stream error in pipe.
^
Error: ETIMEDOUT
at Timeout._onTimeout (C:\app\yyfrankyy\node_modules\request\request.js:759:15)
at ontimeout (timers.js:365:14)
at tryOnTimeout (timers.js:237:5)
at Timer.listOnTimeout (timers.js:207:5)
If this Thing can be fixed. dns-over-http2 would become very reliable resolver now. Even Running On Laptop On Public Hotspots or Mobil Internet.
how you set port and IP if subnet shall be empty? Because subnet is first Argument and if it is „empty“ port is interpreted As subnet And IP As port?
i don't get it. If i use with defaults Index.js its Fine. But if i Want Run subnet empty and port 53 i can't ?
How about changing this behaivior To something like -e "0.0.0.0/0" -p 53 -a 127.0.0.1 for example… for future config param like padding or additional resolver when first come
i cannot Start On localhost binding IPv6 ::1
node .\index.js 0..0.0.0 6666 ::1
dnsd error: Error: bind EINVAL ::1:6666
this error i get since first Version. lookups over tcp6 Are Okay. But it does Not bind udp port when IPv6 address specified.
Nodev6.8.0
h2dns 1.0.6 does Not respect configured "-c, --pool [2] Concurrent Connections of Pool Size“
with Default or even set to 1,
it opens up to tousands of connections to forwardurl
without know howto dPool correctly, i guess it happens somewhere in state of retry to resolve on timeout and spawning New Connection into pool
{ Error: socket hang up
at TLSSocket.onHangUp (_tls_wrap.js:1092:19)
at TLSSocket.g (events.js:291:16)
at emitNone (events.js:91:20)
at TLSSocket.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:74:11)
at process._tickDomainCallback (internal/process/next_tick.js:122:9) code: 'ECONNRESET' }
running 0a851be i see 11 idle connections keep-alive to dns.google.com and for EVERY single query spawning a new connection and closing it after query answered.
spdy 3.4.4
nodejs 6.9.1
After long run for couple hours, all requests are not responding due to listeners are no longer be added.
every Minute you see
Exceed pool maxSockets, creating a new Agent
this happens because the pinginterver
`setInterval(() => {
let ping = forwardUrl + '?name=' + resolver.hostname;
request(ping).pipe(devnull());
}, 60 * 1000);`
codepart
i fixed it with following:
setInterval(() => {
const http2Req = request({
url: forwardUrl,
qs: {
name: resolver.hostname
}
}, (err, response, output) => {
agentPool.release(http2Req.agent)
})//.pipe(devnull());
}, 60 * 1000);
needed comment Out Pipe because
``
{ agent: undefined }
.\yyfrankyy\dns-over-http2\index.js:39
if (tail.agent._spdyState.connection._spdyState.goaway) {
^
TypeError: Cannot read property '_spdyState' of undefined
``
should we still use Pipe here, how?
On Start the first query is slow because delay of Agent Connection waiting created, so do it After init instantly To be ready. I removed Start delay with this:
const ping = function(){
const http2Req = request({
url: forwardUrl,
qs: {
name: resolver.hostname
}
}, (err, response, output) => {
agentPool.release(http2Req.agent)
})//.pipe(devnull());
}
setInterval(function(){
ping()
}, 60 * 1000)
ping()
Run once started and every Minute As used To before. Opens a ready To use Agent directly. Check Benefit by Compare Response Milliseconds of first query ;-)
If the DNS Client TCP Connection is Reset for any reason After query, h2dns 1.0.6 quits with:
``events.js:182
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at exports._errnoException (util.js:1026:11)
at TCP.onread (net.js:607:25)
``
node v8.0.0
node .\h2dns -t 5000
node .\h2dns --timeout 5000
TypeError: "msecs" argument must be a number
at Object.exports.enroll (timers.js:298:11)
at Socket.setTimeout (net.js:330:12)
at ClientRequest.<anonymous> (_http_client.js:642:10)
at emitOne (events.js:101:20)
at ClientRequest.emit (events.js:188:7)
at tickOnSocket (_http_client.js:567:7)
at onSocketNT (_http_client.js:579:5)
---------------------------------------------
at ClientRequest.setTimeout (_http_client.js:641:8)
at Request.start (C:\app\yyfrankyy\node_modules\request\request.js:773:16)
at Request.end (C:\app\yyfrankyy\node_modules\request\request.js:1398:10)
at end (C:\app\yyfrankyy\node_modules\request\request.js:567:14)
at Immediate.<anonymous> (C:\app\yyfrankyy\node_modules\request\request.js:581:7)
at runCallback (timers.js:637:20)
at tryOnImmediate (timers.js:610:5)
at processImmediate [as _immediateCallback] (timers.js:582:5)
parseInt?
google sets it "RA": true, // Always true for Google Public DNS
But dnsd false overwrites
https://github.com/yyfrankyy/dns-over-http2/edit/master/dnsd/convenient.js#l42
can be configured with
https://github.com/yyfrankyy/dns-over-http2/edit/master/dnsd/README.md#l244
i get typeerror .defaults is not a function :-(
please can set somehow dnsd.defaults({convenient: false})
changing https://github.com/yyfrankyy/dns-over-http2/edit/master/dnsd/convenient.js#l42 To true also works..
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.