vericast / nbconflux Goto Github PK
View Code? Open in Web Editor NEWnbconflux converts Jupyter Notebooks to Atlassian Confluence pages
License: BSD 3-Clause "New" or "Revised" License
nbconflux converts Jupyter Notebooks to Atlassian Confluence pages
License: BSD 3-Clause "New" or "Revised" License
e.g., <img>
is not a supported tag. Adding an image in a markdown cell causes a 400.
e.g. pandas added a stylesheet and style attributes between 0.19 and 0.21. Causes a 400
e.g. ---
in markdown becomes <hr>
but the storage format wants <hr />
Requires hooking into the md/html sanitization routines in nbconvert.
Nice tool! Is there any chance to support ipywidgets output? Of course not the fully interactive interface, but maybe only the rendered result? That would be gorgeous!
Hi,
Images included part of a markdown cell are not showing up in Confluence.
![alt text](images/someImage.png)
I modified the notebook to include images like this, but it's slightly clumsy as a new cell has to be inserted just for the image...
from IPython.display import Image
Image("images/someImage.png")
After running
nbconflux my_jupyter_nb.ipynb https://confluence_sample.org/page/viewpage.action?pageId=736763
.. the command prompt doesn't react to any input after request of "Confluence username:", I can't even abort using CTRL+C. Is this a known issue?
Just noticed: does this package only work with confluence hosted on atlassian.com?
I also tested this from a python-script with import: same problem - no response after "python convert.py"
You can expose this package directly to nbconvert (so you could use jupyter nbconvert --to confluence your.ipynb
) using entrypoints:
For example (from the docs):
setup(
...
entry_points = {
'nbconvert.exporters': [
'simple = mymodule:SimpleExporter',
'detail = mymodule:DetailExporter',
],
}
)
I've been trying to install nbconflux
(on Windows) using the command pip install nbconflux
and I always ran into the following error
Installing build dependencies ... done
Getting requirements to build wheel ... error
error: subprocess-exited-with-error
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> [3 lines of output]
error in nbconflux setup command: 'install_requires' must be a string or list of strings containing valid project/version requirement specifiers; Expected end or semicolon (after version specifier)
nbconvert>=5.3requeststraitlets
~~~~~~^
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> See above for output.
note: This error originates from a subprocess, and is likely not a problem with pip.
I thought it might be because of the latest version, thus, I went back to install different versions of nbconflux
(0.7.0, 0.6.1, 0.6.0, 0.5.1, 0.5.0) and all of them resulted in the same error.
On my virtual environment (Windows), I have nbconvert==7.11.0
already
I was extremely excited to hear about nbconflux at the Jupyter DC Pop-up, and even though it isn't entirely working right with our authentication, which is not username password, I can at least give this much feedback.
nbconflux notebooks/MissingTitle.ipynb 'https://this.is.not.real.gov/confluence/display/~davisda4/Test+Notebook
nbconflux notebooks/MissingTitle.ipynb 'https://this.is.not.real.gov/confluence/display/WSO/Jupyter+Notebook+Page+-+Missing+Titles'
More soon, after I figure out how to step it through our authentication.
Is there a way to remove code cells simply with a command line argument?
I know the README specifies how to do this with notebook tags.
Excludes input, output, or entire cells based on notebook cell tags noinput, nooutput, or nocell
But what if I didn't want to have to worry about adding tags to my notebook cells, and instead just wanted to do it from the command line. For example the way you can use the --no-input
and --no-prompt
flags in nbconvert
currently.
> jupyter nbconvert your_notebook.ipynb --to="html" --no-input --no-prompt
Loosely related to #19.
The QA version of my on-premise wiki has been updated to use OAuth2 supported by AWS Cognito which in turn is authenticating with SAML. I'm hoping no one at my organization plans to roll this out to production - but they do need to eventually move our confluence instance to the cloud.
I'm very far from needing a solution, but others may not be so lucky. I think something could be done with the python package requests-oauthlib
.
Hi, i am trying to use nbconflux, but i am not able to enable the CSS Macro, could you add some step by step to enable this feature, or add some link to this in the documentation, please? I am using confluence server here.
I have an idea to find the id of the page by space (key or title) and by page title. For a new page, the parent title could be given.
This would add a dependence (if I were to implement it) on jmespath. A search would have the following inputs:
A method for an exact search:
def find_page(session, baseurl, **kwargs):
cql_query_template = (
'type=page'
' and (space="{space:s}" OR space.title~"{space:s}")'
' and title="{title:s}"')
cql_query = cql_query_template.format(**kwargs)
response = session.get(baseurl + '/search', params={'cql': cql_query})
if not response.ok:
raise Something()
response_data = response.json()
if response_data['size'] != 1:
return None
page_id = jmespath.search('results[0].content.id', response_data)
page_link = baseurl + '/content/' + page_id
return page_link
This could be generalized to support multiple "strategies", each a function taking the session, baseurl, and kwargs. This makes the search function more maintainable:
def cql_search_strategy(cql_query_template):
def _strategy(session, baseurl, **kwargs):
nonlocal cql_query_template
cql_query = cql_query_template.format(**kwargs)
response = session.get(baseurl + '/search', params={'cql': cql_query})
# ....
return _strategy
exact_title_strategy = cql_search_strategy('type=page and (space="{space:s}" OR space.title~"{space:s}") and title="{title:s}"')
title_contains_startegy = cql_search_strategy('type=page and (space="{space:s}" OR space.title~"{space:s}") and title~"{title:s}"')
Hi,
Great tool! Would it be possible to have an option to exclude all cells by default and only include cells that I tag with a particular tag? Because in my use case, I don't want to include most of the details and export a simplified and clean report.
Let me know what you think.
Thanks!
Some characters do not appear to be escaped correctly when using the Math
class from IPython.display
.
Example:
the output cell of
from IPython.display import Math
Math(r"""\begin{eqnarray}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = & \frac{4\pi}{c}\vec{\mathbf{j}} \\
\nabla \cdot \vec{\mathbf{E}} & = & 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = & \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} & = & 0
\end{eqnarray}""")
gives error
400 Client Error: Bad Request for url...
But it works fine after taking out all the &
characters.
It is also possible to sign in with an Atlassian API Token for those scenarios where your organisation has employed multi-factor authentication as per: Use an API token
Sign into with your account. Under Security go to API Tokens then Create API Token. Give the token a meaningful label so that access can be revoked later. The token will be copied to the clipboard. Using Jupyter file editor create the token in the Jupyter environment and name the file confluence.token
.
The api key can be used by setting the environment variables:
CONFLUENCE_PASSWORD=$(cat confluence.token)
CONFLUENCE_USERNAME=<me>
CONFLUENCE_URL=$(cat confluence.url)
Then calling nbconflux <notebook>.ipynb $CONFLUENCE_URL
.
Using `CONFLUENCE_URL' was only to get around the paste to jupyter issue.
Hi All,
Is there a way to hide/remove the code cells?
So that I only see the markdown cells and the output of the code cells?
The package is broken due to nbconvert>=5.3
in the setup.py
Nbconflux doesn't work with nbconvert 6.0.0a0
The image is properly attached to the page, but is not displaying correctly. After I run nbconflux to update the page, and then request its content with body.storage expanded, I see this in the body.storage.value:
<ac:image><ri:url ri:value="https://wiki.nlm.nih.gov/download/attachments/146342104/output_15_1.png?version=3" /></ac:image>
However, when I fix this manually in the page with an attachment link, I see:
<ac:image ac:height="250"><ri:attachment ri:filename="output_15_1.png" /></ac:image>
It looks like the two lines that need a change are:
confluence.tpl line 148
confluence.tpl line 156
I will attempt a fix and get back to you.
Possible related issues: #17
Hi,
I get the following error when using the notebook_to_page function.
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/traitlets/traitlets.py in get(self, obj, cls)
534 try:
--> 535 value = obj._trait_values[self.name]
536 except KeyError:
KeyError: 'exporter'
During handling of the above exception, another exception occurred:
TraitError Traceback (most recent call last)
<ipython-input-2-9a4929330a3c> in <module>
8 url = "xxxxx"
9 nb_path = "xxxxx"
---> 10 html, resources = nbconflux.notebook_to_page(nb_path, url, CONFLUENCE_USERNAME, CONFLUENCE_PASSWORD)
11
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconflux/api.py in notebook_to_page(notebook_file, confluence_url, username, password, generate_toc, attach_ipynb, enable_style, enable_mathjax, extra_labels)
55
56 exporter = ConfluenceExporter(c)
---> 57 result = exporter.from_filename(notebook_file)
58 print('Updated', confluence_url)
59 return result
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconflux/exporter.py in from_filename(self, filename, *args, **kwargs)
345 # so stash it here for later lookup
346 self.notebook_filename = filename
--> 347 return super(ConfluenceExporter, self).from_filename(filename, *args, **kwargs)
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconvert/exporters/exporter.py in from_filename(self, filename, resources, **kw)
179
180 with io.open(filename, encoding='utf-8') as f:
--> 181 return self.from_file(f, resources=resources, **kw)
182
183
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconvert/exporters/exporter.py in from_file(self, file_stream, resources, **kw)
197
198 """
--> 199 return self.from_notebook_node(nbformat.read(file_stream, as_version=4), resources=resources, **kw)
200
201
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconflux/exporter.py in from_notebook_node(self, nb, resources, **kw)
307
308 # Convert the notebook to Confluence storage format, which is XHTML-like
--> 309 html, resources = super(ConfluenceExporter, self).from_notebook_node(nb, resources, **kw)
310
311 # Update the page with the new content
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconvert/exporters/html.py in from_notebook_node(self, nb, resources, **kw)
127 highlight_code = self.filters.get('highlight_code', Highlight2HTML(pygments_lexer=lexer, parent=self))
128 self.register_filter('highlight_code', highlight_code)
--> 129 return super().from_notebook_node(nb, resources, **kw)
130
131 def _init_resources(self, resources):
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconvert/exporters/templateexporter.py in from_notebook_node(self, nb, resources, **kw)
372 preprocessors and filters.
373 """
--> 374 nb_copy, resources = super().from_notebook_node(nb, resources, **kw)
375 resources.setdefault('raw_mimetypes', self.raw_mimetypes)
376 resources['global_content_filter'] = {
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconvert/exporters/exporter.py in from_notebook_node(self, nb, resources, **kw)
141
142 # Preprocess
--> 143 nb_copy, resources = self._preprocess(nb_copy, resources)
144
145 return nb_copy, resources
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconvert/exporters/exporter.py in _preprocess(self, nb, resources)
316 # to each preprocessor
317 for preprocessor in self._preprocessors:
--> 318 nbc, resc = preprocessor(nbc, resc)
319 try:
320 nbformat.validate(nbc, relax_add_props=True)
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconvert/preprocessors/base.py in __call__(self, nb, resources)
45 self.log.debug("Applying preprocessor: %s",
46 self.__class__.__name__)
---> 47 return self.preprocess(nb, resources)
48 else:
49 return nb, resources
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/nbconflux/preprocessor.py in preprocess(self, nb, resources)
58 # names and versions.
59 path = ('/rest/api/content/{page_id}/child/attachment?expand=version'
---> 60 .format(page_id=self.exporter.page_id))
61 resources['attachments'] = {}
62 while path:
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/traitlets/traitlets.py in __get__(self, obj, cls)
573 return self
574 else:
--> 575 return self.get(obj, cls)
576
577 def set(self, obj, value):
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/traitlets/traitlets.py in get(self, obj, cls)
546 )
547 with obj.cross_validation_lock:
--> 548 value = self._validate(obj, default)
549 obj._trait_values[self.name] = value
550 obj._notify_observers(Bunch(
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/traitlets/traitlets.py in _validate(self, obj, value)
608 return value
609 if hasattr(self, 'validate'):
--> 610 value = self.validate(obj, value)
611 if obj._cross_validation_lock is False:
612 value = self._cross_validate(obj, value)
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/traitlets/traitlets.py in validate(self, obj, value)
1843 return value
1844 else:
-> 1845 self.error(obj, value)
1846
1847 def info(self):
~/miniconda3/envs/jupyterlab/lib/python3.8/site-packages/traitlets/traitlets.py in error(self, obj, value, error, info)
688 e = "The '%s' trait expected %s, not %s." % (
689 self.name, self.info(), describe("the", value))
--> 690 raise TraitError(e)
691
692 def get_metadata(self, key, default=None):
TraitError: The 'exporter' trait of a ConfluencePreprocessor instance expected a ConfluenceExporter, not the NoneType None.
I get a similar error when running nbconflux from the command line.
Quick note from the Jupyter call today
Interesting package. it would be nice if it worked. we are using confluence across the org and it would be awesome if we could share are results like this directly from the notebook.
Unfortunately, it does not work:
nbconflux path/to/notebook.ipynb https://path/to/page
traceback:
Traceback (most recent call last):
File "/Users/laukea/.pyenv/versions/miniconda3-latest/bin/nbconflux", line 10, in <module>
sys.exit(main())
File "/Users/laukea/.pyenv/versions/miniconda3-latest/lib/python3.7/site-packages/nbconflux/cli.py", line 57, in main
extra_labels=args.extra_labels)
File "/Users/laukea/.pyenv/versions/miniconda3-latest/lib/python3.7/site-packages/nbconflux/api.py", line 56, in notebook_to_page
exporter = ConfluenceExporter(c)
File "/Users/laukea/.pyenv/versions/miniconda3-latest/lib/python3.7/site-packages/nbconflux/exporter.py", line 100, in __init__
self.server, self.page_id = self.get_server_info(self.url)
File "/Users/laukea/.pyenv/versions/miniconda3-latest/lib/python3.7/site-packages/nbconflux/exporter.py", line 149, in get_server_info
page_id = int(segs[5])
ValueError: invalid literal for int() with base 10: 'create'
When re-publishing a page with a number of attachments it can start to fail with a bad request error about child attachments. This error appears to be caused when there are more than 50 attachments for a page. A workaround is to delete the confluence page or publish to a new name. A single page with more than 50 attachments may run into this problem and prevent even the initial publication.
Traceback (most recent call last):
File "/opt/maxpoint/envs/analysis-preview-py3/bin/nbconflux", line 6, in <module>
sys.exit(nbconflux.cli.main())
File "/var/lib/python3.6/site-packages/nbconflux/cli.py", line 55, in main
enable_style=not args.exclude_style, enable_mathjax=args.include_mathjax)
File "/var/lib/python3.6/site-packages/nbconflux/api.py", line 51, in notebook_to_page
result = exporter.from_filename(notebook_file)
File "/var/lib/python3.6/site-packages/nbconflux/exporter.py", line 339, in from_filename
return super(ConfluenceExporter, self).from_filename(filename, *args, **kwargs)
File "/var/lib/python3.6/site-packages/nbconvert/exporters/exporter.py", line 174, in from_filename
return self.from_file(f, resources=resources, **kw)
File "/var/lib/python3.6/site-packages/nbconvert/exporters/exporter.py", line 192, in from_file
return self.from_notebook_node(nbformat.read(file_stream, as_version=4), resources=resources, **kw)
File "/var/lib/python3.6/site-packages/nbconflux/exporter.py", line 314, in from_notebook_node
self.add_or_update_attachment(filename, data, resources)
File "/var/lib/python3.6/site-packages/nbconflux/exporter.py", line 268, in add_or_update_attachment
resp.raise_for_status()
File "/var/lib/python3.6/site-packages/requests/models.py", line 935, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://confluence/rest/api/content/83985329/child/attachment
Ran across this bug today when using fake HTML tags for emphasis nbconflux will fail to publish. example markdown below:
### My Title <insert funny quip here>
Hi! I'm a big fan of this module. I'm using it more and more. However, my (offline mode) plotly charts don't render in confluence. It looks like a raw HTML dump. Do you have any suggestions for remedying that?
I'm exploring some issues with MathJax on our wiki. The issue is that the HTML macro currently used by nbconflux to add in the scripts are not supported on my corporate confluence. A MathJax plugin will be added to the wiki, since users who do not use Jupyter notebooks may know math as well ;)
Then, I guess I'll hack away until nbconflux can either use the MathJax plugin or embed it directly.
This is partly an FYI, and partly a query for direction - there must be ways to discover which plugins are installed, but these will not be accessible everywhere, so --exclude-mathjax perhaps becomes something like --exclude-mathjax --mathjax-plugin=True
It would be great to be able to prevent watchers from receiving too many updates when I'm doing several exports to fine-tune the page. It seems you can do that with the confluence API by setting "minorEdit" : true in the version description:
https://community.atlassian.com/t5/Confluence-questions/Prevent-notifications-when-using-REST-API/qaq-p/948058
This appears to simply be a matter of the confluence template not paying attention to the resource flag.
Related to #21
I'm having trouble using this package because of a traitlets.traitlets.TraitError
which I can't fix. I have already installed the relevant packages, created an Atlassian API key, set CONFLUENCE_USERNAME
& CONFLUENCE_PASSWORD
environment variables, and created a blank Atlassian webpage.
My command is
nbconflux "/Users/bo.osinski/Documents/imaging-research/bo/fragment-analyzer/fragmentation_data_EDA.ipynb" "https://tempuslabs.atlassian.net/wiki/spaces/TEM/pages/2021654744/Predicting+QC2"
And the error is
Using credentials for [email protected] from environment variables
Traceback (most recent call last):
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/traitlets/traitlets.py", line 528, in get
value = obj._trait_values[self.name]
KeyError: 'exporter'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/bin/nbconflux", line 8, in <module>
sys.exit(main())
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconflux/cli.py", line 55, in main
enable_style=not args.exclude_style, enable_mathjax=args.include_mathjax)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconflux/api.py", line 52, in notebook_to_page
result = exporter.from_filename(notebook_file)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconflux/exporter.py", line 330, in from_filename
return super(ConfluenceExporter, self).from_filename(filename, *args, **kwargs)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconvert/exporters/exporter.py", line 181, in from_filename
return self.from_file(f, resources=resources, **kw)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconvert/exporters/exporter.py", line 199, in from_file
return self.from_notebook_node(nbformat.read(file_stream, as_version=4), resources=resources, **kw)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconflux/exporter.py", line 297, in from_notebook_node
html, resources = super(ConfluenceExporter, self).from_notebook_node(nb, resources, **kw)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconvert/exporters/html.py", line 119, in from_notebook_node
return super().from_notebook_node(nb, resources, **kw)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconvert/exporters/templateexporter.py", line 369, in from_notebook_node
nb_copy, resources = super().from_notebook_node(nb, resources, **kw)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconvert/exporters/exporter.py", line 143, in from_notebook_node
nb_copy, resources = self._preprocess(nb_copy, resources)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconvert/exporters/exporter.py", line 318, in _preprocess
nbc, resc = preprocessor(nbc, resc)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconvert/preprocessors/base.py", line 47, in __call__
return self.preprocess(nb, resources)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/nbconflux/preprocessor.py", line 41, in preprocess
.format(server=self.exporter.server, page_id=self.exporter.page_id),
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/traitlets/traitlets.py", line 556, in __get__
return self.get(obj, cls)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/traitlets/traitlets.py", line 535, in get
value = self._validate(obj, dynamic_default())
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/traitlets/traitlets.py", line 591, in _validate
value = self.validate(obj, value)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/traitlets/traitlets.py", line 1677, in validate
self.error(obj, value)
File "/Users/bo.osinski/miniconda3/envs/nbconflux_conda/lib/python3.6/site-packages/traitlets/traitlets.py", line 1524, in error
raise TraitError(e)
traitlets.traitlets.TraitError: The 'exporter' trait of a ConfluencePreprocessor instance must be a ConfluenceExporter, but a value of class 'NoneType' (i.e. None) was specified.
Relevant installed packages:
bleach==3.3.0
html5lib==1.1
jupyter-client==6.1.11
jupyter-core==4.7.1
nbconflux==0.5.0
nbconvert==6.0.7
nbformat==5.1.2
traitlets==4.3.3
Python 3.6.13
Mac OS 10.14.6
I've tried running this in my native python as well as a new python 3.6 conda environment, but always get the same TraitError
. Does anybody have an idea how I can fix this? Thank you!
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.