mirage / irmin Goto Github PK
View Code? Open in Web Editor NEWIrmin is a distributed database that follows the same design principles as Git
Home Page: https://irmin.org
License: ISC License
Irmin is a distributed database that follows the same design principles as Git
Home Page: https://irmin.org
License: ISC License
amir$ irmin dump thestate
sh: dot: command not found
I don't know if I'm misunderstanding some Unix thing or if I have a missing dependency for the initial tutorial. What do I do?
I have notice that irmin can't store actual public keys unless you wrap them within " ".
cm770@pursuit2:/local/irminsule/testing/irmin-mem$ irmin write person/pubKey 123abc/local/irminsule/testing/irmin-mem$ irmin tree
cm770@pursuit2:
/person/name........................................................................................."carlos"
/person/nationality..............................................................................."universal"
/person/pubKey......................................................................................."123abc"
/person/surname......................................................................................"molina"
cm770@pursuit2:~/local/irminsule/testing/irmin-mem$ irmin write person/pubKey ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvaRbn64jCX5Ne+FS4lmNNn+p+umx8/vcJ1+0oFF7oyXg55pFHJEBNhL0g8UXXzvuMdmFgHCBapAq9Efb4dUv45ffnoc5PQqYToO1Sy8eMSSxnVqI8oQeH81/yzgBelKiHVcLx5FNXyuBesIpvxd7VhrN4VZy2I1eWBE3EefmmfigQ9ISEeIHnIjyK6O922xPWkjiWmd83CAC6DGzCChC13Q6eFFArEgUmmNupm+A5Beu4qz6BkvP6xo0vJoOCI+WruWPsYhjxg13LE17LvSLmm1DQz2ghk25rRGPzNKVeJi7xy1LcM1i4vzIMJbTya9g86q5COvT5MqnIHvlbFi0GQ== [email protected]
irmin: internal error, uncaught exception:
(Failure "Too many arguments")
cm770@pursuit2:~/local/irminsule/testing/irmin-mem$ irmin write person/pubKey "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvaRbn64jCX5Ne+FS4lmNNn+p+umx8/vcJ1+0oFF7oyXg55pFHJEBNhL0g8UXXzvuMdmFgHCBapAq9Efb4dUv45ffnoc5PQqYToO1Sy8eMSSxnVqI8oQeH81/yzgBelKiHVcLx5FNXyuBesIpvxd7VhrN4VZy2I1eWBE3EefmmfigQ9ISEeIHnIjyK6O922xPWkjiWmd83CAC6DGzCChC13Q6eFFArEgUmmNupm+A5Beu4qz6BkvP6xo0vJoOCI+WruWPsYhjxg13LE17LvSLmm1DQz2ghk25rRGPzNKVeJi7xy1LcM1i4vzIMJbTya9g86q5COvT5MqnIHvlbFi0GQ== [email protected]"
If we want to have Irmin running on real systems we need a story about data recollection:
For simplicity, 2. can be transformed into 1. by rebasing the history. A downside with this is that two rebased stores are not able to sync anymore (if they pruned different parts of their history). Solving 2. without transforming it into 1. means supporting partial fetch/push, which the Git protocol doesn't handle very well (not sure if it is a limitation of the git
command-line or of the protocol itself, need to investigate a bit more).
A basic notification mechanism is needed.
We don't currently merge two strings if both contents has been modified since the have branched from a common ancestor. To improve that, need to have a look at https://github.com/janestreet/patdiff but it seems to depend on https://github.com/janestreet/core_extended ... @diml any chance to have the patdiff library usable on mirage (ie. pure ocaml code) ?
I followed the "Getting Started", when I get to:
"You can also access the daemon state by opening your browser to http://127.0.0.1:8080"
I get:
{"error":"(Failure "to_json: HTML node")"}
instead of a "list of possible operations"
I was trying to run the example of using the Irmin API in the README file.
After running module G = IrminGit.Make(IrminGit.Memory);;
I get:
Error: Signature mismatch:
The field `disk' is required but not provided
The field `bare' is required but not provided
The field `Sync' is required but not provided
The field `Store' is required but not provided
The field `root' is required but not provided
Not very urgent, but at some point we will need to be able to distinguish users.
Not sure what's the exact semantics of that for Irmin, though, but that's necessary to populate an IMAP server. We could ask the user to provide an ordering on the path? On the keys in the path?
Currently, Irminsule speaks two languages:
Adding a different binary protocol is not totally trivial but is definitely doable. Tip: use cagit.
Need basic support for import/export. No need to be too clever to start with.
─( 00:00:00 )─< command 0 >────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # #require "irmin";;
Camlp4 Parsing version 4.01.0
─( 10:00:34 )─< command 1 >────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # #require "irmin.unix";;
─( 10:00:42 )─< command 2 >────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # open Irmin_unix;;
─( 10:00:47 )─< command 3 >────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # module Git = IrminGit.FS(struct
let root = Some "/tmp/db"
let bare = true
end);;
module Git : Irmin.BACKEND
─( 10:00:51 )─< command 4 >────────────────────────────────────────────────────────────────────────────────────{ counter: 0 }─
utop # module DB = Git.Make(IrminKey.SHA1)(IrminContents.String)(IrminTag.String);;
Fatal error: exception Stack overflow
If I put the commands into a file and "#use" that, it does work.
Currently the values are raw blobs. It could be interesting to easily support more structured values. The only "interesting" idea here is that a structured value can also contains keys, which can be understood by Irminsule when it computes the export set.
Ideally this structure should be quite easy to define for the user (for instance, using a schema stored somewhere in the database).
Currently, committing a complex operation to the store involves:
So if someone else modifies HEAD between 1. and 3., we can loose some operations on the main branch (but no data corruption ...) -- the added data/commits will be in the store, but not in the branch anymore, which is bad.
A solution to this is to serialize local operations on mutable store. The idea is to clone the database, be the only one to modify it locally and the push back the result. So in this case, local locking is not too bad. An other possibility it to automatically merge/rebase the operation when HEAD has been changed between 1. and 3. but this requires having transactions.
utop # CC.update h ["tables";"mysupertable";"auieauie"] (CC.Value.of_bytes_exn "auieauie");;
- : unit = ()
but
utop # CC.update h ["tables";"mysupertable";"auieauie"] (Marshal.to_string "auieauie" [] |> CC.Value.of_bytes_exn);;
Exception: IrminCRUD.Make(Client).Error "(IrminHTTP.Invalid)".
In the first case, the daemon outputs more lines than in the first.
I'm interested in using Irmin other languages (Clojure and ClojureScript, specifically) via the JSON CRUD interface.
The only documentation I can find on the JSON CRUD interface is a single GET statement - it'd be great to see the other API endpoints have a bit of documentation with (or just) an example payload/CURL line, ideally linking to the source where the endpoint is implemented. I looked through the source a bit, but I've never worked with OCaml, so couldn't quite pin down the shape of the data I should use.
[vagrant@localhost examples]$ cat >irmin_test.ml <<EOT
open Lwt
let t =
let open Irmin_unix in
let module Git = IrminGit.FS(struct
let root = Some "/tmp/foo"
let bare = true
end) in
let module DB = Git.Make(IrminKey.SHA1)(IrminContents.String)(IrminTag.String) in
DB.create () >>= fun db ->
DB.View.create () >>= fun v ->
DB.View.update v [ ] "root" >>= fun () ->
DB.View.merge_path_exn db [] v
let () = Lwt_main.run t
EOT
[vagrant@localhost examples]$ ocamlbuild -use-ocamlfind -no-hygiene -tag "syntax(camlp4o)" -package irmin.unix,sexplib.syntax,comparelib.syntax,bin_prot.syntax irmin_test.native
[vagrant@localhost examples]$ ./irmin_test.native
[vagrant@localhost examples]$ cd /tmp/foo
[vagrant@localhost foo]$ git show
fatal: unable to read root tree (d98125eebf0495e8a2b455578fb261f553a27db5)
[vagrant@localhost foo]$ git log
commit d98125eebf0495e8a2b455578fb261f553a27db5
Author: 448 <[email protected]>
Date: Thu Jan 1 00:00:01 1970 +0000
Merge view to
Actions:
- write
It works ok if I change the path from [] to [ "foo" ].
currently, we are cheating a little bit when using the different backends: we always assume that we picked the right binary format (eg. if you want to access a Git repo, you need to start your irmin database with a Git format or you are screwed). This will be useful when we'll add the convergent encryption backend. Not very hard to do though, but we need some way to cache key translations somewhere if this will be very costly.
We have an issue currently when too many processes are trying to open /.git/refs/heads/master
. This can happen when you have a lot of active connection. One fix is to have a bounded pool of open fd (this is already done for reading objects in .git/objects
but for any reasons, that's not yet the case with tags).
Currently, the push/pull are a bit dumb as they simply synchronize the store and move the HEAD tag. We do not rebase/merge currently, as the first use-case we want to support is a kind of auto-updating cache (which will never modify the store itself).
Would be good to add a proof-of-concept backend which dispatch its keys on different backends type. Maybe using a key -> Irmin.S
dispatch function. So that would be easier to store some parts in memory and other parts on disk.
When one uses only BuildDepends
in the _oasis
file with syntax extensions, Oasis copies everything to the META file:
see https://github.com/samoht/irminsule/blob/master/_oasis#L32
and https://github.com/samoht/irminsule/blob/master/lib/core/META#L6
That forces users of the library to use camlp4
, and to have only extensions that are compatible with type_conv
(that breaks with Eliom for instance, last time I tried at least).
Please, add a XMETARequires
field, like here:
https://github.com/janestreet/core_kernel/blob/master/_oasis#L243
from @dbuenzli
https://github.com/samoht/irminsule/blob/master/lib/core/irminMerge.mli
No deep look at this but I see an exception for Conflicts. Any reason why conflicts are not represented explicitly and conflict resolution managed through other combinators ?
I am looking for the function:
S.t -> S.branch
which tells the current branch
Does it exist somewhere? I am tracking this in a product with the S.t
but surely the S.t
knows the reference it tracks internally?
Is there any documentation about the current or planned design of Irminsule?
I understand that it follows the same principles as Git and can use it as actual storage backend, but that's a very general description.
How the data will be structured and related? Will there be a possibility to make queries?
Can the database store large binary blobs?
Thank you in advance for the answers!
Would be good to have a way to query a remote database for a partial state:
a/b/
a/b/*.txt
I have been exploring the 'irmin' tutorial.
I followed 'Using the In-Memory Backend' instructions as suggested, except that I created the 'irmin-mem' dir within my personal space instead of '/tmp' as indicated in the tutorial.
I uncovered the following error message:
m770@pursuit2:/local/irminsule/testing/irmin-mem$ irmin dump thestate/local/irminsule/testing/irmin-mem$
sh: 1: dot: not found
2014-04-23 10:27:07.942 IRMIN ERROR: The thestate.dot is corrupted
cm770@pursuit2:
Notice that the thestate.dot file is still created!
cm770@pursuit2:~/local/irminsule/testing/irmin-mem$ ls -la
total 16
drwxr-xr-x 2 cm770 cm770 4096 Apr 23 10:27 .
drwxr-xr-x 4 cm770 cm770 4096 Apr 23 10:33 ..
-rw-r--r-- 1 cm770 cm770 5864 Apr 23 10:27 thestate.dot
It might help to take into account that before the 'irmin dump thestate' instruction I executed on my interaction terminal:
irmin snapshot
These are the last lines produced by irmin main terminal:
2014-04-23 10:26:51.761 HTTP INFO : Request received: PATH=/contents/read/19e370dcbf0f82eba30d835f45c7c1900c0ed66b
2014-04-23 10:27:07.927 HTTP INFO : Request received: PATH=/contents/dump
2014-04-23 10:27:07.928 HTTP INFO : Request received: PATH=/node/dump
2014-04-23 10:27:07.929 HTTP INFO : Request received: PATH=/commit/dump
2014-04-23 10:27:07.930 HTTP INFO : Request received: PATH=/ref/dump
irmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestateirmin dump thestate
Seems to be a regression introduced in 0.6.0, which should be related to the API change of list
.
This is needed for portability issues (especially on Xen) and few users worried about their recompilation compile time.
"0) I'm installing on Linux Ubuntu computer
cm@pursuit2:~/local/irminsule/irminsule-master$ make
ocaml setup.ml -configure --enable-tests --prefix /usr/local
...
pkg_alcotest: ........................................ /home/cm/ocamlbrew/ocaml-4.01.0/.opam/system/lib/alcotest
echo "let current = \"0.6.0\"" > lib/core/irminVersion.ml
ocaml setup.ml -build
Finished, 1 target (0 cached) in 00:00:00.
Finished, 143 targets (0 cached) in 00:01:50.
cm@pursuit2:~/local/irminsule/irminsule-master$ make install
ocaml setup.ml -install
Installed /home/cm/ocamlbrew/ocaml-4.01.0/.opam/system/lib/irminsule/irmin.mli
...
Installed /home/cm/ocamlbrew/ocaml-4.01.0/.opam/system/lib/irminsule/irminFS.cmx
Installed /home/cm/ocamlbrew/ocaml-4.01.0/.opam/system/lib/irminsule/META
cp: cannot create regular file `/usr/local/bin/irmin': Permission denied
E: Failure("Command ''cp' '/auto/homes/cm770/local/irminsule/irminsule-master/_build/lib/driver/irminMain.native' '/usr/local/bin/irmin'' terminated with error code 1")
make: *** [install] Error 1"
cm@pursuit2:~/local/irminsule/irminsule-master$ make install
ocaml setup.ml -install
ocamlfind: Package irminsule is already installed
(file /home/cm/ocamlbrew/ocaml-4.01.0/.opam/system/lib/irminsule/META already exists)
E: Failure("Command ''/home/cm/ocamlbrew/ocaml-4.01.0/.opam/system/bin/ocamlfind'
...
lib/core/irminReference.mli lib/core/irminValue.mli lib/core/irminStore.mli lib/core/irminCommit.mli lib/core/irminMisc.mli lib/core/irminKey.mli lib/core/irminGraph.mli lib/core/irmin.mli' terminated with error code 2")
make: *** [install] Error 1
"
from @gregtatcam
I ran into some Irmin issues in my IMAP server which I think are related to my misunderstanding of the API. I implemented interface to Irmin as transactions via the views. I have attached an example where I create the top level key ["imaplet";"user";"mailboxes";"Test”], then I get the view and create keys/values in that view ["messages";"1”], ["messages";"1";"header”], ["messages";"1";"content”]. I commit the view with update and then read the values back for verification. Then I remove the top level key ["messages";"1”] and test each key with mem, read, and then I also list the whole tree under ["messages";"1”]. I get results which I don’t quite understand. Here is the matrix that I get
mem read messages;1 true no messages;1;header false yes messages;1;content false yes
And then the listing under messages;1 returns header and content keys. If I delete messages;1;content and messages;1;header then I can’t read then any longer but mem still returns true and the listing doesn’t return header and content keys. In my IMAP server I have the messages structured in such a way that there is a bunch of sub keys under the message UID keys, like header, content, etc. So, ideally I would like to remove the top level key, basically messages;UID and don’t bother with the removal of all the sub keys. I also would have expected that mem returns false for the removed key. Would you have some time to take a look at the example and explain if and what I’m doing wrong?
seems that the tls
webserver is writing to .git/HEAD
(which means that it is somehow switching branches), but this should ne happen because there is only one branch. I suspect we update the head tag a bit too much -- need to review that.
We already send only a partial view of the store, but this could still be very much improved. I have some ideas already obviously, but this will certainly need more though (and this is really the core of irminsule).
Currently, this involves instantiating a certain amount a functors. Would be good for usability to make it easier.
currently the push/pull logic is handled using a custom binary / REST protocol. would be good if the backends could also express some way to push/pull (so we can use Git directly for instance).
Some users want to have some guarantee on the memory/storage consumption of the system. They want only a bounded part of the history to be stored persistently.
We need to have a better story for this. #71 might be a possible solution.
Currently, there are two situations that Irmin do not handler very well:
merge2
function in user-defined contents.The following error messages are produced from opam run in Linux;
% opam install ezjsonm ocamlgraph lwt cryptokit \
re dolog mstruct core_kernel \
uri cohttp ssl core_kernel \
cmdliner alcotest
....
=-=-= Installing cryptokit.1.9 =-=-=
Building cryptokit.1.9:
make
make install
[ERROR] The compilation of cryptokit.1.9 failed.
Removing cryptokit.1.9.
ocamlfind remove cryptokit
...
# opam-version 1.1.1
# os linux
# command ./configure --prefix /home/cm770/ocamlbrew/ocaml-4.01.0/.opam/system
# path /auto/homes/cm770/ocamlbrew/ocaml-4.01.0/.opam/system/build/ssl.0.4.6
# compiler system (4.01.0)
# exit-code 1
# env-file /auto/homes/cm770/ocamlbrew/ocaml-4.01.0/.opam/system/build/ssl.0.4.6/ssl-7317-548b09.env
...
# opam-version 1.1.1
# os linux
# command ./configure --prefix /home/cm770/ocamlbrew/ocaml-4.01.0/.opam/system
# path /auto/homes/cm770/ocamlbrew/ocaml-4.01.0/.opam/system/build/ssl.0.4.6
# compiler system (4.01.0)
# exit-code 1
# env-file /auto/homes/cm770/ocamlbrew/ocaml-4.01.0/.opam/system/build/ssl.0.4.6/ssl-7317-548b09.env
# stdout-file /auto/homes/cm770/ocamlbrew/ocaml-4.01.0/.opam/system/build/ssl.0.4.6/ssl-7317-548b09.out
# stderr-file /auto/homes/cm770/ocamlbrew/ocaml-4.01.0/.opam/system/build/ssl.0.4.6/ssl-7317-548b09.err
### stdout ###
# ...[truncated]
# checking for ocamldep... /home/cm770/ocamlbrew/ocaml-4.01.0/bin/ocamldep
# checking for ocamllex... /home/cm770/ocamlbrew/ocaml-4.01.0/bin/ocamllex
# checking for ocamlyacc... /home/cm770/ocamlbrew/ocaml-4.01.0/bin/ocamlyacc
# checking for ocamldoc... /home/cm770/ocamlbrew/ocaml-4.01.0/bin/ocamldoc
# checking for ocamlmktop... /home/cm770/ocamlbrew/ocaml-4.01.0/bin/ocamlmktop
# checking for gcc... (cached) gcc
# checking whether we are using the GNU C compiler... (cached) yes
# checking whether gcc accepts -g... (cached) yes
# checking for gcc option to accept ISO C89... (cached) none needed
# checking for SSL_new in -lssl... no
### stderr ###
# configure: error: Cannot find libssl.
# stdout-file /auto/homes/cm770/ocamlbrew/ocaml-4.01.0/.opam/system/build/ssl.0.4.6/ssl-7317-548b09.out
# stderr-file /auto/homes/cm770/ocamlbrew/ocaml-4.01.0/.opam/system/build/ssl.0.4.6/ssl-7317-548b09.err
### stdout ###
# ...[truncated]
# checking for ocamldep... /home/cm770/ocamlbrew/ocaml-4.01.0/bin/ocamldep
# checking for ocamllex... /home/cm770/ocamlbrew/ocaml-4.01.0/bin/ocamllex
# checking for ocamlyacc... /home/cm770/ocamlbrew/ocaml-4.01.0/bin/ocamlyacc
# checking for ocamldoc... /home/cm770/ocamlbrew/ocaml-4.01.0/bin/ocamldoc
# checking for ocamlmktop... /home/cm770/ocamlbrew/ocaml-4.01.0/bin/ocamlmktop
# checking for gcc... (cached) gcc
# checking whether we are using the GNU C compiler... (cached) yes
# checking whether gcc accepts -g... (cached) yes
# checking for gcc option to accept ISO C89... (cached) none needed
# checking for SSL_new in -lssl... no
### stderr ###
# configure: error: Cannot find libssl.
The master HEAD doesn't build for me. it looks like irminMain.ml
is missing (perhaps inadvertently omitted from c9e49a0):
$ make
ocamlbuild -Is src,src/lib,src/lwt -use-ocamlfind -cflags "-bin-annot" -no-links -pkgs cryptokit,jsonm,uri,ocamlgraph,cmdliner,lwt,ocplib-endian,cstruct -tags "syntax(camlp4o)" -pkgs lwt.syntax,cohttp.lwt,cstruct.syntax irminMain.native
Solver failed:
Ocamlbuild knows of no rules that apply to a target named src/irminMain.mly. This can happen if you ask Ocamlbuild to build a target with the wrong extension (e.g. .opt instead of .native) or if the source files live in directories that have not been specified as include directories.
Backtrace:
- Failed to build the target irminMain.native
- Failed to build all of these:
- Building src/irminMain.native:
- Building src/irminMain.cmx:
- Failed to build all of these:
- Building src/irminMain.ml:
- Failed to build all of these:
- Building src/irminMain.mly
- Building src/irminMain.mll
- Building src/irminMain.mlpack
- Building irminMain.native:
- Building irminMain.cmx:
- Failed to build all of these:
- Building irminMain.ml:
- Failed to build all of these:
- Building irminMain.mly
- Building irminMain.mll
- Building irminMain.mlpack
make: *** [_build/src/irminMain.native] Error 6
(*
* After a successful installation of
* opam install ezjsonm ocamlgraph lwt cryptokit \
* re dolog mstruct core_kernel \
* uri cohttp ssl core_kernel \
* cmdliner alcotest
*
* I downloaded irminsule-master.zip from GitHub and unziped on my Linux
* Ubuntu
*)
cm@pursuit2:~/local/irminsule/irminsule-master$ ls -la
total 280
drwxr-xr-x 5 cm cm 4096 Apr 9 17:12 .
drwxr-xr-x 3 cm cm 4096 Apr 9 17:14 ..
-rw-r--r-- 1 cm cm 2737 Apr 8 19:22 CHANGES
-rwxr-xr-x 1 cm cm 363 Apr 8 19:22 configure
drwxr-xr-x 2 cm cm 4096 Apr 8 19:22 examples
-rw-r--r-- 1 cm cm 122 Apr 8 19:22 .gitignore
drwxr-xr-x 6 cm cm 4096 Apr 8 19:22 lib
drwxr-xr-x 2 cm cm 4096 Apr 8 19:22 lib_test
-rw-r--r-- 1 cm cm 892 Apr 8 19:22 Makefile
-rw-r--r-- 1 cm cm 20530 Apr 8 19:22 myocamlbuild.ml
-rw-r--r-- 1 cm cm 3359 Apr 8 19:22 _oasis
-rw-r--r-- 1 cm cm 1752 Apr 8 19:22 README.md
-rw-r--r-- 1 cm cm 193207 Apr 8 19:22 setup.ml
-rw-r--r-- 1 cm cm 7926 Apr 8 19:22 _tags
-rwxr-xr-x 1 cm cm 488 Apr 8 19:22 .travis-ci.sh
-rw-r--r-- 1 cm cm 43 Apr 8 19:22 .travis.yml
cm@pursuit2:~/local/irminsule/irminsule-master$ make
ocaml setup.ml -configure --enable-tests --prefix /usr/local
ocamlfind: Package `git.fs' not found
W: Field 'pkg_git_fs' is not set: Command ''/home/cm/ocamlbrew/ocaml-4.01.0/.opam/system/bin/ocamlfind' query -format %d git.fs > '/tmp/oasis-99ee3d.txt'' terminated with error code 2
ocamlfind: Package `git.memory' not found
W: Field 'pkg_git_memory' is not set: Command ''/home/cm/ocamlbrew/ocaml-4.01.0/.opam/system/bin/ocamlfind' query -format %d git.memory > '/tmp/oasis-49a28a.txt'' terminated with error code 2
E: Cannot find findlib package git.fs
E: Cannot find findlib package git.memory
E: Failure("2 configuration errors")
make: *** [setup.data] Error 1
This will be useful to map OCaml values of a given type to a subtree. Design idea: look at views in ctypes.
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.