Code Monkey home page Code Monkey logo

markdown-exec's Introduction

Markdown Exec

ci documentation pypi version gitpod gitter

Utilities to execute code blocks in Markdown files.

For example, you write a Python code block that computes some HTML, and this HTML is injected in place of the code block.

Installation

With pip:

pip install markdown-exec[ansi]

The ansi extra provides the necessary bits (pygments-ansi-color and a CSS file) to render ANSI colors in HTML code blocks. The CSS file is automatically added to MkDocs' extra_css when Markdown Exec is activated via plugins (see below).

Configuration

This extension relies on the SuperFences extension of PyMdown Extensions.

To allow execution of code blocks, configure a custom fence from Python:

from markdown import Markdown
from markdown_exec import formatter, validator

Markdown(
    extensions=["pymdownx.superfences"],
    extension_configs={
        "pymdownx.superfences": {
            "custom_fences": [
                {
                    "name": "python",
                    "class": "python",
                    "validator": validator,
                    "format": formatter,
                }
                # ...one fence for each language we support:
                # bash, console, md, markdown, py, python, pycon, sh, tree
            ]
        }
    }
)

...or in MkDocs configuration file, as a Markdown extension:

# mkdocs.yml
markdown_extensions:
- pymdownx.superfences:
    custom_fences:
    - name: python
      class: python
      validator: !!python/name:markdown_exec.validator
      format: !!python/name:markdown_exec.formatter
    # ...one fence for each language we support:
    # bash, console, md, markdown, py, python, pycon, sh, tree

...or in MkDocs configuration file, as a plugin:

# mkdocs.yml
plugins:
- search
- markdown-exec

We do recommend enabling Markdown Exec with the MkDocs plugin if you are using MkDocs: it will take care of adding relevant assets (CSS/JS) to the final site when needed.

Usage

You are now able to execute code blocks instead of displaying them:

```python exec="on"
print("Hello Markdown!")
```

The exec option will be true for every possible value except 0, no, off and false (case insensitive).

Below you can see an example of running a bash script that is expected to return a non-zero exit code:

```bash exec="1" source="tabbed-left" returncode="2"
grep extra_css README.md && exit 2
```

See usage for more details, and the gallery for more examples!

markdown-exec's People

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

Watchers

 avatar  avatar

markdown-exec's Issues

Cache

Is your feature request related to a problem? Please describe.
Generating text/images/svg can slow down rendering a lot.

Describe the solution you'd like
Allow to cache things either during serve (memory), or across multiple builds (filesystem).
A cache option could be added. If boolean value, use hash of the code block's contents as ID.
Otherwise use cache option value as ID. Only useful for cross-builds cache.
Items can then be deleted from the cache by deleting the files in /tmp with the ID as name.

stdout from "external" functions not shown

Describe the bug

Stdout created in functions not defined in the code block itself will not be rendered (but shows up in the stdout of the mkdocs run)

To Reproduce

I expect the same rendered output in all three code blocks below:

print("hello")
def hello():
    print("hello")
hello()
from somepackage import hello   # same definition of hello as before
hello()

The last block executes, and its output shows up in the mkdocs stdout, but the "result" block created by markdown-exec remains empty.

Expected behavior

All three blocks should give the same result.

System (please complete the following information):
mkdocs 1.4.3
markdown-exec 1.6.0
Platform: linux
OS: posix
Python: 3.9.16

Feature request: default behaviour for code blocs

I'm using Code Emiter plugin for Obsidian which allows me to run code from code blocks, when I'm writing notes which I later publish to mkdocs with material theme.
Could you provide option for default behaviour for codeblocks?

Example:

Block with exec=on doesn't allow Code emitter to run

```python exec="on"
print("Hello Markdown!")
```

Maybe some config in mkdocs.yml allowing to execute regular codeblock might be good idea?
It would be nice, because:

  • documets will be more portable
  • person can focus more on what to write and not how to do it (most important thing I think)

