Giter Site home page Giter Site logo

kappa-dev / kappatools Goto Github PK

View Code? Open in Web Editor NEW
107.0 18.0 40.0 178.92 MB

Tool suite for kappa models. Documentation and binaries can be found in the release section. Try it online at

Home Page: http://kappalanguage.org/

License: GNU Lesser General Public License v3.0

OCaml 94.37% Standard ML 0.30% Makefile 0.26% Shell 0.08% HTML 0.38% CSS 0.09% JavaScript 2.48% Python 1.56% MATLAB 0.46% C 0.01% Dockerfile 0.01% Nix 0.01%
kappa ocaml simulation

kappatools's Introduction

KaSim logo

KappaTools

Build Status Join the chat at https://gitter.im/Kappa-Dev/KaSim

KaSim is a stochastic simulator for rule-based models written in Kappa. KaSa is a static analyser for Kappa models.

Kappy is a python library to launch and analyse runs and outputs of Kappa models.

Quick startup

If you are new to Kappa, the easiest way to start experimenting with it is using the webapp.

Editor screenshot with contact map Plot screenshot

Editor screenshot with contact map 2 Stories screenshot

It's available directly in your browser, or for more performance as a downloadable electron app, available for MacOS, Windows and Linux.

Kappa tools are also available as Command-Line Interface programs, which you can either build following the instructions below, or find the binaries included with the electron app in subdir resources/bin.

If you would like to use python to interact with the Kappa tools, the kappy lib is where to look. Here's an example of its usage with ipython

In [2]: import kappy

In [3]: model_text = "%agent: A(x)\nA(x[.]), A(x[.]) <-> A(x[1]), A(x[1]) @ 1e-2,1\n%plot: |A(x[.])|\n%init: 100 A()"

In [4]: kappa_client = kappy.KappaStd()

In [5]: kappa_client.add_model_string(model_text)
Out[5]: [...]

In [6]: kappa_client.project_parse()
Out[6]: [...]

In [7]: kappa_client.simulation_start(kappy.SimulationParameter(.1,"[T] > 10"))
Out[7]: {'simulation_artifact_simulation_seed': 297327779}

In [8]: kappa_client.wait_for_simulation_stop()
Out[8]: [...]

In [9]: kappa_client.simulation_plot()
Out[9]:
  [6.7, 48.0],
[...]
  [0.4, 60.0],
  [0.3, 50.0],
  [0.2, 64.0],
  [0.1, 62.0],
  [0.0, 100.0]]}

See the install instructions to start using kappy.

User manual

See documentation page on kappalanguage.org.

Kappy API documentation is online.

The latex sources of the "older" reference manual (and KaSa one) are available in the man/ directory. To compile the manuel, in addition of a decent LaTeX distribution you need gnuplot and graphviz to generate images (make sure that dot is in the PATH of your OS). To generate the pdf of the manual type

make doc

Installation

Core tools

Released versions come with binaries for MacOS, Windows and Debian derivatives (as Ubuntu). Nightly builds of the master branch are built for these platforms by the continuous integration tools.

If you want or need your own build,

  • Install opam (the OCaml package manager) and initialize it (by issuing opam init)
  • In the source directory, install all the dependencies by opam install --deps-only pinned_libs/default if your OS is OSX or linux, or opam install --deps-only pinned_libs/windows if your OS is Windows.
  • dune build

You can be more fine grained if you only need the command-line tools (and therefore could install less dependencies) by doing opam install --deps-only kappa-binaries followed by make all

If nothing worked for you so far. Well, you're pretty much on your own... Kappa tools depend upon the OCaml native compiler version 4.05.0 or above as well as dune, findlib, Lwt (>= 2.6.0), Re, Fmt, Logs and Yojson libraries. Find any way to install them and you'll be only a make all away from getting Kappa binaries...

Kappy

