eclipse-ee4j / grizzly Goto Github PK
View Code? Open in Web Editor NEWGrizzly
Home Page: https://eclipse-ee4j.github.io/grizzly
License: Other
Grizzly
Home Page: https://eclipse-ee4j.github.io/grizzly
License: Other
A written tutorial on how to integrate the FindBugs plug-in for
NetBeans IDE and run it from within NetBeans IDE 6, (Note: the FindBugs
plug-in may not operational in NetBeans IDE 6).
Operating System: All
Platform: All
[1.9.22]
The examples build does not follow Maven 2 best practices.
Since GF uses Maven 2 so should the examples.
Operating System: All
Platform: Macintosh
[1.9.22]
The OutputWriter class is intended to wait up to 1 minute (default wait time)
for output space to be available to complete writing the data. In an HTTP mode
(or for similar protocols), that works just fine.
For protocols (like SIP) where multiple threads are writing to the same socket,
buffer contention will cause OutputWriter to report an error prematurely. Say
there are 10 threads writing on the socket that fills up; all 10 will get a
selector and enter the select() call. When the socket buffer empties, all 10
will get notified that they can write data, and all will attempt to write their
data – but while the socket is still draining, it's likely that only 1 will
succeed and the remaining will write 0 bytes again. If this process is repeated
twice, the remaining sockets will give up (based on the attempts value in
OutputWriter) and close the socket. This entire process takes only a few
milliseconds, since during that time there will be two successful writes.
The async queueing model should take this into account, or we should develop a
selector-per-socket model such that only one thread can wake up from the select
at a time.
Operating System: All
Platform: All
The result of SelectorThread.getKeepAliveStats().getCountConnections() never decreases when
connections are closed, so instead of returning the current number of open connections, it returns the
total number of connections over the full lifetime of the application.
From the implementation, it seems we are missing the logic to decrease the count:
public boolean trap(SelectionKey key){
if ( maxKeepAliveRequests == -1) return true;
Integer count = keepAliveCounts.get(key);
if ( count == null ){
count = 0;
if (keepAliveStats != null)
{ keepAliveStats.incrementCountConnections(); }
}
if ((count++) > maxKeepAliveRequests){
if (keepAliveStats != null)
{ keepAliveStats.incrementCountRefusals(); }
return false;
}
keepAliveCounts.put(key, count);
if (keepAliveStats != null)
{ keepAliveStats.incrementCountHits(); }
return true;
}
/**
Inside the untrap(..), we must decrease the count. Can you file a bug here:
Operating System: All
Platform: All
[1.9.22]
life cycle of a SelectionKey. Operations like cancelling,
double ll in canceling
Operating System: All
Platform: All
Right now modules http & utils have dependencies on
com.sun.org.apache.commons.logging|modeler. This was a requirement when Grizzly
was bundled in GlassFish, but now it should be removed and we should instead
uses package from Apache itself.
Operating System: All
Platform: All
[1.9.22]
Grizzly uses two different approaches in hanlding nio selector's OP_READ,
OP_WRITE, OP_CONNECT... events. One approach is by having a callback handlers on
the client side and the other one is using filters on the serverside.
I had compared this design with a typical AWT/SWING event handling. Using
callback handling seems like a very efficient of handling selector events. That
means, we will have a callback to be invoked upon occurring of particular
selector event. This also helps Grizzly developer to just define what needs to
be done upon a particular event and then, handle the rest of undelying taks of
register/deregister of the channel with the selector to Grizzly. The only
difference from AWT/SWING is, here in Grizzly we should be able to process
multiple events at the same time in multiple threads.
Operating System: All
Platform: Sun
The current jruby jars doesn't allow the addition of extra library (like mySql
driver). This need to be fixed.
Operating System: All
Platform: All
[1.9.22]
There are no junit tests in the comet package
Operating System: All
Platform: Macintosh
[1.9.22]
SelectorHandlerRunner.java::run
while (controller.state == State.STARTED) {
– cut –
// State changed inside the loop
if (controller.state != State.STARTED)
{ break; }
– cut –
no need to check controller.state twice, its checked every time at top of loop.
Operating System: All
Platform: All
Please note the below references in the following description of the problem.
Ref A: Controller.java : doSelect(..) method
Ref B: Context.java : call(..) method
Ref C: TCPSelectorHandler.java : onReadInterest(final..)
Ref D: TCPSelectorHandler.java : onWriteInterest(final..)
Also note that, unless otherwise one overrides any of Grizzly's classes.., by
default, Grizzly uses filters on the Serverside (say for reading) and Callback
handlers on the client side. (Ref.issue 41).
Now take the case of a serverside reading..
During the time of doSelect() as in (A), say the given channel is ready to
read, so, the program controll goes to (C) from line:342(A) and since there is
no callback handler (since it's serverside) it returns true (which delegate to
worker thread boolean).. in (A) line:363.. Now, Grizzly invokes the protocol
chain. This is fine and no problem here. Say the next cycle of doSelect(A)
(since there is while loop) the event is not OP_READ but it's OP_WRITE.. the
program control goes "happily" to (D) and returns true from there. Which means
to delegate work to workere thread that's line:363(A) Now, Grizzly goes and
invokes the protocol chain and hence the read filter at the WRONG time.
Now, if there is protocol filter that's tied to a protocol parser for reading
(supporting) a sepecific protocol, it will definetely thinks that, there is data
that's going to come for parsing, since Grizzly invoked Read filter at the wrong
time. But since, no data is expected, zero bytes are read and given to the
parser to parse. If the parser is very smart, it thinks that, this current read
op has Zero fresh bytes, that's because, this is an unsuccessful read() and so,
it tells the parser to expect more data as the channel is ready to read.
Actually, the channel is NOT ready to read at that point of time.
What all this tells is, (from Ref(A)), Of OP_READ, OP_WRITE, filters get
executed all the time.
That's all I noted.
Have fun!
-Harsha
Operating System: All
Platform: Sun
I'm filing this issue to track the earlier discussion around exception handling
around read or any other similar filters in Grizzly. Here is detail description
of the problem, in the email archive :
https://grizzly.dev.java.net/servlets/ReadMsg?list=dev&msgNo=680
The scenario is, when an exception happens (say, a connection error, or a parser
error while parsing..) the developer of Grizzly would like to take some
definitive action in the application. This requirement applies to both server
and client side.
Its a good idea to have a callback mechanism (or event handling /listeners) to
register for a specific exceptions and then pass them to the registered objects
for action upon their occurrence.
Operating System: All
Platform: Sun
[1.9.22]
A written tutorial on how to use Grizzly's connection caching
including a run-able example.
Operating System: All
Platform: All
Please consider this for future, if this is not possible now.
Operating System: All
Platform: Sun
[1.9.22]
At present in Grizzly, we can not do multiplexing on a given channel. Take a
scenario where a single channel is used by multiple clients (one-2-many) to send
and receive information. Grizzly assumes that, only one client can send (write)
data at any given time. Well, practically, it's not true. For example, in Corba,
multiple threads /clients can send data to the server side at the same time, on
the same channel. One way to handle this problem is, to implement locking at
the protocol level. The otherway is to take care of this in transport layer
itself and making it transperent to the Grizzly developer. (who uses Grizzly to
develop his/her applications)
Operating System: All
Platform: Sun
The catalog https://sqe.dev.java.net/updatecenters/sqe/catalog.xml should use
DTD 2.5 to be supported in NetBeans 6.0 Beta 1.
The current catalog uses version 3.0 which causes that users of NetBeans 6.0
Beta1 can see empty list while connected to this update center. So that plugins
cannot be installed.
Operating System: All
Platform: All
[1.9.22]
Needs to enable SSL with http module in 1.5 using the framework classes from 1.5.
Operating System: All
Platform: All
[1.9.22]
I grabbed the HTTP part of grizzly today and pulled out what I had done
previously against the 1.0 version to port to 1.5-SNAPSHOT. Where before I had:
public static void main(String[] args) throws IOException,
InstantiationException
{
SelectorThread sel = new SelectorThread();
sel.setPort(8002);
sel.setAdapter(new MyAdapter());
final AsyncHandler handler = new DefaultAsyncHandler();
handler.addAsyncFilter(new AsyncFilter()
{
public boolean doFilter(final AsyncExecutor executor)
{
final AsyncTask asyncTask = executor.getAsyncTask();
final AsyncHandler asyncHandler = executor.getAsyncHandler();
final DefaultProcessorTask processorTask =
(DefaultProcessorTask) executor.getAsyncTask().getProcessorTask();
processorTask.getRequest().setAttribute(CALLBACK_KEY, new
Runnable() {
public void run()
{ asyncHandler.handle(asyncTask); }
});
processorTask.invokeAdapter();
return false;
}
});
sel.setAsyncHandler(handler);
sel.setEnableAsyncExecution(true);
sel.setDisplayConfiguration(true);
sel.initEndpoint();
sel.startEndpoint();
}
and an adaptor:
class MyAdapter implements Adapter
{
static byte[] CONTENT;
{ CONTENT = ByteChunk.convertToBytes("hello world!\n"); }
private static final ScheduledExecutorService exec =
Executors.newScheduledThreadPool(2);
public void service(final Request req, final Response res) throws Exception
{
System.out.println("got request");
exec.schedule(new Callable() {
public Void call() throws Exception
{ res.setStatus(200); byte[] bytes = CONTENT; ByteChunk chunk = new ByteChunk(); res.setContentLength(bytes.length); res.setContentType("text/plain"); chunk.append(bytes, 0, bytes.length); res.doWrite(chunk); System.out.println("sending resposne!"); Async.commit(req); return null; }
}, 10, TimeUnit.SECONDS);
}
public void afterService(Request req, Response res) throws Exception
{ req.action( ActionCode.ACTION_POST_REQUEST , null); }
public void fireAdapterEvent(String type, Object data)
{
}
}
Which would correctly respond in 10 seconds, now it responds with nothing
immediately, and 10 seconds later attempts to respond but doesn't actually do
anything (also logging no error).
Any guidelines on how to do ARP with the new code?
Operating System: All
Platform: All
[memcached-1.0]
One of http module unit test fails with exception:
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
Operating System: All
Platform: All
[1.9.22]
This bug is another compatibility issue. And is minor, but is valid as far as
public APIs are concerned. The method
TCPConnectorHandler.java: public void finishConnect(SelectionKey key){}
is changed from its type. The old version does not throw an exception.
But the new one throws throws IOException.
My application which was running earlier on prior version of Grizzly, needed to
be modified to compile and run against v1.6.1.
This change came from:
r490, line 425 | r508, line 429
SelectionKey
public void finishConnect(SelectionKey key) throws IOException{
thanks..
Operating System: All
Platform: Sun
Test platform:
JRuby 1.1RC1
Rails 2.0.2
To reproduce:
1. rails grizzly-jruby-test
2. go to grizzly-jruby-test directory and rake rails:freeze:gems
3. java -jar grizzly-jruby-1.7-snapshot.jar .
Error message:
2008. 1. 10 ???? 12:00:15 com.sun.grizzly.standalone.StaticResourcesAdapter
????: New Servicing page from:
/Volumes/FLASHBACK/workspace/grizzly-jruby-test/public
Exception in thread "pool-1-thread-1" 2008. 1. 10 ???? 12:00:23
com.sun.grizzly.standalone.StaticResourcesAdapter
????: New Servicing page from:
/Volumes/FLASHBACK/workspace/grizzly-jruby-test/public
/Volumes/FLASHBACK/workspace/grizzly-jruby-test/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:499:in
require': no implicit conversion from nil to integer (TypeError) from ./config/../vendor/rails/railties/lib/initializer.rb:155:in
require_frameworks'
from ./config/../vendor/rails/railties/lib/initializer.rb:88:in each' from ./config/../vendor/rails/railties/lib/initializer.rb:156:in
require_frameworks'
from ./config/../vendor/rails/railties/lib/initializer.rb:88:in process' from ./config/../vendor/rails/railties/lib/initializer.rb:49:in
send'
from ./config/../vendor/rails/railties/lib/initializer.rb:49:in `run'
from ./config/environment.rb:58
from javasupport:46
...internal jruby stack elided...
from org.jruby.Ruby.loadScript(Ruby.java:1185)
from org.jruby.runtime.load.ExternalScript.load(ExternalScript.java:53)
from org.jruby.runtime.load.LoadService.smartLoad(LoadService.java:307)
from org.jruby.runtime.load.LoadService.require(LoadService.java:333)
from
com.sun.grizzly.jruby.RubyObjectPool.loadRubyLibraries(RubyObjectPool.java:168)
from com.sun.grizzly.jruby.RubyObjectPool$1.run(RubyObjectPool.java:135)
from
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
from
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
from java.lang.Thread.run(Thread.java:637)
Operating System: All
Platform: All
[1.9.22]
From the community, fyaoxy "at" gmail.com, a patch contribution for
com.sun.grizzly.util.OutputWriter.java
Index:
F:/svn/grizzly/modules/grizzly/src/main/java/com/sun/grizzly/util/OutputWriter.java
===================================================================
—
F:/svn/grizzly/modules/grizzly/src/main/java/com/sun/grizzly/util/OutputWriter.java
(revision 394)
+++
F:/svn/grizzly/modules/grizzly/src/main/java/com/sun/grizzly/util/OutputWriter.java
(working copy)
@@ -86,14 +86,13 @@
try {
while ( bb.hasRemaining() ) {
int len = socketChannel.write(bb);
attempts++;
if (len < 0) { - throw new EOFException(); - }
bytesProduced += len;
if (len == 0) {
else {
if ( writeSelector == null ){
writeSelector = SelectorFactory.getSelector();
if ( writeSelector == null)
{ @@ -111,8 +110,7 @@ }
else
{ attempts--; }
} else { - attempts = 0; + //handle write count = 0 end; }
}
} finally {
Operating System: All
Platform: All
[1.9.22]
On JRuby 1.1(RC1) and Rails 2.0(.2),
suppose "hpricot" gem is installed within JRUBY_HOME and
environment.rb has
require "hpricot", then the following error comes up:
Exception in thread "pool-1-thread-1" ./config/environment.rb:15: no such file
to load – hpricot (LoadError)
from :1
...internal jruby stack elided...
Copying "hpricot" gem into vendor/gems doesn't work either.
Operating System: All
Platform: All
At present, Grizzly frameworks TCPSelectorHandler(..) construct has a boolean
as an argument to tell if that particualr transport handler is going to be on
the client side or not. This is not clear to user when he reads someone code.
My suggestion would be to make it really distinguishable part on the
TransportHandler.
For example, you could say, TCPServerSideHandle() and TCPCliendSideHandler()
or TCPSelectorHandler.setRole(Role.AsServer);
TCPSelectorHandler.setRole(Role.AsClient);
thanks...
Operating System: All
Platform: Sun
[1.9.22]
The feature needs to be re-implemented using the framework classes from 1.5
because right now configuring the value has no effect. Should be simple based on
Alexey's work.
Operating System: All
Platform: All
[1.9.22]
This is about:
interface ConnectorHandlerPool.java
and it's implementor DefaultConnectorHandlerPool.java
First of all the word "Pool" gives an impression to the user of this framework
that, this class is POOL of ConnectorHanlders which is definetely not the case
here. All that this class and it's interface do is to provide impelemenation for
aquring a connection and release a connection (I guees from a pool or linked
concurrent queue).
This name toooo confusing. ConnectionPoolManager.java
Here are some suggestions:
for the interface:
Operating System: All
Platform: Sun
[2.0.0]
This is a place holder for a tutorial contribution to show how to get and build
the project grizzly source code using Meven IDE. Adam Dutson has volunteered
to create this tutorial. Thanks Adam!
Operating System: All
Platform: All
[1.9.22]
// Selector.select() invokation.
invocation
Operating System: All
Platform: All
Hello,
In the grizzly http, the "0\r\n\r\n" ending for a HTTP message is not send in a
seperate chunk but appended to the last data chunk.
Here is a more visual explenation:
chunk 1 <<
HTTP/1.1 200 OK
Transform-Encoding: chunked
.. other headers
1234
hello world
0
end chunk 1 <<
chunk 1 <<
HTTP/1.1 200 OK
Transform-Encoding: chunked
.. other headers
1234
hello world
end chunk 1 <<
chunk 2 <<
HTTP/1.1 200 OK
Transform-Encoding: chunked
.. other headers
0
end chunk 2 <<
Other HTTP servers send the "0\r\n\r\n" in a seperate (as the last) chunk.
As far as I got from the HTTP spec it is supposed to be like that.
Operating System: All
Platform: All
[1.9.22]
UDPSelectorHandler.java
This class represent a UPD implementation
Operating System: All
Platform: All
We use log4j in our application to do the logging. And we have some
standard format defined for the log file. What is the best way to
pipe the Grizzly logs to log4j other than changing the source code of
Grizzly?
Operating System: All
Platform: All
[1.9.22]
A written tutorial on how to integrate the FindBugs plug-in for
NetBeans IDE and run it from within NetBeans IDE 5.5 / 5.5.1.
Operating System: All
Platform: All
[1.9.22]
public void realWriteBytes(byte cbuf[], int off, int len)
throws IOException {
if (len > 0) {
if (len > outputByteBuffer.remaining())
{ ByteBuffer tmp = ByteBuffer.allocate( outputByteBuffer.capacity() * 2 + len); outputByteBuffer.flip(); tmp.put(outputByteBuffer); outputByteBuffer = tmp; }
outputByteBuffer.put(cbuf, off, len);
}
}
if position + len is bigger than capacity * 2, outputByteBuffer overflows.
Operating System: All
Platform: All
[1.9.22]
There are no JUnit tests in the cometd package.
Operating System: All
Platform: Macintosh
[1.9.22]
By default, the Grizzly Framework bundle default implementation for TCP and UPD
transport.
Operating System: All
Platform: All
[1.9.22]
Grizzly v1.6.1/0 onwards:
Grizzly ignores the TCP selection handlers added if the controller is
already started. In the old versions this is not a problem.
Here is a TENTATIVE fix: In Controller.java:
public void addSelectorHandler(SelectorHandler selectorHandler){
if (selectorHandlers == null)
{ selectorHandlers = new ConcurrentLinkedQueue(); }
selectorHandlers.add(selectorHandler);
if (isStarted())
{ Runnable selectorRunner = new SelectorHandlerRunner(this, selectorHandler); new Thread(selectorRunner).start(); }
}
Operating System: All
Platform: Sun
ConcurrentLinkedQueue getSelectorHandlers()
Return the first SelectorHandler
instead of return first, should be most likely returns all
Operating System: All
Platform: All
The Controller start method can be split into many segments.
One idea is, to create all defaults in a method called init()
and the selector handler for loop in a different method
and much more..
this way, the controller.start() method looks simpler and easy to understand for
the develoer who is using Grizzly.
Operating System: All
Platform: Sun
[1.9.22]
There are set of applications which do not require the expiring of
SelectionKeys, (i.e. require keep alive). See Controller.doSelect(), which does:
iterator = readyKeys.iterator();
long currentTime = System.currentTimeMillis();
while (iterator.hasNext() && selectorHandler.isOpen())
{ key = iterator.next(); selectionKeyHandler.expire(key,currentTime); }
A possible solution to this issue is to move the above logic into the
TCPSelectorHandler.postSelect() method, which is currently empty.
Then, create a new class that implements SelectorHandler interface which is
called NonExpiringTCPSelectorHandler which would take on all the methods of the
TCPSelectorHandler with the exception of the TCPSelectorHandler.postSelect().
postSelect() should be empty for the NonExpiringTCPSelectorHandler. Then, the
TCPSelectorHandler should extend NonExpiringTCPSelectorHandler and have one
method in it. The override of postSelect() method which contains the expiring
of keys logic above.
For those applications which do not need to expire keys, they would configure
the Controller to use the NonExpiringTCPSelectorHandler. This could be done at
the Grizzly configuration setup time by doing something like:
Controller sel = new Controller();
SelectorHandler selectorHandler = new NonExpiringSelectorHandler();
// set any additional items on the SelectorHandler
sel.setSelectorHandler(selectorHandler);
sel.setProtocolChainInstanceHandler(new DefaultProtocolChainInstanceHandler(){
public ProtocolChain poll() {
ProtocolChain protocolChain = protocolChains.poll();
if (protocolChain == null)
{ protocolChain = new DefaultProtocolChain(); protocolChain.addFilter(new ReadFilter()); protocolChain.addFilter(new HTTPParserFilter()); }
return protocolChain;
}
});
This proposed resolution would also not break the SSLSelectorHandler or
UDPSelectorHandler as they are currently implemented. However, if there are SSL
or UDP applications out there which do not need to "expire keys", then a similar
resolution will need to be implemented as well since both SSLSelectorHandler
and UDPSelectorHandler extend TCPSelectorHandler.
Other applications which need expiring of keys would continue to work as they do
today. No changes would be required since the TCPSelectorHandler is the default
SelectorHandler and its functionality would not change.
Operating System: All
Platform: All
[1.9.22]
SelectorHandler
s, which stopedstopped
Operating System: All
Platform: All
canceling
/**
ConnectorHandler
based on therequested
/**
SelectorHandler
s willstopped
Operating System: All
Platform: All
/**
describing
Operating System: All
Platform: All
Ar present, TCPSelectoHandler().. forces the user to create a socket first and
then supply it to the connect(..) method.
Instead, its much easier and simple to just accept "host" and numeric 'port'
from user then constuct the InetSocketAddress internally in the consturctor..
For example,
TCPSelectoHandler tsh = new TCPSelectoHandler(host, port) //string and int
tsh.connect(); //to connect to given host and port
Operating System: All
Platform: Sun
[1.9.22]
instead consist of sharing the ProtocolFilter amongs ProtocolChain:
among
Operating System: All
Platform: All
Currently the TCPSelectorHandler, by default sets the Socket's tcpNoDelay to
false when a new SocketChannel is accepted. This also needs to be set on the
TCPConnectorHandler when a client initiated connection is established.
Separate from the TCPConnectorHandler not explicitly assigning tcpNoDelay,
there's a potential bug in TCPSelectorHandler.configureChannel(). It assumes
the default for a java.net.Socket's tcpNoDelay will also be false by default.
If the underlying JDK changes this default from false to true, AND Grizzly wants
the tcpNoDelay to be false, it will not get set to false. Here's that segment
of code from TCPSelectorHandler.configureChannel():
if(tcpNoDelay)
socket.setTcpNoDelay(tcpNoDelay);
This probably ought to be changed to:
if (socket.getTcpNoDelay() && tcpNoDelay)
socket.setTcpNoDelay(tcpNoDelay);
Or, simply:
socket.setTcpNoDelay(tcpNoDelay);
Operating System: All
Platform: All
[1.9.22]
The current http module doesn't support SSL. This is a regression from 1.0.x
Operating System: All
Platform: All
[1.9.22]
in UDPSelectorHandler::preSelect function
datagramChannel.configureBlocking(false); is used twice
Operating System: All
Platform: All
Here is the list that I've for the workspace dir. structure.
1. Remove directory "main" if it's not needed.
2. Push all interfaces to a different directory under com/sun/grizzly/spi?
3. Push all default implementations to a dir called defaults under
com/sun/grizzly/defaults?
Operating System: All
Platform: Sun
[1.9.22]
This is about:
interface ConnectorHandlerPool.java
and it's implementor DefaultConnectorHandlerPool.java
First of all the word "Pool" gives an impression to the user of this framework
that, this class is POOL of ConnectorHanlders which is definetely not the case
here. All that this class and it's interface do is to provide impelemenation for
aquring a connection and release a connection (I guees from a pool or linked
concurrent queue).
This name toooo confusing.
Here are some suggestions:
for the interface: ConnectionPoolManager.java
ConnectionPoolManagerImpl.java
Or ConnectionPoolEvent.java
ConnectionPoolEventHandler.java
Operating System: All
Platform: Sun
[1.9.22]
The class DefaultProtocolChainInstanceHandler really does not do what it name
says. The funtionality of the class is, to have a Concurrent Linked Queue of
protocol chains. There should a name to reflect this functionality.
Here are some suggestions:
ProtocolChainCache.java
ProtocolChainPool.java
ProtocolChainsQueue.java
Operating System: All
Platform: Sun
[1.9.22]
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.