bug: ANSI escape codes in `jax.ClosedJaxpr` are not being converted to HTML

Description of the bug

Description is title.

I'm using JAX within some code blocks which I'm executing using markdown-exec -- e.g.

```python exec="yes" source="tabbed-left" session="ex-dida"
# A little numerical example.
def f(x, y):
    z = x * y
    z = z * z
    q = z * y
    p = q * q
    return p

print(jax.make_jaxpr(f)(3.0, 5.0))

The result here does not have the ANSI escape codes converted:

{ �[34m�[22m�[1mlambda �[39m�[22m�[22m; a�[35m:f32[]�[39m b�[35m:f32[]�[39m. �[34m�[22m�[1…
    �[39m�[22m�[22mc�[35m:f32[]�[39m = mul a b
    d�[35m:f32[]�[39m = mul c c
    e�[35m:f32[]�[39m = mul d b
    f�[35m:f32[]�[39m = mul e e
  �[34m�[22m�[1min �[39m�[22m�[22m(f,) }

Version:
I'm using version 1.7.0 of markdown-exec

Setting source="console" is incompatible with result="ansi"

Describe the bug

It seems that it is not possible to include ANSI output while still showing the command that was executed.

To Reproduce

```bash exec="1" result="ansi"
ansible-lint -t idempotency playbook.yml
```

```bash exec="1" source="console" result="ansi"
ansible-lint -t idempotency playbook.yml
```

Expected behavior

Use of result=ansi should not depend of value of source.

Screenshots

  • The first example renders ansi correctly but it does not include the command line.
  • The second example includes the command line executed but fails to render ANSI and adds some extra backticks which break the rendering.

Additional context
Add any other context about the problem here.

Consideration for `mkdocs get-deps` regarding the `[ansi]` extra

Hi!
I am thinking how to make this plugin work out of the box with mkdocs get-deps.
Most people would probably want it to suggest markdown-exec[ansi] but it currently gives you just markdown-exec and there's no way to make it include [ansi].

Here are some things that could be done:

  1. Just make pygments-ansi-color a default dependency of this plugin - any big reason why not?

  2. Add a new config that people should use :

     - markdown-exec:
         ansi: required   # one of: [off, required, auto], default: auto

    (bonus compared to the current behavior: it also guards against the ansi feature silently not working - the required setting would break on missing import)

    in which case we can put this option into extra_dependencies in https://github.com/mkdocs/catalog

  3. Somehow just directly put markdown-exec[ansi] into https://github.com/mkdocs/catalog

Separately, I also noticed by reading the implementation that the CSS file is currently also always included into the final site, whether or not the ansi feature was successfully enabled.

Support pycon code blocks

Is your feature request related to a problem? Please describe.
This would allow dynamic examples in Python docstrings for example. See mkdocs/mkdocs#2835

Describe the solution you'd like
Support the pycon specifier. Then keep only lines starting with >>> , and remove those before executing.

[Feature] Output logging in rendered output

Is your feature request related to a problem? Please describe.
I am using markdown_exec to have examples which are also run and show their output. Part of this would be nice to display the logging output too.

Describe the solution you'd like
An annotation similar to exec=True except you specify the logging level, i.e. logs=INFO.

Describe alternatives you've considered
I previously injected hidden code into the code blocks that would take the buffer that you overwrite the print builtin with and set this to the outstream of rich.print. I could do something similar for logging but I would prefer not to rely on private functionality.

I recently did so with sessions, injecting in session["__name__"] = "__main__" to run the example script's __main__ block, as well as try solve issues to pickling that occur when using markdown exec but to no avail. A recent PR changed the name of the global variable so it was a good lesson not to rely on the private functionality.

Additional context
The logging from the running examples actually gets streamed to the session running mkdocs --serve which pollutes the build output. It would be good to redirect this anywho.

code block exited with non-zero status does not provide enough information for addressing the issue

Describe the bug
When execution of a bash code block fails, there is not context information provided, making impossible to debug the issue (which can also happen on CI).

WARNING  -  �[0mmarkdown_exec: Execution of bash code block exited with non-zero status

Considering that I have 10+ command execution inside docs, finding the one that failed on CI become a gamble.

Expected behavior

  • display filename causing the failure
  • display command that returned the error, including the returned error
  • display both stdout and stderr output, so user can figure-out the build failure

Screenshots

System (please complete the following information):

  • Markdown Exec version: [e.g. 0.2.1]
  • Python version: [e.g. 3.8]
  • OS: [Windows/Linux]

Additional context
Add any other context about the problem here.

[Feature] Option to globally disable execution

Is your feature request related to a problem? Please describe.
For documentation with lots of executing example and live-reload, this can be a bit slow at times and no necessary while building non-code parts of the documentation. I'd like to turn it off while
focusing on the text and later enable it while working on code snippets.

Describe the solution you'd like

plugins:
  - markdown-exec:
        enabled: !ENV [SOME_ENV_VAR, false]

This is similar to how the offline plugin works.

Describe alternatives you've considered
None really, I tried the above solution in case it was a nice global option that mkdocs provided but sadly it's not.

Additional context
I'd be happy to provide a PR with a little bit of guidance on:

  • Where do options to a plugin get parsed, I'm unfamiliar with developing mkdocs plugins.
  • What would be the least disruptive solution with a pointer or two.

Compability with snippets

Is your feature request related to a problem? Please describe.
Maintainability gets harder as our documentation grows. It would be great, if mkdocs exec would be compatible with snippets so that we can extract Python code to a seperate place and inject it during the build.

https://stackoverflow.com/questions/76523189/is-there-a-way-to-include-and-execute-a-python-script-and-render-the-output-in-m

Describe the solution you'd like
Adding any way of importing and executing files would be awesome! It would help with maintainability, reduce duplicate code, reduce git diffs,...

Shell support

Allow executing shell code blocks. Use the interpreter specified as language (sh/bash/zsh/fish/etc.).
In fact, it would be like supporting every other interpreter (ruby, perl).
Not sure if this is feasible at once or if we need special casing for each.

No output without print and no line breaks

Describe the bug
First of all, thanks for this very nice plugin. There are two issues, probably related:

  1. Output is only generated with print, not by calling the variable/object.

    This will produce nothing:
    '''python exec="on" source="material-block"
    x=1
    x
    '''

    This will work:
    '''python exec="on" source="material-block"
    x=1
    print(x)
    '''
    1

  2. Line breaks are not respected.

    This will print the two numbers next to each other, rather than below each other.
    '''python exec="on" source="material-block"
    x=1
    y=1
    print(x)
    print(y)
    '''
    1 2

Expected behavior
I would expect the output to be as in the console, so that the code examples are representative of real use.

System (please complete the following information):

  • Markdown Exec version: 1.6.0
  • Python version: e.g. 3.10
  • OS: Windows

Unable to specify the pygments formatter to use on received output

Describe the bug
Executed problems can produce ANSI output, which mkdocs can render using the ansi pygments formatter.

Still, this plugin does not allow us to specify which formatter to use and uses markdown.

This means that two undesired things will happen when documenting program output:

  • if the output contains ANSI, the rendering will be messed
  • if the output is plain text, some random keywords will be highlighted in the output

To Reproduce
Steps to reproduce the behavior:

  1. Gran a CLI tool that produces ANSI output, like ANSI test file
  2. Add a markdown-exec block the runs it
  3. What the rendered output.

Expected behavior

We need to allow exec to work similarly to already valid ANSI formatter

```ansi
```

Note that while testing, you might miss to see the colors but the ANSI will render fine. If you use inspect, you will see that class colors were added to the HTML and they will render once you add the extra css needed for them.

Screenshots

Example of an ANSI test file using the block above:

Example of undesired markdown coloring on a command line output:

Example of failure to process ANSI escapes:

System (please complete the following information):

  • Markdown Exec version: 1.0.0
  • Python version: 3.11
  • OS: MacOS

Additional context

I did observe that there is already support for recognizing the output as JSON or HTML, so I guess it should not be too hard to add an option where we can declare the expected output format, so it would render correctly.

If you could give some hints on how this can be addressed, I would be happy to contribute a PR. I was quite pleased about the current plugin behavior and its really good documentation.

feature: Issue warning if pymdownx.superfences is not enabled

Is your feature request related to a problem? Please describe.

Several users, including myself, couldn't understand why code blocks weren't rendered. It was because the pymdownx.superfences was not enabled. The readme does not really explain that.

Describe the solution you'd like

Add a note to the readme, and when using as a plugin, detect when pymdownx superfences is not enabled, to issue an error.

Describe alternatives you've considered

Just docs. But we can do better.

Additional context

#37

Appearance of code block headings in the navigation sidebar

I am trying to get the same beautifully looking sections in the navigation sidebar (left) as in the documentation of this very plugin : markdown_exec/ 😄 :

2024-01-12T16:03:40,220039700+02:00

While there is an option for the headings to appear in the table of contents, I cannot find any documentation about the way this is done for the navigation sidebar, as seen in the API reference page. I can only trace and guess that this is generated via the gen_ref_nav.py script. Unless I miss something obvious, would it be considerable to expose this functionality directly to users of markdown-exec ?

Isssue with Abbreviations

There seems to be an issue when the abbr extension is used in conjunction with markdown-exec.

I have following markdown content (Screenshot as I cannot have two a ``` fence inside another)

