lucagrulla / node-tail Goto Github PK
View Code? Open in Web Editor NEWThe zero dependency Node.js module for tailing a file
Home Page: https://www.lucagrulla.com/node-tail/
License: MIT License
The zero dependency Node.js module for tailing a file
Home Page: https://www.lucagrulla.com/node-tail/
License: MIT License
Possibly related to #22 and #8.
Expected data:
{ line1 }
{ line2 }
Received data:
"" (empty line)
{ line1 }{ line2 }
I think this happens due to the asynchronous nature of fs.ReadStream
used to read the portion of the file:
{ line1 }
\n
which belongs to { line1 }
{ line2 }\n
However, the stream.on 'data'
for 2. executes before the ones for 1. and 3.
This is possible to fix by using fs.openSync / fs.readSync / fs.closeSync
instead of the asynchronous fs.ReadStream
API.
Npm won't install this package if you have v0.8 of node. I think it works fine, it's just the package.json that needs to be updated to allow for the new version of Node.
Problem: I have a file being constantly written to, I'm using node-tail to watch this file and I'm piping the data through a socket to the front end. Unfortunately instead of receiving the latest appended information I'm receiving everything.
a very basic example (I'm not using a socket here, just console to log out the results):
const Tail = require("node-tail").Tail;
const tail = new Tail(file);
tail.on("line", data => console.log(data));
I am using tail on a nodejs express server, to continuosly watch at a log file. Every time a line is added, I send a socket event to the browser client to add the line to a div.
Is there any resource/memory problem in leaving tail always on?
Thanks.
A module shouldn't write to console, ever. This is a very bad practice, I encourage to remove all calls to console.
i have a log.txt file with a prefix date, i want to use node.js to monitor the log.txt file changed line in real time, how to set parameter or other method to tail the 2018-09-15-log.txt file? everyday i only want to tail the current day's log file, thanks
Hi, I was wondering if there was a reason that node-tail uses fs.watch
instead of fs.watchFile
. Is it for cross-platform compatibility reasons? I recently had to implement file tailing using inotify (and thus watch
), and I would be happy to contribute toward a watch
based node-tail, but I wasn't sure if you intentionally went with watchFile
.
Either way, thanks for your work, it was very helpful for me to learn from.
Here's a suggestion:
stream.on 'data', (data) =>
@buffer += data
if @separator is ''
# just send the whole buffer
# (without this condition it buffers the last character)
@emit("line", @buffer) # "data" event to be more precise
@buffer = ''
else
# buffer anything after the last separator
# (and don't send the separators)
parts = @buffer.split(@separator)
@buffer = parts.pop()
@emit("line", chunk) for chunk in parts
I have 2 tail objects, 1 pointing to a text file on a local drive and another pointing to a text file sitting on a NFS filesystem.
The first tail (local drive) calls the tail.on() event but the second tail (on nfs) does not call tail.on()
any suggestions or a workaround?
Can we get a new release on npm? I'm looking specifically for the fix commited in 3791355 for the unreferenced var "e".
When I run my server, the tail.on() callback won't trigger. If I open a file (mIRC log files, regular text files with Unix line endings) in a text editor (notepad++), while the server is running, and continue to reload the file in notepad as it is updated by mIRC, the callback will fire for all new lines since my last reload. But I can't seem to get it to trigger outside of this. Any ideas?
Hi all, just wondering what the advantages of this library are, over this code:
const cp = require('child_process');
module.exports = function(file){
const n = cp.spawn('tail',['-f',file]);
n.on('error', function(err){
console.error(err.stack || err);
});
return n.stdout;
};
Please let me know, thanks
I have a use case where I get the name of the file that I need to tail shortly after the first line is already written due to how my external library is designed. With node-tail, I currently have no way to read the very first line in this case, since from node-tail's point of view, the timestamp of the file hasn't changed (or no inode event is fired yet) when I first call watch().
Will you provide a capability to force node-tail to tail the file including what's already been written before watch() is called? I know this isn't really the functionality of the "tail", but I think it would be quite useful.
I'm using node-tail to tail my access logs which have a high update frequency. But under this load node-tail reports many incorrect lines that start at the middel of the actual line. Any idea what causes this?
What I'm actually doing is reading the logfile from a game. Tail will never detect the changes (and the latest added lines) in the logfile unless I manually open it (with anything that adds an EOL).
However, it seems to work fine on Mac OS.
Digging a bit, if node-tail
is using fs.watch
, this issue may be due to this (from NodeJS docs):
On Windows systems, this feature depends on ReadDirectoryChangesW.
This may be due to the game not trigerring a ReadDirectoryChangesW
when editing the logfile.
fs.js:797
return binding.stat(pathModule._makeLong(path));
^
Error: ENOENT, no such file or directory '../storage/logstash/20151215-fpm-fcgi.log'
at Error (native)
at Object.fs.statSync (fs.js:797:18)
at new Tail (/home/forge/www/client1/logwatch/node_modules/tail/tail.js:67:16)
at /home/forge/www/client1/logwatch/server.js:32:16
at Array.forEach (native)
at Object.<anonymous> (/home/forge/www/client1/logwatch/server.js:30:3)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
touch
this file first. I'm a little new to streams and tails. Is that the recommended action?If file watched deleted, node will exit with exception and can't be catched outside
fs.js:954
return binding.stat(pathModule._makeLong(path));
^
Error: ENOENT: no such file or directory, stat '/tmp/1234.csv'
at Object.fs.statSync (fs.js:954:18)
at Tail.watchEvent (/opt/JAICAS/node_modules/tail/lib/tail.js:123:18)
at FSWatcher.<anonymous> (/opt/JAICAS/node_modules/tail/lib/tail.js:105:24)
at emitTwo (events.js:106:13)
at FSWatcher.emit (events.js:192:7)
at FSEvent.FSWatcher._handle.onchange (fs.js:1367:12)
This is caused by
https://github.com/lucagrulla/node-tail/blob/master/src/tail.coffee#L62
you can simply fix it with try/cache or check file exist before fs.statSync(this.filename);
On line 48: it's fsWatchOptions, not watchOptions
https://github.com/lucagrulla/node-tail/blame/master/README.md#L48
Can we have a last position on unwatch from where we can resume if we re watch the file again?
This feature will help in making the system fault tolerant. Please look into this.
I want to get this to work but seem unable to.
console.log only outputs the first character of the line first time I update the file.
And the second time a new line is written it writes out thousands of console.logs (for each line)
I tried to use useWatchFile: true and it does not spew out thousands of lines (using Windows). But the "data" is empty.
I am suspecting an encoding issue. Please add option to specify encoding.
I am trying to tail a UTF-16le encoded file.
I can't figure how to pass this argument.
I tried by fsWatchOptions
but I think it's just the filename encoding, not the file content.
I apologize if I'm misunderstanding the purpose of this library, but currently if I'm tailing a file and create a new line, it will tail from the beginning by default. Even if I set the option fromBeginning
to false this remains. This is the code I'm currently using:
Tail = require('tail').Tail;
tail = new Tail("fileToTail.txt", {fromBeginning: false});
tail.on("line", function(data) {
console.log(data);
});
tail.on("error", function(error) {
console.log('ERROR: ', error);
});
Could you please add an option for tailing the last few lines? Perhaps replace 'fromBeginning' with 'lastLines' or something, that takes either an int value, or 'true' or something, which is a special value which means from beginning.
I noticed you are missing a license... what is this licensed under?
i.e. I want to watch all ".txt" files under a specified directory
I want to write something like this
tail = new Tail({dir: "~", glob: "*.txt"})
tail.on 'line', (data, file_path) ->
console.log data, file_path
And expecting that the file creating event is automaticly handled and new files that matching the glob option will be auto watched.
Hi, I have encountered a problem using this module on a Linux kernel that does not support inotify, because fs.watch
does not work without it. The module always uses fs.watch
if available in the node API, and I am using the node v4 so this is always the case.
This change has come from #7 which states that fs.watchFile
is deprecated, however this is not true - the documentation simply states to use fs.watch
where possible.
Note: fs.watch() is more efficient than fs.watchFile and fs.unwatchFile. fs.watch should be used instead of fs.watchFile and fs.unwatchFile when possible.
I don't think there's any simple, clean way to test whether fs.watch
is going to work. At the moment the best solution I can think of would be to allow the user to provide an option/flag to force the use of fs.watchFile
rather than fs.watch
.
The documentation for fs.watch contains various other caveats around its use so a providing an override would benefit anyone using this module on a system that cannot support its requirements, not just my problem with a lack of inotify support.
Cheers.
If you want to stop tail:
tail.unwatch()
It seems that the current version expects tail.close()
instead.
Tried the README example then edited my "foobar.txt" file and nothing happened.
Hi,
great work with tail!
I get the following error when trying to use the package within an Electron application:
Error: ./node_modules/tail/lib/tail.js [0] Module parse failed: Unexpected token (66:126)
It is probably something to do with my webpack config, but I haven't been able to figure out what's wrong.
Line 66 in tail.js looks like this:
({separator: this.separator = /[\r]{0,1}\n/, fsWatchOptions: this.fsWatchOptions = {}, fromBeginning = false, follow: this.follow = true, logger: this.logger, useWatchFile: this.useWatchFile = false, flushAtEOF: this.flushAtEOF = false, encoding: this.encoding = "utf-8"} = options);
If I split this line to one per variable it works. I guess there is some coffee script magic I don't know.
I'll continue to try to configure the webpack configuration.
package.json says:
"engines": {
"node": ">= 0.4.0"
},
Running it on Node v4:
> process.versions
{ http_parser: '2.8.0',
node: '4.9.1',
v8: '4.5.103.53',
uv: '1.9.1',
zlib: '1.2.11',
ares: '1.10.1-DEV',
modules: '46',
openssl: '1.0.2o' }
> require('tail');
/node_modules/tail/lib/tail.js:11
Tail = class Tail extends events.EventEmitter {
^^^^^
SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:373:25)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Module.require (module.js:353:17)
at require (internal/module.js:12:17)
at repl:1:1
at REPLServer.defaultEval (repl.js:272:27)
at bound (domain.js:287:14)
>
May I know how to dynamically adjust the path/log filename? Something like if the log file is dependent on the current system date eventually it changes to following day
(i.e: pathfolder/20180314_data_log.txt ---> pathfolder/20180315_data_log.txt)
Any suggestions? Thanks
Hi all,
there's no way to catch exception coming from "file not exists" error or "rename" events ?
This test crashes everytime. And I am not able to control exceptions.
var Tail = require('tail').Tail
, exec = require('child_process').exec
exec('echo hello world 0 >> file.txt')
tail = new Tail('file.txt')
tail.on("line", function(data) {
console.log(data);
});
setTimeout(function() {
exec('echo hello world 1 >> file.txt')
}, 1000)
setTimeout(function() {
exec('mv file.txt old.txt')
}, 1500)
setTimeout(function() {
echo('echo hello world 2 >> file.txt')
}, 3000)
It looks like problem comes from:
else if e is 'rename'
@unwatch()
setTimeout (=> @watch()), 1000
you may need to check if file exists before call @watch ... if it does not exist, call setTimeout and check again.
How to disable the output of options?
I currently use this code:
`var options= {lineSeparator: /[\r]{0,1}\n/, fromBeginning: false, watchOptions: {}, follow: true}
tail = new Tail("query.log", options);`
This results in:
Tail starting:
filename: query.log
options: { lineSeparator: /[\r]{0,1}\n/,
fromBeginning: false,
watchOptions: {},
follow: true }
How to disable this output?
Hi
I am using node-tail on a server with relatively high load. My app basically monitors a syslog text file that gets written with relatively high rate (about 25-35kB/s). File looks more or less like this:
2014-07-09T09:56:16+00:00 nszen3.dc1.company.net [info] postfix/smtpd: lost connection after CONNECT from unknown[10.12.109.70]
2014-07-09T09:56:16+00:00 nszen3.dc1.company.net [info] postfix/smtpd: disconnect from unknown[10.12.109.70]
2014-07-09T09:56:15+00:00 xe17-1d.dc2.company.net [notice] 897262: Jul 9 09:56:14.844 UTC: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/16, changed state to down
2014-07-09T09:56:13+00:00 aw1-1p.dc3.company.net [notice] 1724: Jul 9 09:56:15.584 UTC: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/1, changed state to down
2014-07-09T09:56:13+00:00 aw1-1.dc3.company.net [notice] 2673: Jul 9 09:56:15.622 UTC: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/1, changed state to down
2014-07-09T09:56:40+00:00 aw1-1.dc3.company.net [error] Postfix blah blah
multi
line message
2014-07-09T09:56:13+00:00 aw1-1.dc3.company.net [notice] 2673: Jul 9 09:56:15.622 UTC: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/1, changed state to down
...
The end goal is to 'split' the stream into an array of syslog messages. The logical step would be to use \n
as a separator but it does not work in this particular case because some of the messages are multi line.
I ended up writing code that looks like this:
var tail = new Tail("/opt/syslog/archive.log", "\n20")
tail.on('line', function(data) {
process_further('20' + );
}
tail.on('error', function(error) { console.log(error);});
The results are as expected vast majority of the time - I get the exact message that's supposed to be extracted. Unfortunately once every couple minutes the message gets corrupted in a funny way. process_further()
for some reason gets called with junk data in the begining of the string, for example:
2014-2014-07-09T06:03:36+00:00 478242-dhcp2.kickstart.company.com [notice] info: dhcpd: DHCPREQUEST for 10.132.29.112 (10.192.0.40) from 00:26:b9:4e:e3:07 via 10.192.28.3
or
202014-07-08T12:47:15+00:00 f4-42-1.company.net [notice] : 2014 Jul 8 12:46:19 UTC: %ETHPORT-5-IF_DUPLEX: Interface Ethernet1/34, operational duplex mode changed to Full
Please bear in mind that it happens only once every couple thousand of lines.
I have been troubleshooting this for last couple days and I am not able to find the culprit. So far I have checked following things:
\n
aka 0x0A
.if (stats.size < _this.pos) {
console.log("rewinded! stats.size=" + stats.size + " @pos=" + _this.pos + " difference(@pos-size)=" + (_this.pos - stats.size));
_this.pos = stats.size;
}
and to my surprise it was fired couple times:
rewinded! stats.size=1219983229 @pos=1219983490 difference(@pos-size)=261
rewinded! stats.size=1219983750 @pos=1219984281 difference(@pos-size)=531
I thought it is not possible, but wanted to verify anyway so I wrote short ruby script to monitor file size returned by system and produce an alert when it's rewinded:
#!/usr/bin/ruby
filename = '/opt/syslog/archive.log'
prev = 0
loop do
fsize = File.stat(filename).size
if fsize - prev < 0
alert = 'REWINDED!'
puts "size: #{fsize} prev:#{prev} diff: #{fsize - prev} #{alert}"
else
alert = ''
end
prev = fsize
abort("File rewinded, aborting") if alert != ''
sleep 0.1
end
That script has been running for last couple of hours and it never fired, so the file is not being rewinded yet for some reason node thinks it is.
Still, it does not look like it correlates with the time when messages are corrupted:
rewinded! stats.size=1219983229 @pos=1219983490 difference(@pos-size)=261
rewinded! stats.size=1219983750 @pos=1219984281 difference(@pos-size)=531
rewinded! stats.size=1226892183 @pos=1226894946 difference(@pos-size)=2763
rewinded! stats.size=1232545312 @pos=1232545481 difference(@pos-size)=169
rewinded! stats.size=1232581791 @pos=1232582488 difference(@pos-size)=697
rewinded! stats.size=1235945205 @pos=1235945374 difference(@pos-size)=169
rewinded! stats.size=1245025044 @pos=1245026503 difference(@pos-size)=1459
rewinded! stats.size=1245908859 @pos=1245909751 difference(@pos-size)=892
Problem with chunk: 014-07-09T10:48:01+00:00 dev.dc3.company.net [info] postfix/cleanup: 821A8DDD33: message-id=<[email protected]>
14-07-09T10:48:01+00:00 phase3sniffer.dc3.company.net [info] postfix/qmgr: 84FA12EC0085: from=<[email protected]>, size=1159, nrcpt=1 (queue active)
rewinded! stats.size=1263001128 @pos=1263001772 difference(@pos-size)=644
rewinded! stats.size=1270921071 @pos=1270921374 difference(@pos-size)=303
rewinded! stats.size=1274044805 @pos=1274045193 difference(@pos-size)=388
rewinded! stats.size=1276448317 @pos=1276449057 difference(@pos-size)=740
rewinded! stats.size=1276991206 @pos=1276992015 difference(@pos-size)=809
rewinded! stats.size=1277356959 @pos=1277357127 difference(@pos-size)=168
rewinded! stats.size=1289780552 @pos=1289781614 difference(@pos-size)=1062
@buffer
gets overwritten. Would it be possible if readBlock()
did not finish executing lines 11-22 but @internalDispatcher
received another next
event from watch()
?More (possibly relevant) details:
Simplest code to reproduce the problem:
var Tail = require('tail').Tail
var tail = new Tail("/opt/syslog/archive.log", "\n20")
tail.on('line', function(data) {
if(data.substr(0,2) != '14') {
console.log("Problem with chunk: " + data);
}
})
tail.on('error', function(error) { throw error })
Please note that first 'Problem' must be ignored since node-tail will start reading from a beginning of a file which is unlikely to start with \n20
.
Thanks for reading this. I would appreciate any ideas or suggestions as to what else may I try?
thanks,
Marek
I'm not entirely sure what fromBeginning is supposed to do, and there don't seem to be tests for it; but what I'm trying to do is have the tail.on('line', callback)
be fired once for each line in a given file when the on
is first registered, then call it once for each following line that is appended.
Here's what I've got:
for (const filename of files) {
let t = new Tail(filename, {fromBeginning: true});
// Each time a new line comes in, send it along
t.on("line", function(line){
console.log(line);
callback(line);
});
}
Passing the option doesn't seem to be changing anything at all, could someone please explain how it's supposed to work? Thanks!
Hello,
I'm trying to tail a file to monitor its changes, but after a while, the monitoring stops by itself. Other programs like "Notepad++" successfuls to monitor the changes and it's only when those other programs detect a change in the file that Tail "unsleeps" and detect it as well.
In short, if I monitor a file, at the begening it works perfectly well, but after a while, Tail only detect a change when the file is open by another program OR if another program checks if the file has changed.
What could cause this problem?
Thank you in advance!
Add the filename(optionnal) in the callback event in addition to the data
I am attempting to tail a very fast log files (100+ lines/sec). I'm having a problem where 75% of lines are being dropped when using watch. When using watchFile about 5% of lines are dropped. It seems this library has a bug with very fast updates. There are some other related issues open as well regarding this. I'd love to see this bug fixed.
The following library seems to handle this situation without dropping any lines if it helps:
https://github.com/Juul/tail-stream
How do you configure this to tail a binary file ?
I have a process that appends chunks of binary characters to a file. I can't use a separator to split them as that would remove the split char (and indeed any char I choose as a separator may be present elsewhere in the chunk). Ideally I just want the new chunk passed through as-is, and preferably as a Buffer, not a string. Is this possible ?
Or maybe an option to always send the last chunk on close ? That way I could (hopefully) set a separator that would never match, and on close it would send what was the remaining buffer.
i use tail to focus on a file, when i push about 10,000 messages to the file, the function(data) may return a messy message, then i have to handle this exception:
error: SyntaxError: Unexpected token Z
content: Z],用户[2108420],道具ID[54],道具名称[1分钟加速],道具增加[1]."}
the message should be a json like:
content: {"message": "时间[2015-08-14T13:48:37Z],用户[2108420],道具ID[54],道具名称[1分钟加速],道具增加[1]."}
I checked this exception happen in tail.on(), so what could i do next? how to fix it?
🐎
Hello!
I've already added my comment here #8
I'm experiencing this issue when line
event is receiving corrupted lines from time to time. Initial log file have correct lines. I came across with this in production with log file that gets around 3-5 large lines per second (depending on the time of the day).
To reproduce this I made simple example that can be found here:
https://github.com/megamk/log-tail-emulation
If the file to-be-tailed doesn't exist, this will error, but that error can't be handled because watch
is called from within the constructor, before the client's had a chance to register an 'error'
event handler.
I'd be glad to put up a PR to fix this but I'm not sure what fix you'd prefer. My inclination is to call watch
asynchronously (i.e. change this to process.nextTick(=> @watch(pos))
, except for that that'll break the tests since they expect node-tail
to catch synchronous writes (which is easy enough to change except for that maybe that signals that such a change would break some client code too).
Alternatively we could have watch
throw
that fs.statSync
error rather than emit
it, except for that that's inconsistent with other error handling in the module and we'd have to change this to handle that change somehow.
Hello everybody!
I'm trying to install the tail however I am getting an error message. Someone has gone through this problem at install time?
root@pc:~# npm install tail
npm http GET https://registry.npmjs.org/tail
npm ERR! Error: failed to fetch from registry: tail
npm ERR! at /usr/share/npm/lib/utils/npm-registry-client/get.js:139:12
npm ERR! at cb (/usr/share/npm/lib/utils/npm-registry-client/request.js:31:9)
npm ERR! at Request._callback (/usr/share/npm/lib/utils/npm-registry-client/request.js:136:18)
npm ERR! at Request.callback (/usr/lib/nodejs/request/main.js:119:22)
npm ERR! at Request. (/usr/lib/nodejs/request/main.js:212:58)
npm ERR! at Request.emit (events.js:88:20)
npm ERR! at ClientRequest. (/usr/lib/nodejs/request/main.js:412:12)
npm ERR! at ClientRequest.emit (events.js:67:17)
npm ERR! at HTTPParser.onIncoming (http.js:1261:11)
npm ERR! at HTTPParser.onHeadersComplete (http.js:102:31)
npm ERR! You may report this log at:
npm ERR! http://bugs.debian.org/npm
npm ERR! or use
npm ERR! reportbug --attach /root/npm-debug.log npm
npm ERR!
npm ERR! System Linux 3.11.0-15-generic
npm ERR! command "node" "/usr/bin/npm" "install" "tail"
npm ERR! cwd /root
npm ERR! node -v v0.6.12
npm ERR! npm -v 1.1.4
npm ERR! message failed to fetch from registry: tail
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR! /root/npm-debug.log
npm not ok
By default Tail tries to use fs.watch
and only as alternative fs.watchFile
.
Although fs.watch
is the suggested approach it is platform dependent and shows different behaviours in certain scenarios. Add a flag in the options map to allow the explicit choice of the strategy so that the consumer can pick a slower but sometime more reliable tailing strategy
A standard npm install tail
won't include the main file compiled to JS, just tail.coffee
. Is it just me, or maybe the publishing somehow failed?
I came across a problem, when watching a log file which rotates once in a while. After the rotation happens (the currently tailed file gets renamed, and a new file with the same name is created) - tail stops getting the updates.
Looking at the source code, seems like it should take care of it (by capturing the rename
event). But apparently it just doesn't work for me, and it simply stops tailing the file. I monitor a pm2 log file.
Are there any workaround to solve that problem?
Is it possible to specify the number of lines from the tail of the file to be included in the response before watching? As with tail -n
Hi, thank you for the recent bug fix for fromBeginning. I've noticed that the behaviour only delivers the content when the first change was noticed.
Expected behaviour (At least, from my perspective) would be that it would deliver the existing contents of the file as soon as the stream is opened. Is this correct?
Cheers,
Nathan
so the tail is by filename.
I understand that the rename event can catch the renaming of the "old" file, but how do I then continue the tail on the "new" file ?
Hi, I've installed [email protected] but the optional logger
parameter functionality seems to be missing from this release.
I've verified my installed version is 1.1.0 by checking the version in node_modules/tail/package.json
and looked at the JS file lib/tail.js
which still contains these lines:
console.info("Tail starting:");
console.info("filename:", this.filename);
console.info("options:", options);
Maybe there was an issue with the publish.
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.