You should be able to pip install kappy.

  • Under MacOS and linux (and if you're not using a python version so cutting edge that we haven't notice its release yet), wheels that contain the core binaries should be available.
  • For other platforms/python versions, you need to get kappa agents by yourself thanks to the opam package manager by opam install kappa-binaries kappa-agents (or use an externaly hosted REST API)
  • In order to develop in kappy and run all its tests, you need to follow the "get your own build section" above as well as install requests (and future).

Usage

KaSim

In order to run a simulation for 100 time units printing observables values every 0.5 time unit, type

bin/KaSim kappa_file_1 ... kappa_file_n -l 100 -p 0.5 -o data_file

This will produce a data file of 200 point containing the trajectory that was produced during the simulation.

Type:

bin/KaSim --help

for a complete list of options.

Kappy

Do:

import kappy
client = kappy.KappaRest("http\://url_of/the_server","project_name")

to get a kappa client that uses the REST API hosted by http://url_of/the_server and deals with project project_name.

or do:

import kappy
client = kappy.KappaStd()

to get a kappa client that uses a kappa agent installed locally. Add a string argument specifing the path/to/KaSimAgent to use a specific agent.

A minimal example of usage is:

model = "\
%agent: A(x[x.A]) \
%var: n_0 100 \
%var: k_on 1e-2 \
'rule' A(x[.]), A(x[.]) <-> A(x[1]), A(x[1]) @ k_on, 1 \
%plot: |A(x[.])| \
%init: n_0 A()"
client.add_model_string(model)
client.project_parse()
sim_params = kappy.SimulationParameter(pause_condition="[T] > 100",plot_period=1)
client.simulation_start(sim_params)
client.wait_for_simulation_stop()
results = client.simulation_plot()
client.simulation_delete()
# Rerun with some overwritten values for algebraic variables
client.project_parse(k_on=5e-2,n_0=500)
client.simulation_start(sim_params)
client.wait_for_simulation_stop()
results' = client.simulation_plot()
client.shutdown()

Tests

Launch the core/integration tests by make check.

Regenerate the reference files if you've changed something in the outputs by make build-tests

Launch python tests by nosetests (after having followed the "Get your own build" section).

kappatools's People

Contributors

antoinepouille avatar antonkulaga avatar aznmonkey avatar bgyori avatar dependabot[bot] avatar ethulhu avatar feret avatar hmedina avatar jonathan-laurent avatar lykimquyen avatar majorseitan avatar pagreene avatar phanimahesh avatar pirbo avatar reubenj avatar thierry-martinez avatar vd1 avatar wwaites avatar yarden avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kappatools's Issues

bug in wake up map

Following model
'glue' BASE(b53),BASE(b35)->BASE(b53!0),BASE(b35!0)

'TA grow' ->BASE(cA,wT)

Doesn't find activation between 'TA grow' and 'glue'

Influence map bug

In the following model:

%agent:A(x)
%agent:B(x)

'ab' A(x) -> A(x!1),B(x!1)
'a..b' A(x!_) -> A(x)

%init: 10 A

Influence map should show 'ab' <--> 'b..a' but only shows 'a..b' --> 'ba'
This results in incorrect simulations.

Rate laws

I would suggest a little more flexibility:

  • one syntax for the usual mass action case, including the LHS implicitly: @ real_number
  • another syntax for the general case, not including the LHS implicitly: @@ some_expression [or some better syntax]

Overestimation of activity when no clashes are possible

Hi all,

Same system as issue #39:

%agent: a()
%agent: b()
%agent: c()
'AB' a() -> b() @ 1
%obs: 'A' a()
%obs: 'C' c()
%init: 100 a()
%mod: 'A' < 10 do $ADD 1 c() until [false]

Now my problem is that KaSim generates null events even though there are no possible clashes in this system, as far as I can tell.

> KaSim -i kappa_bug.ka -e 100 -p 100 -o kappa_bug.out
...
Simulation ended (eff.: 0.724638)