grafik

The final output however has the abbreviation glossary attached below the markdown-exec code fence:

grafik

Mkdocstrings use - Allow printing other object than `str`

Hi, first thanks for this package and the mkdocstrings suite in general !

Is your feature request related to a problem? Please describe.
Executing code that is supposed to output numpy array does not work.

Describe the solution you'd like
To be allowed to output other kind of objects than str.

Describe alternatives you've considered
I tried converting objects to str as a workaround, but the rendering is not satisfying enough and writing print(str(obj)) in the python code is a bit misleading for future reader of the documentation

Additional context
Code

import numpy as np

xyz = np.array([
    [0,   0,   2,   5,   0,   1,   2,   0,   4,   3,   1,   2,   4],  # noqa
    [0,   0,   2,   5,   0,   1,   2,   0,   4,   3,   1,   2,   4],  # noqa
    [0,  -2,  -4,   1,  -5,   0,  -3,  -3,  -2,   2,  -3,  -2,   0]   # noqa
])

print(xyz)

Result in documentation :

TypeError: sequence item 0: expected str instance, numpy.ndarray found

Support named blocks

Hello, thanks a lot for the nice package. I would like to ask whether it is possible to use/add named blocks similarly to Julia Documenter.jl. I mean that I declare a variable in one block

```python exec="true"
x = 1
```

