diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000000000000000000000000000000000000..20b9ad465e182411d7ec760f3d5e99a7f7d7883b --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,31 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + rust: "1.64" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: lightmotif-py/docs/conf.py + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +python: + install: + - requirements: lightmotif-py/docs/requirements.txt + - method: pip + path: . diff --git a/lightmotif-py/README.md b/lightmotif-py/README.md index 01ae47c650262b480bca6a6a0bd1bc911cf9b601..97c020db633b1a244b7029ecbd36c779a2c77819 100644 --- a/lightmotif-py/README.md +++ b/lightmotif-py/README.md @@ -15,7 +15,7 @@ [](https://git.embl.de/larralde/lightmotif/) [](https://github.com/althonos/lightmotif/issues) [](https://github.com/althonos/lightmotif/blob/master/CHANGELOG.md) -[](https://pepy.tech/project/lightmotif) +[](https://pepy.tech/project/lightmotif) ## ðŸ—ºï¸ Overview diff --git a/lightmotif-py/docs/Makefile b/lightmotif-py/docs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d4bb2cbb9eddb1bb1b4f366623044af8e4830919 --- /dev/null +++ b/lightmotif-py/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/lightmotif-py/docs/api/count.rst b/lightmotif-py/docs/api/count.rst new file mode 100644 index 0000000000000000000000000000000000000000..4e943a73d1223e51f8ed75051c7d6bb43ea2dfd1 --- /dev/null +++ b/lightmotif-py/docs/api/count.rst @@ -0,0 +1,9 @@ +CountMatrix +=========== + +.. currentmodule:: lightmotif + + +.. autoclass:: lightmotif.CountMatrix + :special-members: __init__ + :members: diff --git a/lightmotif-py/docs/api/encoded.rst b/lightmotif-py/docs/api/encoded.rst new file mode 100644 index 0000000000000000000000000000000000000000..9b0318b01dcc69283a015a102b5a16890e59b0cb --- /dev/null +++ b/lightmotif-py/docs/api/encoded.rst @@ -0,0 +1,9 @@ +EncodedSequence +=============== + +.. currentmodule:: lightmotif + + +.. autoclass:: lightmotif.EncodedSequence + :special-members: __init__ + :members: diff --git a/lightmotif-py/docs/api/index.rst b/lightmotif-py/docs/api/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..719c4398fe722caea3e858e1a871645d056f84cd --- /dev/null +++ b/lightmotif-py/docs/api/index.rst @@ -0,0 +1,49 @@ +API Reference +============== + +.. currentmodule:: lightmotif + +.. automodule:: lightmotif + + +.. toctree:: + :hidden: + + encoded <encoded> + striped <striped> + count <count> + weight <weight> + scoring <scoring> + + +Sequence +-------- + +.. autosummary:: + :nosignatures: + + lightmotif.EncodedSequence + lightmotif.StripedSequence + + +Matrices +-------- + +.. autosummary:: + :nosignatures: + + lightmotif.CountMatrix + lightmotif.WeightMatrix + lightmotif.ScoringMatrix + +Functions +--------- + +.. autofunction:: lightmotif.create + +.. autofunction:: lightmotif.stripe + + + + + diff --git a/lightmotif-py/docs/api/scoring.rst b/lightmotif-py/docs/api/scoring.rst new file mode 100644 index 0000000000000000000000000000000000000000..f9e900584f4029b715a1352b2830e60cc5eda60e --- /dev/null +++ b/lightmotif-py/docs/api/scoring.rst @@ -0,0 +1,9 @@ +ScoringMatrix +============= + +.. currentmodule:: lightmotif + + +.. autoclass:: lightmotif.ScoringMatrix + :special-members: __init__ + :members: diff --git a/lightmotif-py/docs/api/striped.rst b/lightmotif-py/docs/api/striped.rst new file mode 100644 index 0000000000000000000000000000000000000000..9388ff497ca26aaf2e979861b0bd6a385e6daa61 --- /dev/null +++ b/lightmotif-py/docs/api/striped.rst @@ -0,0 +1,9 @@ +StripedSequence +=============== + +.. currentmodule:: lightmotif + + +.. autoclass:: lightmotif.StripedSequence + :special-members: __init__ + :members: diff --git a/lightmotif-py/docs/api/weight.rst b/lightmotif-py/docs/api/weight.rst new file mode 100644 index 0000000000000000000000000000000000000000..a951ccf338d487bce287bef709d6ad0ac87eefa7 --- /dev/null +++ b/lightmotif-py/docs/api/weight.rst @@ -0,0 +1,9 @@ +WeightMatrix +============ + +.. currentmodule:: lightmotif + + +.. autoclass:: lightmotif.WeightMatrix + :special-members: __init__ + :members: diff --git a/lightmotif-py/docs/changes.md b/lightmotif-py/docs/changes.md new file mode 120000 index 0000000000000000000000000000000000000000..699cc9e7b7c5bf63c3549abe36e3eecf8efab625 --- /dev/null +++ b/lightmotif-py/docs/changes.md @@ -0,0 +1 @@ +../../CHANGELOG.md \ No newline at end of file diff --git a/lightmotif-py/docs/conf.py b/lightmotif-py/docs/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..2dae4253023873fb898b9dd3bc4b0cbbdfe8750f --- /dev/null +++ b/lightmotif-py/docs/conf.py @@ -0,0 +1,215 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Imports ----------------------------------------------------------------- + +import configparser +import datetime +import os +import sys +import re +import shutil +import semantic_version +import sphinx_bootstrap_theme + +# -- Path setup -------------------------------------------------------------- + +docssrc_dir = os.path.dirname(os.path.abspath(__file__)) +project_dir = os.path.dirname(os.path.dirname(docssrc_dir)) + + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +import lightmotif + +project = lightmotif.__name__ +author = re.match('(.*) <.*>', lightmotif.__author__).group(1) +year = datetime.date.today().year +copyright = '{}, {}'.format("2023" if year==2023 else "2023-{}".format(year), author) + +# extract the semantic version +semver = semantic_version.Version.coerce(lightmotif.__version__) +version = str(semver.truncate(level="patch")) +release = str(semver) + +# extract the project URLs from ``setup.cfg`` +cfgparser = configparser.ConfigParser() +cfgparser.read(os.path.join(project_dir, "setup.cfg")) +project_urls = dict( + map(str.strip, line.split(" = ", 1)) + for line in cfgparser.get("metadata", "project_urls").splitlines() + if line.strip() +) + +# patch the docstring of so that we don't show the link to redirect +# to the docs (we don't want to see it when reading the docs already, duh!) +doc_lines = lightmotif.__doc__.splitlines() +if "See Also:" in doc_lines: + see_also = doc_lines.index("See Also:") + lightmotif.__doc__ = "\n".join(doc_lines[:see_also]) + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", + "sphinx.ext.napoleon", + "sphinx.ext.coverage", + "sphinx.ext.mathjax", + "sphinx.ext.todo", + "sphinx.ext.extlinks", + "sphinx_bootstrap_theme", + "nbsphinx", + "recommonmark", + "IPython.sphinxext.ipython_console_highlighting", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [ + '_build', + 'Thumbs.db', + '.DS_Store', + '**.ipynb_checkpoints', + 'requirements.txt' +] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "default" + +# The name of the default role for inline references +default_role = "py:obj" + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'bootstrap' + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +html_theme_options = { + # Bootswatch (http://bootswatch.com/) theme. + "bootswatch_theme": "flatly", + # Choose Bootstrap version. + "bootstrap_version": "3", + # Tab name for entire site. (Default: "Site") + "navbar_site_name": "Documentation", + # HTML navbar class (Default: "navbar") to attach to <div> element. + # For black navbar, do "navbar navbar-inverse" + "navbar_class": "navbar", + # Render the next and previous page links in navbar. (Default: true) + "navbar_sidebarrel": True, + # Render the current pages TOC in the navbar. (Default: true) + "navbar_pagenav": False, + # A list of tuples containing pages or urls to link to. + "navbar_links": [ + ("GitHub", cfgparser.get("metadata", "home_page").strip(), True) + ] + [ + (k, v, True) + for k, v in project_urls.items() + if k in {"Zenodo", "PyPI"} + ], + "admonition_use_panel": True, +} + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +html_sidebars = { + "*": ["localtoc.html"], + "api/*": ["localtoc.html"], + "examples/*": ["localtoc.html"], +} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = lightmotif.__name__ + + +# -- Extension configuration ------------------------------------------------- + +# -- Options for extlinks extension ------------------------------------------ + +extlinks = { + 'doi': ('https://doi.org/%s', 'doi:%s'), + 'pmid': ('https://pubmed.ncbi.nlm.nih.gov/%s', 'PMID:%s'), + 'isbn': ('https://www.worldcat.org/isbn/%s', 'ISBN:%s'), +} + +# -- Options for imgmath extension ------------------------------------------- + +imgmath_image_format = "svg" + +# -- Options for napoleon extension ------------------------------------------ + +napoleon_include_init_with_doc = True +napoleon_include_special_with_doc = True +napoleon_include_private_with_doc = True +napoleon_use_admonition_for_examples = True +napoleon_use_admonition_for_notes = True +napoleon_use_admonition_for_references = True +napoleon_use_rtype = False + +# -- Options for autodoc extension ------------------------------------------- + +autoclass_content = "class" +autodoc_member_order = 'groupwise' +autosummary_generate = [] + +# -- Options for intersphinx extension --------------------------------------- + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + "python": ("https://docs.python.org/3/", None), + "psutil": ("https://psutil.readthedocs.io/en/latest/", None), + "biopython": ("https://biopython.org/docs/latest/api/", None), + "numpy": ("https://numpy.org/doc/stable/", None) +} + +# -- Options for recommonmark extension -------------------------------------- + +source_suffix = { + '.rst': 'restructuredtext', + '.txt': 'markdown', + '.md': 'markdown', +} + +# -- Options for nbsphinx extension ------------------------------------------ + +nbsphinx_execute = 'auto' +nbsphinx_execute_arguments = [ + "--InlineBackend.figure_formats={'svg', 'pdf'}", + "--InlineBackend.rc={'figure.dpi': 96}", +] + diff --git a/lightmotif-py/docs/index.rst b/lightmotif-py/docs/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..1a79ae23ccfcce225f3fdb9a0397fa6b2915468f --- /dev/null +++ b/lightmotif-py/docs/index.rst @@ -0,0 +1,117 @@ +.. lightmotif documentation master file, created by + sphinx-quickstart on Tue Jul 18 16:36:58 2023. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +LightMotif |Stars| +================== + +.. |Stars| image:: https://img.shields.io/github/stars/althonos/lightmotif.svg?style=social&maxAge=3600&label=Star + :target: https://github.com/althonos/lightmotif/stargazers + +*A lightweight* `platform-accelerated <https://en.wikipedia.org/wiki/Single_instruction,_multiple_data>`_ *library for* `biological motif <https://en.wikipedia.org/wiki/Sequence_motif>`_ *scanning using* `position weight matrices <https://en.wikipedia.org/wiki/Position_weight_matrix>`_. + +|Actions| |Coverage| |License| |Crate| |PyPI| |Wheel| |Bioconda| |Python Versions| |Python Impls| |Source| |Mirror| |Issues| |Changelog| |Downloads| + +.. |Actions| image:: https://img.shields.io/github/actions/workflow/status/althonos/lightmotif/python.yml?branch=main&logo=github&style=flat-square&maxAge=300 + :target: https://github.com/althonos/lightmotif/actions + +.. |Coverage| image:: https://img.shields.io/codecov/c/gh/althonos/lightmotif?logo=codecov&style=flat-square&maxAge=3600 + :target: https://codecov.io/gh/althonos/lightmotif/ + +.. |License| image:: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square&maxAge=2678400 + :target: https://choosealicense.com/licenses/mit/ + +.. |Crate| image:: https://img.shields.io/crates/v/lightmotif-py.svg?maxAge=600&style=flat-square + :target: https://crates.io/crates/lightmotif-py + +.. |PyPI| image:: https://img.shields.io/pypi/v/lightmotif.svg?style=flat-square&maxAge=600 + :target: https://pypi.org/project/lightmotif + +.. |Wheel| image:: https://img.shields.io/pypi/wheel/lightmotif.svg?style=flat-square&maxAge=2678400 + :target: https://pypi.org/project/lightmotif/#files + +.. |Bioconda| image:: https://img.shields.io/conda/vn/bioconda/lightmotif?style=flat-square&maxAge=3600 + :target: https://anaconda.org/bioconda/lightmotif + +.. |Python Versions| image:: https://img.shields.io/pypi/pyversions/lightmotif.svg?style=flat-square&maxAge=600 + :target: https://pypi.org/project/lightmotif/#files + +.. |Python Impls| image:: https://img.shields.io/pypi/implementation/lightmotif.svg?style=flat-square&maxAge=600 + :target: https://pypi.org/project/lightmotif/#files + +.. |Source| image:: https://img.shields.io/badge/source-GitHub-303030.svg?maxAge=2678400&style=flat-square + :target: https://github.com/althonos/lightmotif/tree/main/lightmotif-py + +.. |Mirror| image:: https://img.shields.io/badge/mirror-EMBL-009f4d?style=flat-square&maxAge=2678400 + :target: https://git.embl.de/larralde/lightmotif/ + +.. |Issues| image:: https://img.shields.io/github/issues/althonos/lightmotif.svg?style=flat-square&maxAge=600 + :target: https://github.com/althonos/lightmotif/issues + +.. |Changelog| image:: https://img.shields.io/badge/keep%20a-changelog-8A0707.svg?maxAge=2678400&style=flat-square + :target: https://github.com/althonos/lightmotif/blob/master/CHANGELOG.md + +.. |Downloads| image:: https://img.shields.io/pypi/dm/lightmotif?style=flat-square&color=303f9f&maxAge=86400&label=downloads + :target: https://pepy.tech/project/lightmotif + + +Overview +-------- + +`Motif <https://en.wikipedia.org/wiki/Sequence_motif>`_ scanning with +`position weight matrices <https://en.wikipedia.org/wiki/Position_weight_matrix>`_ +(also known as position-specific scoring matrices) is a robust method for +identifying motifs of fixed length inside a +`biological sequence <https://en.wikipedia.org/wiki/Sequence_(biology)>`_. They can be +used to identify `transcription factor <https://en.wikipedia.org/wiki/Transcription_factor>`_ +`binding sites in DNA <https://en.wikipedia.org/wiki/DNA_binding_site>`_, +or `protease <https://en.wikipedia.org/wiki/Protease>`_ `cleavage <https://en.wikipedia.org/wiki/Proteolysis>`_ site in `polypeptides <https://en.wikipedia.org/wiki/Protein>`_. +Position weight matrices are often viewed as `sequence logos <https://en.wikipedia.org/wiki/Sequence_logo>`_: + +.. image:: https://raw.githubusercontent.com/althonos/lightmotif/main/docs/_static/prodoric_logo_mx000274.svg + :target: https://www.prodoric.de/matrix/MX000274.html + +The ``lightmotif`` library provides a Python module to run very efficient +searches for a motif encoded in a position weight matrix. The position +scanning combines several techniques to allow high-throughput processing +of sequences: + +- Compile-time definition of alphabets and matrix dimensions. +- Sequence symbol encoding for fast table look-ups, as implemented in HMMER or MEME +- Striped sequence matrices to process several positions in parallel, inspired by Michael Farrar. +- Vectorized matrix row look-up using ``permute`` instructions of `AVX2 <https://fr.wikipedia.org/wiki/Advanced_Vector_Extensions>`_. + +*This is the Python version, there is a* `Rust crate <https://docs.rs/lightmotif>`_ *available as well.* + + +Setup +----- + +Run ``pip install lightmotif`` in a shell to download the latest release and all +its dependencies from PyPi, or have a look at the +:doc:`Installation page <install>` to find other ways to install the +``lightmotif`` Python package. + + +Library +------- + +.. toctree:: + :maxdepth: 2 + + Installation <install> + API Reference <api/index> + Changelog <changes> + + +License +------- + +This library is provided under the open-source +`MIT license <https://choosealicense.com/licenses/mit/>`_. + +*This project was developed by* `Martin Larralde <https://github.com/althonos/>`_ +*during his PhD project at the* `European Molecular Biology Laboratory <https://www.embl.de/>`_ +*in the* `Zeller team <https://github.com/zellerlab>`_. + diff --git a/lightmotif-py/docs/install.rst b/lightmotif-py/docs/install.rst new file mode 100644 index 0000000000000000000000000000000000000000..73f1b085663c8dc8c01a3871cc869cd1332d15f3 --- /dev/null +++ b/lightmotif-py/docs/install.rst @@ -0,0 +1,73 @@ +Installation +============ + +.. note:: + + Wheels are provided for Windows, Linux and OSX x86-64 platforms, as well as + Linux and OSX Aarch64 platforms. Other machines will have to build the wheel + from the source distribution. Building ``lightmotif`` involves compiling + Rust code, which requires a Rust compiler to be available. + + +PyPi +^^^^ + +``lightmotif`` is hosted on GitHub, but the easiest way to install it is to download +the latest release from its `PyPi repository <https://pypi.python.org/pypi/lightmotif>`_. +It will install all dependencies then install ``lightmotif`` either from a wheel if +one is available, or from source after compiling the Rust code : + +.. code:: console + + $ pip install --user lightmotif + + +.. Arch User Repository +.. ^^^^^^^^^^^^^^^^^^^^ + +.. A package recipe for Arch Linux can be found in the Arch User Repository +.. under the name `python-lightmotif <https://aur.archlinux.org/packages/python-lightmotif>`_. +.. It will always match the latest release from PyPI. + +.. Steps to install on ArchLinux depend on your `AUR helper <https://wiki.archlinux.org/title/AUR_helpers>`_ +.. (``yaourt``, ``aura``, ``yay``, etc.). For ``aura``, you'll need to run: + +.. .. code:: console + +.. $ aura -A python-lightmotif + + +GitHub + ``pip`` +^^^^^^^^^^^^^^^^ + +If, for any reason, you prefer to download the library from GitHub, you can clone +the repository and install the repository by running (with the admin rights): + +.. code:: console + + $ pip install -U git+https://github.com/althonos/lightmotif + +.. caution:: + + Keep in mind this will install always try to install the latest commit, + which may not even build, so consider using a versioned release instead. + + +GitHub + ``setuptools`` +^^^^^^^^^^^^^^^^^^^^^^^ + +If you do not want to use ``pip``, you can still clone the repository and +run the ``setup.py`` file manually, although you will need to install the +build dependencies (mainly ``setuptools-rust``): + +.. code:: console + + $ git clone --recursive https://github.com/althonos/lightmotif + $ cd lightmotif + $ python setup.py build + # python setup.py install + +.. Danger:: + + Installing packages without ``pip`` is strongly discouraged, as they can + only be uninstalled manually, and may damage your system. diff --git a/lightmotif-py/docs/make.bat b/lightmotif-py/docs/make.bat new file mode 100644 index 0000000000000000000000000000000000000000..32bb24529f92346af26219baed295b7488b77534 --- /dev/null +++ b/lightmotif-py/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/lightmotif-py/docs/requirements.txt b/lightmotif-py/docs/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3a9f5bcde1aa66fb270e800c3eb2306afae63d8 --- /dev/null +++ b/lightmotif-py/docs/requirements.txt @@ -0,0 +1,13 @@ +# build dependencies +setuptools >=46.4 + +# sphinx documentation dependencies +semantic_version ~=2.8 +recommonmark ~=0.7 +pygments-style-monokailight ~=0.4 +ipython ~=7.19 +pygments ~=2.4 +nbsphinx ~=0.8 + +# sphinx-bootstrap-theme ~=0.7 with patched admonition +https://github.com/althonos/sphinx-bootstrap-theme/archive/master.zip \ No newline at end of file