KaSim version: 1.08_260911

problem with perturbation

I have a bug related to perturbations in the latest version (perhaps also in some earlier ones,
but I have used perturbations succesfully).

Here is my code:

%agent: A(e01,x01)
%init: 10 A(e0,x0)
# injection
'inj' A(e0) -> A(e1) @ 0
# futile activity
'flip01' A(x0) -> A(x1) @ 1
'flip10' A(x1) -> A(x0) @ 1
%var: 'A' A(e0)
%var: 'B' A(e
1)
%plot: 'A'
%plot: 'B'
%mod: [T] > 100 do 'inj' := [inf]

The simulation stops around 100+epsilon in the correct state but
does not go any further

Any idea what is wrong? Something in my code?
Vincent

snapshot naming

It would be useful to name a snapshot other than the default "snap_$eventnum.ka"? I will be running 100+ jobs at a time on a cluster at some point and needing a way to discern which snapshot came from which simulation.

Currently the snapshot only outputs the event number and time within the simulation. Having the command line or kappa file names in the snapshot file would be helpful, but being able to name the snapshot file itself would be ultimately preferable.

Ryan

variables and perturbations

a useful trick with systems where equilibrium happens in t time units is to "move" the equilibrium by using a sequence of perturbations separated by say 2*t - eg one can vary an off-rate parameter and get all the answers in a computationally cheap way in just one simulation

but variables such as k_off cannot be modified via the perturbation syntax in KaSim at the moment - it would be nice to be able to do this

option --dot-output

I get a really nice snapshot either in Kappa (in which case i can put it in the KF to see it) - or in dot in which case i have no idea how to visualize it - graphviz gives me a funny rendering. What should i use?

Rate laws

I would suggest a little more flexibility:

  • one syntax for the usual mass action case, including the LHS implicitly: @ real_number
  • another syntax for the general case, not including the LHS implicitly: @@ some_expression [or some better syntax]

Stalled models should check for perturbations

If model has a deadlock (no rule can be applied) at time t, and if there is a perturbation at time t+Dt then it should increment time of Dt and apply the perturbation.

Note that if it deadlocks at event E and a perturbation is defined at event E+dE it should deadlock (and output a warning)

Rule and observable names in influence map

Right now the influence map displays all rule and observable nodes with the full Kappa pattern strings. For readability and ease of interpretation, it would be nice to have the option to use rule names and observable names in the influence map instead.

variables/vars no := symbol

The manual incorrectly states that a var declaration uses :=.
But in fact writing

%var: 'homodimer' := A(a1!1),A(a1!1)

will give an error:

Error (agents.ks) line 6, character 20: Variable 'homodimer' should be either a pure kappa expression or an algebraic expression on variables

One should write - as with rules:

%var: 'homodimer' A(a1!1),A(a1!1)

--cflow raises run time error "Causal.record: incomplete embedding"

I use the following model: (essai.ka)

B(a!),C(a~u) -> B(a!),C(ap) @ 1
A(b) -> @ 1
C(a!_) -> C(a) @2
-> A(a!1,b),B(a!1) @10
-> C(a
p) @10

%init: 10 A(a!1,b),B(a!1)
%init: 10 C(au!1),C(ap!1)

KaSim -i essai.ka --cflow --implicit-signature -e 20 -seed 560966040
raises _Runtime error Causal.record: incomplete embedding_

whereas

KaSim -i essai.ka --cflow --implicit-signature -e 20 -seed 298905525
works fine.

data-base of simulations?

here is an idea: when running a simulation it would be nice to have an option to get an archive of 1) all the files used, 2) the command line used and even possibly 3) the output files themselves - to guarantee the replayability of the simulation

a simpler version of this idea is to give as a default long name for an output file the command-line that generated the file - with an additional number to distinguish it from the previous ones

