yoursunny / ndnts Goto Github PK
View Code? Open in Web Editor NEWNDN libraries for the Modern Web
Home Page: https://ndnts-docs.ndn.today
License: ISC License
NDN libraries for the Modern Web
Home Page: https://ndnts-docs.ndn.today
License: ISC License
I seem to be running into this error when i run this on a raspberry pi 4b its seems to be working fine on my laptop.
I get the following error even when i run nfdc status, but when i run nfd-start everything looks fine
pi@raspberrypi:~ $ NFD version 0.7.0-23-g1752159a starting
Built with Clang version 9.0.0 (http://git-us.linaro.org/toolchain/jenkins-scripts.git d13bb6bafb2139131749cebad3ed0862013bb7b6), with GNU libstdc++ version 20190406, with Boost version 1.62.0, with libpcap version 1.8.1, with WebSocket++ version 0.8.1, with ndn-cxx version 0.7.0-26-g78ffc635
1590914901.724933 INFO: [nfd.FaceTable] Added face id=255 remote=null:// local=null://
1590914901.725080 INFO: [nfd.FaceTable] Added face id=254 remote=contentstore:// local=contentstore://
1590914901.725268 INFO: [nfd.CsPolicy] setLimit 10
1590914901.725558 INFO: [nfd.StrategyChoice] setDefaultStrategy /localhost/nfd/strategy/best-route/%FD%05
1590914901.725907 INFO: [nfd.FaceTable] Added face id=1 remote=internal:// local=internal://
1590914901.727492 WARN: [nfd.CommandAuthenticator] 'certfile any' is intended for demo purposes only and SHOULD NOT be used in production environments
1590914901.728307 INFO: [nfd.StrategyChoice] changeStrategy(/ndn/broadcast) /localhost/nfd/strategy/best-route/%FD%05 -> /localhost/nfd/strategy/multicast/%FD%03
1590914901.728401 INFO: [nfd.StrategyChoice] changeStrategy(/localhost) /localhost/nfd/strategy/best-route/%FD%05 -> /localhost/nfd/strategy/multicast/%FD%03
1590914901.728500 INFO: [nfd.StrategyChoice] changeStrategy(/localhost/nfd) /localhost/nfd/strategy/multicast/%FD%03 -> /localhost/nfd/strategy/best-route/%FD%05
1590914901.728594 INFO: [nfd.CsPolicy] setLimit 65536
1590914901.728632 INFO: [nfd.CsPolicy] setLimit 65536
1590914901.728742 INFO: [nfd.EthernetFactory] enabling multicast on 01:00:5e:00:17:aa
1590914901.728913 INFO: [nfd.TcpChannel] [tcp4://0.0.0.0:6363] Creating channel
1590914901.729076 INFO: [nfd.UdpChannel] [udp4://0.0.0.0:6363] Creating channel
1590914901.729150 INFO: [nfd.UdpChannel] [udp6://[::]:6363] Creating channel
1590914901.729209 INFO: [nfd.UdpFactory] enabling multicast on 224.0.23.170:56363
1590914901.729251 INFO: [nfd.UdpFactory] enabling multicast on [ff02::1234]:56363
1590914901.729389 INFO: [nfd.UnixStreamChannel] [unix:///run/nfd.sock] Creating channel
1590914901.729588 INFO: [nfd.WebSocketChannel] [ws://0.0.0.0:9696] Creating channel
with:
data = await endpoint_sub.consume(interest);
One interest is sent at a time and we wait for either a data packet or timeout.
I want to send multiple interests at once, and then adjust this number according to data retrieval or timeouts
In other words, we want to send the interests and handle the reply in another place.
Is it possible to split this into two separate functions, one for sending the interest and the other for handling the reply?
For the @ndn/ndn
package, I think it would be great if it could provide some general guidance and maybe a simple example of how to get started. Although quite funny, especially the "Online demo" that is being linked is a bit confusing, as you expect something NDN-related to happen instead of just seeing the 🤌 emoji. Also considering that the implementation is distributed over a lot of packages, I think it would be nice to make it a bit easier for new users to get started (especially if they encounter NDNts by just searching for "NDN" on npm).
Hi, I follow your instruction in lib nfdmgmt, it does not work if I don't run produce().
My code is as follow, this will not register a "/hi" into NFD.
const { face } = await connectToRouter(uri, {
H3Transport,
testConnection: false,
});
enableNfdPrefixReg(face);
const prefix = new Name("/hi");
face.addRoute(prefix);
After I run a produce, the "/hi" will be registered. Is this a bug?
const { face } = await connectToRouter(uri, {
H3Transport,
testConnection: false,
});
enableNfdPrefixReg(face);
const prefix = new Name("/hi");
face.addRoute(prefix);
const endpoint = new Endpoint({fw: face.fw});
endpoint.produce(prefix, null);
The following doesn't work as expected (no updates are received), but works fine when a string is used instead of a name in sync.add
. Is this expected?
const sync = new SvSync({
syncPrefix: new Name("/ndn/multicast/svs"),
endpoint: endpoint,
})
const syncNode = sync.add(new Name(`/ndn/alice/svs`)); // <-- sync.add(`/ndn/alice/svs`) works.
Reproduce on NDN Play. (A,B) run a Sync group using Name and (C,D) run a separate group using string.
(running on nightly build for 10/28/2021)
when I use svchat, ndnts show up a declare bug, and I change get state(): L3Face.State;
to private get state(): L3Face.State;
, bug disappear.
problem:
Error: node_modules/@ndn/l3face/lib/l3face.d.ts:28:9 - error TS2379: Getter and setter accessors do not agree in visibility.
28 get state(): L3Face.State;
~~~~~
Error: node_modules/@ndn/l3face/lib/l3face.d.ts:29:17 - error TS2379: Getter and setter accessors do not agree in visibility.
29 private set state(value);
~~~~~
Just out of curiosity. Do you plan to implement FLIC? It will help transfer large dataset
NDNts/packages/sync/src/svs/publisher.ts
Line 10 in d40938a
You can detect such problems in advance by adding ". /mk/tsconfig-base.json" by adding "importsNotUsedAsValues": "error" to "compilerOptions" to catch such problems in advance.
i tried to recreate from your tutorial (https://yoursunny.com/t/2020/NDNts-webpack-start/)
when i tried to send interest and parameters from my website to router -> server it works. But when i wanna try to send interest and bunch of parameters and converted into json, an error popped up
"Uncaught runtime errors :
ERROR
obj is not Encodable ....."
my website still able to connect to router but i cant send the json, here is my code
const dataEncoded = encoder.encode(name, age, sex, disease); const jsonData = JSON.stringinfy(dataEncoded); interest.appParameters = jsonData;
and i wanna ask another question too
If I have a form in html then I take its value so that it can be received on the server side, should i convert that value into ndn element first? and can the server accept json format or not
Thanks!
NDNts/packages/nfdmgmt/src/control-command.ts
Lines 18 to 22 in 41f4db6
The correct spelling is "faces".
Face Management commands, datasets, and notifications are available under namespace
ndn:/localhost/nfd/faces
.
Quoted from https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Face-Management.
Thanks for awesome NDN libraries!
Followed example in the cat
README and got following error
ndncat put-segmented /A </tmp/1.bin
ndncat put-segmented <name>
publish segmented object
Positionals:
name name prefix [string] [required]
Options:
--help Show help [boolean]
--version Show version number [boolean]
--convention1 use 2014 Naming Convention [boolean] [default: false]
--rdr publish RDR metadata packet [boolean] [default: true]
--ver version number; 'none' to omit version component, 'now' to use
current timestamp [string] [default: "now"]
--file read from file instead of stdin [string]
--chunk-size segment payload size [number] [default: 4096]
TypeError: input.split is not a function or its return value is not iterable
...
Looks like that the instanceof Component
check fails every time even though input
is instance of Component
class.
Hi there, I'm the maintainer of BrowserFS. I've been going through the dependents of browserfs.
Please see the notice in the readme: https://github.com/jvilk/browserfs
Would you be interested in updating your project to use the updated fork, ZenFS?
The comment is written as internal comments rather than TSDoc, which is invisible in the published package:
// lib/packet/ca-profile.d.ts
export declare namespace CaProfile {
// <SNIP>
interface Fields {
prefix: Name;
info: string;
probeKeys: string[];
maxValidityPeriod: number;
cert: Certificate;
}
// <SNIP>
}
This is misleading since the NDN Cert Spec says maxValidityPeriod
is in seconds.
Please write a TSDoc comment (visible in IDE) explaining this to avoid confusion.
Hi bro, one of your great works is SelfLearningStrategy, could you please Implement the PrefixAnnouncement in LPPacket? I want to improve your SelfLearningStrategy. Add a PA process to the SelfLearningStrategy::AfterReceiveInterest() for implementing Kite, so the Mobility Producer could send Interest to the Immobile Consumer (or RV) to set the Trace in FIB.
so we are deploying a website based on https://yoursunny.com/t/2020/NDNts-webpack-start/ and have deployed to netlify,
and have customized it to use websocket using await WsTransport.createFace({}, "wss://router.example.org/");
and using multiple options for "wss://"
such as "wss://ourlink.com/" "wss://ourlink.com:9696/" wss://ourlink.com:9696/ws/
each issuing the following error
https://postimg.cc/gallery/c0Sgptx
we created the server side in the azure cloud vm by allowing all inbound and outbound to enter and exit in the VM, nfd has been run on the server and there is not a single log in.
is there any source or recommendation in solving this
Thank you.
I'm still trying to make development for (https://yoursunny.com/t/2020/NDNts-webpack-start/)
this time I try to make server from python ndn
and I got an issue where when I use appParameters the interest is not received on the server
but if I don't use it, the server received the interest
this is my code on main.js
import { connectToNetwork, connectToRouter } from "@ndn/autoconfig";
import { Endpoint } from "@ndn/endpoint";
import { AltUri, Interest, Name } from "@ndn/packet";
import { WsTransport } from "@ndn/ws-transport";
async function ping(evt) {
evt.preventDefault();
// Disable the submit button during function execution.
const $button = document.querySelector("#app_button");
$button.disabled = true;
try {
// Construct the name prefix <user-input>+/ping
const prefix = new Name(document.querySelector("#app_prefix").value);
const app = document.querySelector("#app_param").value;
const $log = document.querySelector("#app_log");
$log.textContent = `Check Data \n${AltUri.ofName(prefix)}\n`;
const endpoint = new Endpoint();
const encoder = new TextEncoder();
// Generate a random number as initial sequence number.
let seqNum = Math.trunc(Math.random() * 1e8);
for (let i = 0; i < 3; ++i) {
++seqNum;
// Construct an Interest with prefix + seqNum.
const interest = new Interest();
interest.name = prefix;
interest.mustBeFresh = true;
interest.lifetime = 1000;
interest.appParameters = encoder.encode(app);
$log.textContent += `\n${encoder.encode(app)}\n`;
const t0 = Date.now();
try {
// Retrieve Data and compute round-trip time.
const data = await endpoint.consume(interest);
const rtt = Date.now() - t0;
const dataContent = data.content;
//console.log(dataContent);
$log.textContent += `\n${AltUri.ofName(data.name)} rtt=${rtt}ms content=${String.fromCharCode(...dataContent)}`;
} catch(err) {
// Report Data retrieval error.
$log.textContent += `\n${AltUri.ofName(interest.name)} ${err}`;
}
// Delay 500ms before sending the next Interest.
await new Promise((r) => setTimeout(r, 500));
}
} finally {
// Re-enable the submit button.
$button.disabled = false;
}
}
async function main() {
// Connect to the global NDN network in one line.
// This function queries the NDN-FCH service, and connects to the nearest router.
//await connectToRouter("wss://192.168.56.106:9696/ws/", {});
//await WsTransport.createFace({}, "wss://testbed-ndn-rg.stei.itb.ac.id/ws/");
await WsTransport.createFace({}, "ws://192.168.56.106:9696/ws/");
//await WsTransport.createFace({}, "ws://coba.ndntel-u.my.id/ws/");
// Enable the form after connection was successful.
document.querySelector("#app_button").disabled = false;
document.querySelector("#app_form").addEventListener("submit", ping);
}
window.addEventListener("load", main);
this is my producer.py code
@app.route('/data/user')
def on_interest(name: FormalName, param: InterestParam, ap: Optional[BinaryStr]):
print(f'>> I: {Name.to_str(name)}, {param}')
content = f'Hello, world! {bytes(ap)}'.encode()
app.put_data(name, content=content, freshness_period=10000)
print(f'<< D: {Name.to_str(name)}')
print(MetaInfo(freshness_period=10000))
print(f'Content: (size: {len(content)})')
print('')
thank you for your help
node ➜ /workspaces/NDNts (main) $ pnpm run build
> @ndn/root@ build /workspaces/NDNts
> bash mk/build.sh
packages/sync/src/psync/codec.ts(2,34): error TS2307: Cannot find module '@yoursunny/psync-bloom' or its corresponding type declarations.
packages/sync/src/psync/partial-publisher.ts(6,29): error TS2307: Cannot find module '@yoursunny/psync-bloom' or its corresponding type declarations.
packages/sync/src/psync/partial-subscriber.ts(5,65): error TS2307: Cannot find module '@yoursunny/psync-bloom' or its corresponding type declarations.
Start with a clean container (Debian GNU/Linux 11 (bullseye), NodeJS v18.13.0, pnpm 7.27.0) and run pnpm i
first, followed by pnpm run build
.
Hi,
I would like to ask if there is a way to parse ndnts packet by using wireshark? I found that it is possible to analyse udp and tcp packets, but websocket only shows small fragments.
Since req.rto
is strictly less than the Interest's lifetime, this line makes retransmission happens very frequently.
For example, if I set the lifetimeAfterRto
to be 4000 and retxLimit
to be 5, and the RTT is 200ms, then when the latest segment is missing, the expected behavior is retrying in 4s after the last timeout.
But the actual behavior is sending all 6 Interests in 200*5 = 1s, which does not make sense since all Interests except the first one will be suppressed. Then, your fetcher will report exceedRetxLimit
after the first Interest times out.
This behavior does not align with my expectation.
I tried to recreate the website from your website (https://yoursunny.com/t/2020/NDNts-webpack-start/) and successfully connected to the NDN Testbed. But, we want to connect the website to our local testbed, is there any source or recommendation to do this?
Thank you
In the following code, inside "SetInterval" method node sequence number is increasing every 2s. But I am not understanding it. For example, I want to publish 10 data under 1 ownPrefix which means I want to increase the node sequence number until 10. I do not want to increase the sequence number after every 2s. If I remove the setInterval method then on the consumer side I am not getting the names that are published. Can you please explain a bit?
import {openUplinks} from "@ndn/cli-common";
import {Endpoint} from "@ndn/endpoint";
import {Data, Name} from "@ndn/packet";
import {makePSyncCompatParam, PSyncPartialPublisher, PSyncZlib, SyncNode} from "@ndn/sync";
import * as fs from 'fs';
const syncPrefix = new Name("/sync1");
const ownPrefix = new Name(`/textolines/`);
function text2lines():string[] {
var text = fs.readFileSync("/Users/XXX/Desktop/NDNts/data.txt", "utf-8");
return text.split("\n");
}
let lines = text2lines();
//Publish Function
(async () => {
await openUplinks();
const sync = new PSyncPartialPublisher({
p: makePSyncCompatParam({
ibltCompression: PSyncZlib,
}),
// @ts-ignore
syncPrefix,
});
//----------- For debugging output -- optional----------
if (process.env.NDNTS_SYNC_DEBUG === "1") {
sync.on("debug", ({ action, interestName }) => {
console.log(`DEBUG ${action} ${interestName ?? ""}`);
});
}
//---------optional end---------------
const pub_nodes: Array<SyncNode<Name>> = [];
for (let i = 0; i < 1; ++i) {
pub_nodes.push(sync.add(ownPrefix.append(`${i}`)));
}
var interval = setInterval(() => {
for (let i = 0; i<pub_nodes.length; i++)
{ const node = pub_nodes[i];
for (let j = 0; j < lines.length; j++)
{
node.seqNum++;
console.log(`PUBLISH ${node.id} ${node.seqNum}`);
}
}
}, 2000);
})().catch(console.error);
//Producer
(async () => {
await openUplinks();
const endpoint = new Endpoint();
endpoint.produce(ownPrefix, async (interest) => {
console.log(`Got Interest ${interest.name}`);
const x = Number.parseInt(interest.name.at(2).text, 10);
console.log(x)
// Make a Data packet that has the same name as the Interest.
const data = new Data(interest.name);
data.freshnessPeriod = 1000;
data.content = new TextEncoder().encode(lines[x]);
// Sending the Data is as simple as returning it from the function.
return data;
},
// options
);
})();
another issue is if I change the syncPrefix to syncPrefix_pub then it is throwing me an error which I also do not understand. Why should I use only "syncPrefix" keyword. I am sharing the error:
(node:92568) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'append' of undefined
at new PSyncPartialPublisher (file:///Users/XXX/Desktop/NDNts/node_modules/@ndn/sync/lib/psync/partial-publisher_node.js:109:54)
at file:///Users/XXX/Desktop/NDNts/Psync_test.js:16:18
(Use `node --trace-warnings ...` to show where the warning was created)
(node:92568) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:92568) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I am trying to run psync-partial-publisher.ts from NDNts directory as you have mentioned.
NDNTS_NFDREG=1 npm run literate packages/sync/interop-test/psync-partial-publisher.ts
but I am getting the following errors:
npm ERR! code ENOENT
npm ERR! syscall open
npm ERR! path /Users/XXX/Desktop/ndntts/package.json
npm ERR! errno -2
npm ERR! enoent ENOENT: no such file or directory, open '/Users/XXX/Desktop/ndntts/package.json'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/XXX/.npm/_logs/2021-08-16T14_16_17_807Z-debug.log
XXX@XXX-MBP ndntts % cd NDNts
XXX@XXX-MBP NDNts % NDNTS_NFDREG=1 npm run literate packages/sync/interop-test/psync-partial-publisher.ts
> @ndn/root@ literate /Users/XXX/Desktop/ndntts/NDNts
> bash mk/literate.sh "packages/sync/interop-test/psync-partial-publisher.ts"
\e[96mRUNNING packages/sync/interop-test/psync-partial-publisher.ts\e[39m
(node:3013) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
internal/process/esm_loader.js:74
internalBinding('errors').triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@k-foss/ts-esnode' imported from /Users/XXX/Desktop/ndntts/NDNts/packages/sync/interop-test/
at packageResolve (internal/modules/esm/resolve.js:664:9)
at moduleResolve (internal/modules/esm/resolve.js:705:18)
at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:819:11)
at Loader.resolve (internal/modules/esm/loader.js:89:40)
at Loader.getModuleJob (internal/modules/esm/loader.js:242:28)
at Loader.import (internal/modules/esm/loader.js:177:28)
at internal/process/esm_loader.js:57:31
at initializeLoader (internal/process/esm_loader.js:62:5)
at Object.loadESM (internal/process/esm_loader.js:67:11)
at runMainESM (internal/modules/run_main.js:47:31) {
code: 'ERR_MODULE_NOT_FOUND'
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ndn/root@ literate: `bash mk/literate.sh "packages/sync/interop-test/psync-partial-publisher.ts"`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @ndn/root@ literate script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm WARN Local package.json exists, but node_modules missing, did you mean to install?
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/XXX/.npm/_logs/2021-08-16T14_16_27_308Z-debug.log
Same thing is happening for partial consumer also.
I have installed NDNts, Node.js v14.17.4, and npm v6.14.4. I have installed nightly builds. I created a producer and trying to run it. NFD is also running. But it is throwing the following error:
NDNts % NDNTS_NFDREG=1 node ./producer.mjs
(node:46681) UnhandledPromiseRejectionWarning: Error: connect ENOENT /run/nfd.sock
at PipeConnectWrap.afterConnect [as oncomplete] (net.js:1148:16)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:46681) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:46681) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Hi,
I import a cert from a base64 string, and use it to verify the packet. it seems it did not verify the date of the cert.
I use an out-of-date python-ndn cert, and import it into ndnts.
* /pcnl/ndn/video/sz02/live
+->* /pcnl/ndn/video/sz02/live/KEY/-F%96%1F%40%04%2F%05
+->* /pcnl/ndn/video/sz02/live/KEY/-F%96%1F%40%04%2F%05/self/v=1649990055921
Certificate name:
/pcnl/ndn/video/sz02/live/KEY/-F%96%1F%40%04%2F%05/self/v=1649990055921
Validity:
NotBefore: 19700101T000000
**NotAfter: 20220415T023415** <--------------------- out of date
Public key bits:
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1h+7WRmW8/n7lJ6cfyMaDiGdYqQH
9EFjUc5Df1e9RbmtjIXbPLRiCxTC5Dbyh/TY59YvOV8IEQRQQU30t4Y/Dw==
Signature Information:
Signature Type: SignatureSha256WithEcdsa
Key Locator: /pcnl/ndn/video/sz02/live/KEY/-F%96%1F%40%04%2F%05
following is ndnts code,
const sz02 = fromBase64(`
Bv0BTwc9CARwY25sCANuZG4IBXZpZGVvCARzejAyCARsaXZlCANLRVkICC1Glh9A
BC8FCARzZWxmNggAAAGAKxI38RQJGAECGQQANu6AFVswWTATBgcqhkjOPQIBBggq
hkjOPQMBBwNCAATWH7tZGZbz+fuUnpx/IxoOIZ1ipAf0QWNRzkN/V71Fua2Mhds8
tGILFMLkNvKH9Njn1i85XwgRBFBBTfS3hj8PFl4bAQMcLwctCARwY25sCANuZG4I
BXZpZGVvCARzejAyCARsaXZlCANLRVkICC1Glh9ABC8F/QD9Jv0A/g8xOTcwMDEw
MVQwMDAwMDD9AP8PMjAyMjA0MTVUMDIzNDE1F0YwRAIgcn/wSGmDz7HpNR56mVGF
VLt9xR2q8Qqb0IYBhC48L0wCIBQ//+R3Ll4fZfNpJrGs1G7phhTGGCywyugL2QES
E7QO`
);
const data0 = new Decoder(sz02).decode(Data);
const cert0 = Certificate.fromData(data0);
const verifier = createVerifier(cert0);
About trust-schema module example, if authorA and authorB are both signed by adminA, authorA signed articleA, this is our expectation. Meanwhile, authorB also signed articleA, this is not our expectation. When a consumer received a data package, how to check it come from authorB, and reject it.
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.