and then use it in another block

```python exec="true"
print(x)
```

I believe that this could be done by merging the blocks with the same name. Probably not the most time-efficient way as some code would be evaluated multiple times but it should work :)

Thanks a lot,

Lukas

`source = "tabbed-right"` seems to conflict with annotations in Material

Describe the bug
There's really two bugs here. The first bug is that I've enabled pymdownx.tabbed but the tabs don't appear to be working when I set source="tabbed-right".

Secondly, if I have any annotations using Material -- using the tabbed option breaks them -- e.g.

Screenshots
Before tabs (here, I'm using source="console"):

image

After, with source = "tabbed-right":

image

System (please complete the following information):

  • Markdown Exec version: 1.2.0
  • Python version: 3.11
  • OS: Mac OS X

Here's my plugins and markdown_extensions:

plugins:
  - search
  - offline
  - markdown-exec
  - git-revision-date-localized:
      enable_creation_date: true
      type: date
  - mkdocstrings:
      enabled: !ENV [ENABLE_MKDOCSTRINGS, true]
      custom_templates: templates
      default_handler: python
      handlers:
        python:
          options:
            show_source: true
            show_root_heading: true

markdown_extensions:
  - attr_list
  - md_in_html
  - admonition
  - pymdownx.details
  - pymdownx.tabbed
  - pymdownx.highlight
  - pymdownx.superfences:
      custom_fences:
        - name: mermaid
          class: mermaid
          format: !!python/name:pymdownx.superfences.fence_code_format
  - pymdownx.arithmatex:
      generic: true
  - toc:
      permalink: true

Allow integrating output in the source itself

Is your feature request related to a problem? Please describe.
Following #1 and #2, it would be nice if we could integrate the output of Python code directly within the source itself, most commonly at the end.

Describe the solution you'd like
An integrated-above (or concat?) option for the show_source configuration. Basically: output = code_block("python", source_block + "\n" + output).

It would allow this:

def func(name):
    """Return "hello" plus name.

    Example:
        ```pycon exec="yes" show_source="integrated-above" capture="out"
        >>> from module import func
        >>> print(func("Steve"))
        ```
    """
    return f"Hello {name}!"

Result:

>>> from module import func
>>> print(func("Steve"))
Hello Steve!

feature: Add option to specify initial number of lines in pyodide fence editors

Is your feature request related to a problem? Please describe.

If I want to add an editor with just three lines, I'd like to spare some vertical space. Currently it always has the same number of lines.

Describe the solution you'd like

Allow configuring number of lines in pyodide editors.

Describe alternatives you've considered

/

Additional context

/

Add a cwd option to console

Using console formatter to create usage examples but at this moment there is no way to set the CWD for the executed command.

By adding a cwd/chdir optional argument, this can be avoided.

feat: Support specifying terminal width

Discussed in #33

Originally posted by NikosAlexandris January 26, 2024
Rich table output in the console is truncated (i.e. table column names are incomplete), for example : https://nikosalexandris.github.io/rekx/how_to/inspect/. See in this pages source code the output of commands wrapped inside a block

    ``` bash exec="true" result="ansi" source="above"
    ```

Any idea how to "fix" this ?
See also : squidfunk/mkdocs-material#4964 (comment).


We could provide a new option to set the terminal width in the subprocess. Basically export COLUMNS=1000.

@NikosAlexandris could try the following and let me know if it fixes your issue?

``` bash exec="true" result="ansi" source="above"
export COLUMNS=1000  # markdown-exec: hide
rekx inspect data/single_file/SISin202001010000004231000101MA.nc
```

Support capturing stdout and stderr

Is your feature request related to a problem? Please describe.
In the spirit of literate programming, and following #1, we should allow writers to use print in their Python code instead of output_markdown or output_html (those two functions are still useful when the source is not shown).

Describe the solution you'd like
An option like capture="out", (capture="err", capture="outerr").

bug: can not run the example

Description of the bug

I can not manage to get the example working

image

To Reproduce

  • python -m venv markdown
  • markdown\Scripts\activate.bat
  • pip install mkdocs==1.3.1 markdown-exec==1.7.0
  • mkdocs new test_mkexec
  • cd test_mkexec
  • add at the bottom of index.md
```python exec="on"
print("Hello Markdown!")
```
  • add in mkdocs.yml
plugins:
- search
- markdown-exec
  • mkdocs serve

Full traceback

INFO - Building documentation...
INFO - Cleaning site directory
INFO - Documentation built in 0.06 seconds
INFO - [17:25:07] Watching paths for changes: 'docs', 'mkdocs.yml'
INFO - [17:25:07] Serving on http://127.0.0.1:8000/
INFO - [17:25:07] Browser connected: http://127.0.0.1:8000/

Expected behavior

python code is interpreted and page show "hello world"

Environment information

(markdown) C:\workplace\test>pip list
Package Version


click 8.1.7
colorama 0.4.6
ghp-import 2.1.0
importlib-metadata 7.0.1
Jinja2 3.1.3
Markdown 3.3.7
markdown-exec 1.7.0
MarkupSafe 2.1.4
mergedeep 1.3.4
mkdocs 1.3.1
packaging 23.2
pip 23.2.1
pymdown-extensions 10.4
python-dateutil 2.8.2
PyYAML 6.0.1
pyyaml_env_tag 0.1
setuptools 65.5.0
six 1.16.0
watchdog 3.0.0
zipp 3.17.0

(markdown) C:\workplace\test>python --version
Python 3.11.6

I tried with latest of mkdocs & markdown-exec without better result

What am I doing wrong?

bug: Directory change dos not persist between code blocks executed on the same session

Description of the bug

Given that the current working directory is part of the state when executing code in a shell,
then the state does not persist between executed code blocks when changing to another directory.

To Reproduce

Enter in a directory, print its name and list files inside it :

```
bash exec="true" result="ansi" session="somesession" source="above"
cd somedirectory/
pwd
```

OR

``` bash exec="true" result="ansi" session="somesession" source="above"
cd somedirectory/
ls .
```

Print the current directory's name (or list its content), expected to be somedirectory (or the same content) from the previous commands :

``` bash exec="true" result="ansi" session="somesession" source="above"
pwd
```

Expected behavior

Given that the current working directory is part of the state, executing subsequent code blocks on the same session should remember previously executed code blocks that change the directory.

Environment information

python -m markdown_exec.debug
  • System: Linux-6.7.0-arch3-1-x86_64-with-glibc2.38
  • Python: cpython 3.11.6
  • Environment variables:
  • Installed packages:
    • markdown-exec v1.8.0

bug: source="tabbed-left" showing source vertically, rather than horizontally

Description of the bug

Here is my output, when using source="tabbed-left"

image

To Reproduce

mkdir mcve-mkdocs
cd mcve-mkdocs/
python3.11 -m venv .venv
. .venv/bin/activate
pip install mkdocs mkdocs markdown-exec[ansi]
mkdocs new .

Here's my mkdocs.yml file:

site_name: My Docs
markdown_extensions:
- pymdownx.tabbed
- pymdownx.superfences:
    custom_fences:
    - name: python
      class: python
      validator: !!python/name:markdown_exec.validator
      format: !!python/name:markdown_exec.formatter

Here's my docs/index.md file:

# Welcome to MkDocs

```python exec="true" source="tabbed-left"
print("I'm the result!")
```

Expected behavior

From https://pawamoy.github.io/markdown-exec/usage/ , I was expecting the source and output to be side-by-side, like this:

image

Environment information

python -m markdown_exec.debug  # | xclip -selection clipboard
  • System: Linux-5.10.102.1-microsoft-standard-WSL2-x86_64-with-glibc2.35
  • Python: cpython 3.11.6
  • Environment variables:
  • Installed packages:
    • markdown-exec v1.7.0

Additional context

bug: Don't always include ANSI CSS file

Description of the bug

Reported in #28: apparently the ANSI CSS file is always included in the final site. It should not be included if the ANSI extra was not installed.

bug: color is missing if I print a diff with rich.syntax

Description of the bug

I use markdown-exec to include the output of pytest in my documentation.
I use rich to generate some diffs during this run and have the problem that the red and green colors are missing in the diff.

image

I was able to reproduce this bug without pytest, but I have no idea if this is a markdown-exec or rich problem.

Can you please look into?

To Reproduce

see the repository

pip install -r requirements.txt
mkdocs serve

Expected behavior

I would expect that markdown-exec is able to produce the same colors which I also see in the terminal.

Environment information

python -m markdown_exec.debug  # | xclip -selection clipboard
  • System: Linux-6.1.0-18-amd64-x86_64-with-glibc2.36
  • Python: cpython 3.12.1
  • Environment variables:
  • Installed packages:
    • markdown-exec v1.8.0

Additional context

Don't render anything if output is empty

Is your feature request related to a problem? Please describe.
Using sessions to declare some variables. Output is empty. An empty paragraph is added to the HTML.

Describe the solution you'd like
Don't render anything when output is empty.

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.