in both cases the intention is to make it simpler, when one works with different variants of a model, to map result files to variants of the model and conditions in which they were produced (aka the context of the simulation)

to go a little further, we could have an entire data-base of models and simulations - which we could interact with by scripting (I know MLstate has done some work on this perhaps we should ask them?)

Version 1.08 does not have --eclipse

The version 1.08 doesn't have the --eclipse option that causes the plugin for it not to produce the expected outputs. Kindly look into the same.

invariant violation

I just downloaded v 1.08.1_280911 having been using 1.08_220811. Both the sample models and models I have used successfully with the previous version give the error:

_Runtime error Dynamics.diff: invariant violation_

This seems to happen during the compilation of the rules.

Ryan

Dual Rate Rules behaving weird

Given the code:

%agent: Subunit(Link, Recog)
%agent: Link(Kin, Sub)
%agent: Kinase(Cat)
%agent: Prot(Recog, X1~un~ph, X2~un~ph)

'Kin.Link' Kinase(Cat), Link(Kin) -> Kinase(Cat!1), Link(Kin!1) @ 1.0e-4
'Kin..Link' Kinase(Cat!1), Link(Kin!1) -> Kinase(Cat), Link(Kin) @ 1.0e-2

'Link.Sub' Link(Sub), Subunit(Link) -> Link(Sub!1), Subunit(Link!1) @ 1.0e-4
'Link..Sub' Link(Sub!1), Subunit(Link!1) -> Link(Sub), Subunit(Link) @ 1.0e-2

'Sub.Prot' Subunit(Recog), Prot(Recog) -> Subunit(Recog!1), Prot(Recog!1) @ 1.0e-4
'Sub..Prot' Subunit(Recog!1), Prot(Recog!1) -> Subunit(Recog), Prot(Recog) @ 1.0e-2


'Kin.().Prot|X1*' Kinase(Cat!_), Prot(Recog!_, X1~un) -> Kinase(Cat!_), Prot(Recog!_, X1~ph) @ 0.0(1.0e0)
'Kin.Link.Sub.Prot|X2*' Kinase(Cat!1), Link(Kin!1, Sub!2), Subunit(Link!2, Recog!3), Prot(Recog!3, X2~un) -> Kinase(Cat!1), Link(Kin!1, Sub!2), Subunit(Link!2, Recog!3), Prot(Recog!3, X2~ph) @ 1.0e0

%init: 10000 (Link, Kinase, Subunit, Prot)

%obs: 'Sub|X1*' Prot(X1~ph?)
%obs: 'Sub|X2*' Prot(X2~ph?)

If the rule:

'Kin.().Prot|X1*' Kinase(Cat!_), Prot(Recog!_, X1~un) -> Kinase(Cat!_), Prot(Recog!_, X1~ph) @ 0.0(1.0e0)

is rewritten as:

'Kin.().Prot|X1*' Kinase(), Prot(X1~un) -> Kinase(), Prot(X1~ph) @ 0.0(1.0e0)

the result is that site X1 remains in state un perpetually, instead of tracking the dynamics of the sister site X2.

Invalid semantics of default interface

the model

%agent: A(x)
A,A -> A(x!1),A(x!1) @ [inf]

triggers the warning:

WARNING: agent 'A' is deleted by rule because its interface is not compatible with right hand side
When correct interpretation of "don't care don't write" should be "whatever the interfaces of As are initially, bind them on x".

warning during model initialization

Currently there is no warning during initialization for rules with oddities, such as rules with no rates (eg A(x),B(x) -> A(x!1),B(x!1) ). I think some sort of warning similar to that given in simplx would be useful to detect rules like this. The model ran without problems, and I assume that a rate of 0 was given to the rule.
Also I have unknowingly run models with rules that have no space between @ and the rate (eg A(x),B(x) -> A(x!1),B(x!1) @3e-05 ). Once again no warning or error appeared so I assume again that the rule executed normally and with the desired rate, but some sort of warning for these small typos would be nice.

ryan

Perturbation is never triggered

The following system:

%agent: a()
%agent: b()
%agent: c()
'AB' a() -> b() @ 1
%obs: 'A' a()
%obs: 'C' c()
%init: 100 a()
%mod: 'A' < 10 do $ADD 1 c() until [false]

run with the command line KaSim -i test.ka -e 100 -p 100 -o test.out
never introduces a c() agent.

tested KaSim versions: 1.07 and 1.08

use vars in the %init as well?

This way we could rescale the population/volume by touching one parameter which would modify both init and the rate laws (depending on the molecularity).

warning "do you want to erase?" appears twice

warning "do you want to erase?" which appears when one overwrites a data file, appears twice

File 'ts2.out' already exists do you want to erase (y/N)? y
File '/Users/Vincent/bio/et/et1/kasim/ts2.out' already exists do you want to erase (y/N)? y

wrong activation in the influence map

here is an unexpected influence map; KaSim seems to think that
A(x!1,y!1) and
A(y!1),A(x!1)
can be glued

here is the model

%agent: A(x,y)
%init: 100 A(x,y)
'sb' A(x,y) -> A(x!1,y!1)
%obs: 'AA' A(y!1),A(x!1)

and the command to generate the faulty influence map
./KaSim -i example.ks -im s.dot -e 0

Random.int exception

On some plateform, KaSim raises Random.int exception during pseudo random number seeding

Implicit signatures.

Implicit signatures is not working with agent that are not in the intitial state.
(eg. see agents that are created dynamically for instance)

Questions are not prompted on the proper output channel ?

When the output is redirected into a file, the questions are not prompted in the terminal, but in the file.

For instance, if I enter :
KaSim -i essai.ka -p 10 -e 60 > LOG
and if the file data.output already exists, then the simulator is stucked waiting for the end-user to answer to a question that is in the LOG file, but not on the terminal.

Maybe stderr would be better than stdout.

Implicit signature does not work with variables.

With the following model:

A(x,y) ->
A(x),B(y) -> A(x!1),B(y!1)
A(x!1),B(y!1) -> A(x),B(y)
A(x) ->
-> A(x,y)
A(y),A(y) -> A(y!1),A(y!1)

%var: 'A' A(x)

%init: A(x,y)
%init: B(y)

KaSim complains:
_Error (essai.ka) line 8, char 11: Agent 'A' is not declared_

even when the "--implicit-signature" command line option is used.

Problem in the influence map

Activation map is wrong with the following kappa file :

%agent: A(x)

%agent: Tick(x01)

'intro' -> A @ 0.0

'tick0' Tick(x) -> Tick(x~0)

'tick1' Tick(x) -> Tick(x~1)

%obs: '0' Tick(x~0)

%obs: '1' Tick(x~1)

%obs: 'A' A

%mod: '0' > '1' do 'intro':= `inf

%mod: 'A' > 5 do 'intro':= 0.0

%init: 3 Tick(x~1)

2 runtime errors

Both of the following errors occur during simulation after a successful compilation of a kappa file:

  1. _Runtime error State.negative_update: Invalid_argument("Node.get_lifts: node 0 has no site 4")_
  2. _Runtime error State.negative_update: Node #84501 is no longer in the graph and injection 0[3->62826,2->14070,1->84501,0->67561] of mixture Ste5(ste11!0,ste5!1),Ste11(ste5!0),Ste5(ste5!1,ste7!2),Ste7(S359_T363~p,ste5!2) was pointing on it!_

Each error is consistent to a set of initial conditions, although the rules and the agent declarations in each kappa file are identical. I am unsure what the runtime errors are referring to, however the second always occurs with a homodimer of Ste5 which is the only agent that dimerizes. The model is too large to post on the forum(~300 rules), but I would be happy to email it if needed.

ryan

snapshot output

currently snapshots output the following:

Snapshot [Event: 38039274, Time: 3498.000079]

%init: 3
Kss1(T183p,Y185u,dock!0),Ste11(S302_S306_S307u,degradationu,mapk!0,ste5)
%init: 23
Ste2(gpa1,pheromone,sst2)
%init: 3573
Gpa1(nuc~GDP,ste2,ste4)

it seems that there is something preventing the snapshot from being in kasim's initial condition syntax

ryan

Data files do not always stop at tmax

the -t T -p N option yields data files that do not always stop at T (with N+1 data points, i * T/N, i=0,...,N) but sometimes go several iterations beyond T. This seems to be a stochastic behavior...

For example, use the attached test.ka with
KaSim -i test.ka -t 1 -p 30 -seed 996313470
behaves as expected

KaSim -i test.ka -t 1 -p 30 -seed 850995465
does not.

It appears that when the time advance Dt is larger than a few time intervals T/N you correctly write out the (same) system state for as many T/N steps as needed to catch up with Dt. That's clearly desired. However, you also do this when you run over T

bizarre debug output

I am running this very simple model

%agent: A(x,y)

%obs: 'G2' A(y!2),A(x!2,y!1),A(x!1)

%init: 1000 (A(x,y!3),A(x!3,y!2),A(x!2,y!1),A(x!1,y))

'dissoc' A(y!1),A(x!1) -> A(y),A(x)

and kasim outputs 1000's of messages like that

Node 0 is of type A
Node 1 is of type A
Node 2 is of type A
Node 3 is of type A

is it possible to get rid of this?

variables in initial conditions

A bug is present when using a variable as a value for an initial condition. For example:
...
%var: 'num' 1000
%init: 'num' A,B
...
returns "num is not declared" error.
This only occurs when the variable is used in the initial conditions. 'num' was successfully used with the expression
%mod: ([T] [mod] 'num') = 0 do $SNAPSHOT
in the same file.
Also, one of the example files in the distribution (abc.ka) attempts to use a variable as an initial condition with the same result.

KaSim manual perturbation example doesn't work

Hi,
I just copy-pasted a perturbation example from KaSim's manual and it doesn't work.

%agent: A()
A() -> @ 1
%init: 100 A()
%mod: ([mod] [E] 10)=0 do $SNAPSHOT until [false]

I get this:

$ ~/bin/KaSim_1.08_linux_x86 -i example.ka -e 100 --dot-output
Parsing example.ka...
Error (example.ka) line 4, character 12: Syntax error

KaSim's version is 1.08_210711

Cheers,
Ricardo

KaSim speed

I downloaded and compiled KaSim 1.07_300511 and noticed that it was substantially slower than the previous version I had, and is also slower than simplx for comparable simulations with regard to the simulation length, number of agents and number of rules. It was sufficiently slow that I did not test it with the larger rule set that gave me the runtime errors. The previous version I had been using (from which I received the runtime errors) was 1.06_240511.

Another item of note (though trivial) is that the title of the Terminal tab in which KaSim is active no longer says "KaSim", but "ocamlrun" instead.

semantics of the -p option

What is the semantics of option -p

If i run on a model that deadlocks after 3000 steps

KaSim -i g2.kas -t 10 -p 3000 -o out2

I obtain what seems to be

  1. a sampling of points done uniformly by unit of time - whereas I want
    uniformly by unit of event (in this case i want all events)
  2. the output file out2 end with null events, so the sampling include null events
    which does not make sense from a plotting point of view (just in terms of time
    increments)

Flux map is unreadable

Graphical representation of the flux importance is not adequate and leads to too big or thin arrows. Should find another way to normalize the size of the arrows.

Semantics of semi-link deletion

Rules of the from A(x!_ ),B(x!) -> A(x! ),B(x)
are interpreted by KaSim as a bond deletion when applied to the graph A(x!1),B(x!1)
The correct semantics should be a null event

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.