pax_global_header00006660000000000000000000000064146137322040014514gustar00rootroot0000000000000052 comment=d6dc8a57adb1c2ac17090c6382f011eb682d1261 nbconvert-7.16.4/000077500000000000000000000000001461373220400136135ustar00rootroot00000000000000nbconvert-7.16.4/.git-blame-ignore-revs000066400000000000000000000001071461373220400177110ustar00rootroot00000000000000# Initial pre-commit reformat 68b496b7fcf4cfbffe9e1656ac52400a24cacc45 nbconvert-7.16.4/.github/000077500000000000000000000000001461373220400151535ustar00rootroot00000000000000nbconvert-7.16.4/.github/ISSUE_TEMPLATE/000077500000000000000000000000001461373220400173365ustar00rootroot00000000000000nbconvert-7.16.4/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000007701461373220400220340ustar00rootroot00000000000000______________________________________________________________________ ## name: Bug report about: Create a report to help us improve **Nbconvert version:** nbconvert-7.16.4/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000005561461373220400230710ustar00rootroot00000000000000______________________________________________________________________ ## name: Feature Request about: Suggest an idea for this project nbconvert-7.16.4/.github/ISSUE_TEMPLATE/question.md000066400000000000000000000004061461373220400215270ustar00rootroot00000000000000______________________________________________________________________ ## name: Question about: If you need some help labels: question If you have a question, you can file an issue here or preferably ask on [Jupyter Discourse](https://discourse.jupyter.org/). nbconvert-7.16.4/.github/dependabot.yml000066400000000000000000000004301461373220400200000ustar00rootroot00000000000000version: 2 updates: # Set update schedule for GitHub Actions - package-ecosystem: "github-actions" directory: "/" schedule: # Check for updates to GitHub Actions every weekday interval: "weekly" groups: actions: patterns: - "*" nbconvert-7.16.4/.github/workflows/000077500000000000000000000000001461373220400172105ustar00rootroot00000000000000nbconvert-7.16.4/.github/workflows/docs.yml000066400000000000000000000030111461373220400206560ustar00rootroot00000000000000name: Docs on: push: branches: [main] pull_request: concurrency: group: docs-${{ github.ref }} cancel-in-progress: true jobs: generate-docs: runs-on: ubuntu-latest strategy: matrix: python-version: ["3.8", "3.11"] steps: - name: Check out repository code uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install texlive-plain-generic inkscape texlive-xetex latexmk enchant-2 # pandoc is not up to date in the ubuntu repos, so we install directly wget https://github.com/jgm/pandoc/releases/download/3.1.2/pandoc-3.1.2-1-amd64.deb && sudo dpkg -i pandoc-3.1.2-1-amd64.deb - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Install run: pip install -v ".[all]" - name: List installed packages run: | pip freeze pip check - name: Build HTML docs run: | cd docs make html SPHINXOPTS="-W" - name: Upload HTML uses: actions/upload-artifact@v4 with: name: html-${{ github.job }}-${{ strategy.job-index }} path: build/sphinx/html - name: Build PDF docs run: | cd docs make latexpdf - name: Upload PDF uses: actions/upload-artifact@v4 with: name: pdf-python-${{matrix.python-version}}-${{ github.job }}-${{ strategy.job-index }} path: docs/build/latex/nbconvert.pdf nbconvert-7.16.4/.github/workflows/enforce-label.yml000066400000000000000000000005001461373220400224240ustar00rootroot00000000000000name: Enforce PR label on: pull_request: types: [labeled, unlabeled, opened, edited, synchronize] jobs: enforce-label: runs-on: ubuntu-latest permissions: pull-requests: write steps: - name: enforce-triage-label uses: jupyterlab/maintainer-tools/.github/actions/enforce-label@v1 nbconvert-7.16.4/.github/workflows/prep-release.yml000066400000000000000000000027201461373220400223200ustar00rootroot00000000000000name: "Step 1: Prep Release" on: workflow_dispatch: inputs: version_spec: description: "New Version Specifier" default: "next" required: false branch: description: "The branch to target" required: false post_version_spec: description: "Post Version Specifier" required: false since: description: "Use PRs with activity since this date or git reference" required: false since_last_stable: description: "Use PRs with activity since the last stable git tag" required: false type: boolean jobs: prep_release: runs-on: ubuntu-latest permissions: contents: write steps: - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Prep Release id: prep-release uses: jupyter-server/jupyter_releaser/.github/actions/prep-release@v2 with: token: ${{ secrets.GITHUB_TOKEN }} version_spec: ${{ github.event.inputs.version_spec }} post_version_spec: ${{ github.event.inputs.post_version_spec }} target: ${{ github.event.inputs.target }} branch: ${{ github.event.inputs.branch }} since: ${{ github.event.inputs.since }} since_last_stable: ${{ github.event.inputs.since_last_stable }} - name: "** Next Step **" run: | echo "Optional): Review Draft Release: ${{ steps.prep-release.outputs.release_url }}" nbconvert-7.16.4/.github/workflows/publish-release.yml000066400000000000000000000036511461373220400230240ustar00rootroot00000000000000name: "Step 2: Publish Release" on: workflow_dispatch: inputs: branch: description: "The target branch" required: false release_url: description: "The URL of the draft GitHub release" required: false steps_to_skip: description: "Comma separated list of steps to skip" required: false jobs: publish_release: runs-on: ubuntu-latest environment: release permissions: id-token: write steps: - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - uses: actions/create-github-app-token@v1 id: app-token with: app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} - name: Populate Release id: populate-release uses: jupyter-server/jupyter_releaser/.github/actions/populate-release@v2 with: token: ${{ steps.app-token.outputs.token }} target: ${{ github.event.inputs.target }} branch: ${{ github.event.inputs.branch }} release_url: ${{ github.event.inputs.release_url }} steps_to_skip: ${{ github.event.inputs.steps_to_skip }} - name: Finalize Release id: finalize-release env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} uses: jupyter-server/jupyter-releaser/.github/actions/finalize-release@v2 with: token: ${{ steps.app-token.outputs.token }} target: ${{ github.event.inputs.target }} release_url: ${{ steps.populate-release.outputs.release_url }} - name: "** Next Step **" if: ${{ success() }} run: | echo "Verify the final release" echo ${{ steps.finalize-release.outputs.release_url }} - name: "** Failure Message **" if: ${{ failure() }} run: | echo "Failed to Publish the Draft Release Url:" echo ${{ steps.populate-release.outputs.release_url }} nbconvert-7.16.4/.github/workflows/tests.yml000066400000000000000000000124531461373220400211020ustar00rootroot00000000000000name: Tests on: push: branches: [main] pull_request: schedule: - cron: "0 8 * * *" concurrency: group: tests-${{ github.ref }} cancel-in-progress: true defaults: run: shell: bash -eux {0} jobs: run-tests: runs-on: ${{ matrix.os }} env: NBFORMAT_VALIDATOR: jsonschema strategy: matrix: os: ["ubuntu-20.04", "macos-latest", "windows-latest"] python-version: ["3.8", "3.12"] include: - os: "windows-latest" python-version: "3.9" - os: "macos-latest" python-version: "3.10" - os: "ubuntu-20.04" python-version: "3.11" fail-fast: false steps: - uses: actions/checkout@v4 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Install Linux dependencies if: startsWith(runner.os, 'Linux') run: | sudo apt-get update sudo apt-get install texlive-plain-generic inkscape texlive-xetex latexmk sudo apt-get install xvfb x11-utils libxkbcommon-x11-0 libxcb-xinerama0 python3-pyqt5 # pandoc is not up to date in the ubuntu repos, so we install directly wget https://github.com/jgm/pandoc/releases/download/3.1.2/pandoc-3.1.2-1-amd64.deb && sudo dpkg -i pandoc-3.1.2-1-amd64.deb - name: Run tests on Linux if: ${{ startsWith(runner.os, 'linux') }} run: | xvfb-run --auto-servernum hatch run cov:test - name: Run tests on other platforms if: ${{ !startsWith(runner.os, 'linux') }} run: | hatch run cov:nowarn - uses: jupyterlab/maintainer-tools/.github/actions/upload-coverage@v1 coverage: runs-on: ubuntu-latest needs: - run-tests steps: - uses: actions/checkout@v4 - uses: jupyterlab/maintainer-tools/.github/actions/report-coverage@v1 test_lint: name: Test Lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Run Linters run: | hatch run typing:test hatch run lint:build pipx run interrogate -v . pipx run doc8 --max-line-length=200 --ignore-path=docs/source/other/full-config.rst check_release: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - run: pip install -e . - uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2 with: version_spec: 10.10.10 token: ${{ secrets.GITHUB_TOKEN }} check_links: runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v4 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1 with: ignore_links: "https://ipywidgets.readthedocs.io/en/latest/examples/Output" test_minimum_versions: name: Test Minimum Versions timeout-minutes: 20 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 with: dependency_type: minimum - name: Install dependencies run: | sudo apt-get update sudo apt-get install texlive-plain-generic inkscape texlive-xetex latexmk sudo apt-get install xvfb x11-utils libxkbcommon-x11-0 libxcb-xinerama0 python3-pyqt5 # pandoc is not up to date in the ubuntu repos, so we install directly wget https://github.com/jgm/pandoc/releases/download/2.9.2.1/pandoc-2.9.2.1-1-amd64.deb && sudo dpkg -i pandoc-2.9.2.1-1-amd64.deb - name: Run tests run: | xvfb-run --auto-servernum hatch run test:nowarn || xvfb-run --auto-servernum hatch run test:nowarn --lf test_prereleases: name: Test Prereleases runs-on: ubuntu-latest timeout-minutes: 20 steps: - uses: actions/checkout@v4 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 with: dependency_type: pre - name: Run the tests run: | export NBFORMAT_VALIDATOR=jsonschema hatch run test:nowarn || hatch run test:nowarn --lf make_sdist: name: Make SDist runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v4 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - uses: jupyterlab/maintainer-tools/.github/actions/make-sdist@v1 test_sdist: runs-on: ubuntu-latest needs: [make_sdist] name: Install from SDist and Test timeout-minutes: 20 steps: - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - uses: jupyterlab/maintainer-tools/.github/actions/test-sdist@v1 tests_check: # This job does nothing and is only used for the branch protection if: always() needs: - coverage - test_lint - test_minimum_versions - test_prereleases - check_links - check_release - test_sdist runs-on: ubuntu-latest steps: - name: Decide whether the needed jobs succeeded or failed uses: re-actors/alls-green@release/v1 with: jobs: ${{ toJSON(needs) }} nbconvert-7.16.4/.gitignore000066400000000000000000000013741461373220400156100ustar00rootroot00000000000000MANIFEST build dist _build docs/man/*.gz docs/source/api/generated docs/source/config/options docs/source/interactive/magics-generated.txt docs/gh-pages docs/source/CHANGELOG.md nbconvert/resources/style.min.css tests/files/*.html *.py[co] __pycache__ *.egg-info *~ *.bak .ipynb_checkpoints .tox .DS_Store \#*# .#* .coverage* htmlcov .cache docs/source/*.tpl docs/source/*.j2 docs/source/example.html docs/source/mytemplate/* docs/source/config_options.rst .venv # Eclipse pollutes the filesystem .project .pydevproject .settings # VSCode *.code-workspace .history .vscode # Downloaded theme files share/templates/lab/static/index.css share/templates/lab/static/theme-dark.css share/templates/lab/static/theme-light.css share/templates/classic/static/style.css nbconvert-7.16.4/.mailmap000066400000000000000000000250661461373220400152450ustar00rootroot00000000000000A. J. Holyoake ajholyoake Aaron Culich Aaron Culich Aron Ahmadia ahmadia Benjamin Ragan-Kelley Benjamin Ragan-Kelley Min RK Benjamin Ragan-Kelley MinRK Barry Wark Barry Wark Ben Edwards Ben Edwards Bradley M. Froehle Bradley M. Froehle Bradley M. Froehle Bradley Froehle Brandon Parsons Brandon Parsons Brian E. Granger Brian Granger Brian E. Granger Brian Granger <> Brian E. Granger bgranger <> Brian E. Granger bgranger Christoph Gohlke cgohlke Cyrille Rossant rossant Damián Avila damianavila Damián Avila damianavila Damon Allen damontallen Darren Dale darren.dale <> Darren Dale Darren Dale <> Dav Clark Dav Clark <> Dav Clark Dav Clark David Hirschfeld dhirschfeld David P. Sanders David P. Sanders David Warde-Farley David Warde-Farley <> Doug Blank Doug Blank Eugene Van den Bulke Eugene Van den Bulke Evan Patterson Evan Patterson Evan Patterson Evan Patterson Evan Patterson epatters Evan Patterson epatters Ernie French Ernie French Ernie French ernie french Ernie French ernop Fernando Perez Fernando Perez Fernando Perez Fernando Perez fperez <> Fernando Perez fptest <> Fernando Perez fptest1 <> Fernando Perez Fernando Perez Fernando Perez Fernando Perez <> Fernando Perez Fernando Perez Frank Murphy Frank Murphy Gabriel Becker gmbecker Gael Varoquaux gael.varoquaux <> Gael Varoquaux gvaroquaux Gael Varoquaux Gael Varoquaux <> Ingolf Becker watercrossing Jake Vanderplas Jake Vanderplas Jakob Gager jakobgager Jakob Gager jakobgager Jakob Gager jakobgager Jason Grout Jason Grout Jason Gors jason gors Jason Gors jgors Jens Hedegaard Nielsen Jens Hedegaard Nielsen Jens Hedegaard Nielsen Jens H Nielsen Jens Hedegaard Nielsen Jens H. Nielsen Jez Ng Jez Ng Jonathan Frederic Jonathan Frederic Jonathan Frederic Jonathan Frederic Jonathan Frederic Jonathan Frederic Jonathan Frederic jon Jonathan Frederic U-Jon-PC\Jon Jonathan March Jonathan March Jonathan March jdmarch Jörgen Stenarson Jörgen Stenarson Jörgen Stenarson Jorgen Stenarson Jörgen Stenarson Jorgen Stenarson <> Jörgen Stenarson jstenar Jörgen Stenarson jstenar <> Jörgen Stenarson Jörgen Stenarson Juergen Hasch juhasch Juergen Hasch juhasch Julia Evans Julia Evans Kester Tong KesterTong Kyle Kelley Kyle Kelley Kyle Kelley rgbkrk Laurent Dufréchou Laurent Dufréchou Laurent Dufréchou laurent dufrechou <> Laurent Dufréchou laurent.dufrechou <> Laurent Dufréchou Laurent Dufrechou <> Laurent Dufréchou laurent.dufrechou@gmail.com <> Laurent Dufréchou ldufrechou Lorena Pantano Lorena Luis Pedro Coelho Luis Pedro Coelho Marc Molla marcmolla Martín Gaitán Martín Gaitán Matthias Bussonnier Matthias BUSSONNIER Matthias Bussonnier Bussonnier Matthias Matthias Bussonnier Matthias BUSSONNIER Matthias Bussonnier Matthias Bussonnier Michael Droettboom Michael Droettboom Nicholas Bollweg Nicholas Bollweg (Nick) Nicolas Rougier Nikolay Koldunov Nikolay Koldunov Omar Andrés Zapata Mesa Omar Andres Zapata Mesa Omar Andrés Zapata Mesa Omar Andres Zapata Mesa Pankaj Pandey Pankaj Pandey Pascal Schetelat pascal-schetelat Paul Ivanov Paul Ivanov Pauli Virtanen Pauli Virtanen <> Pauli Virtanen Pauli Virtanen Pierre Gerold Pierre Gerold Pietro Berkes Pietro Berkes Piti Ongmongkolkul piti118 Prabhu Ramachandran Prabhu Ramachandran <> Puneeth Chaganti Puneeth Chaganti Robert Kern rkern <> Robert Kern Robert Kern Robert Kern Robert Kern Robert Kern Robert Kern <> Robert Marchman Robert Marchman Satrajit Ghosh Satrajit Ghosh Satrajit Ghosh Satrajit Ghosh Scott Sanderson Scott Sanderson smithj1 smithj1 smithj1 smithj1 Steven Johnson stevenJohnson Steven Silvester blink1073 S. Weber s8weber Stefan van der Walt Stefan van der Walt Silvia Vinyes Silvia Silvia Vinyes silviav12 Sylvain Corlay Sylvain Corlay sylvain.corlay Ted Drain TD22057 Théophile Studer Théophile Studer Thomas Kluyver Thomas Thomas Spura Thomas Spura Timo Paulssen timo vds vds2212 vds vds Ville M. Vainio Ville M. Vainio ville Ville M. Vainio ville Ville M. Vainio vivainio <> Ville M. Vainio Ville M. Vainio Ville M. Vainio Ville M. Vainio Walter Doerwald walter.doerwald <> Walter Doerwald Walter Doerwald <> W. Trevor King W. Trevor King Yoval P. y-p nbconvert-7.16.4/.pre-commit-config.yaml000066400000000000000000000047471461373220400201100ustar00rootroot00000000000000ci: autoupdate_schedule: monthly autoupdate_commit_msg: "chore: update pre-commit hooks" repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: check-case-conflict - id: check-ast - id: check-docstring-first - id: check-executables-have-shebangs - id: check-added-large-files - id: check-case-conflict - id: check-merge-conflict - id: check-json - id: check-toml - id: check-yaml - id: debug-statements - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema rev: 0.28.1 hooks: - id: check-github-workflows - repo: https://github.com/executablebooks/mdformat rev: 0.7.17 hooks: - id: mdformat additional_dependencies: [mdformat-gfm, mdformat-frontmatter, mdformat-footnote] - repo: https://github.com/pre-commit/mirrors-prettier rev: "v4.0.0-alpha.8" hooks: - id: prettier types_or: [yaml, html, json] - repo: https://github.com/adamchainz/blacken-docs rev: "1.16.0" hooks: - id: blacken-docs additional_dependencies: [black==23.7.0] - repo: https://github.com/codespell-project/codespell rev: "v2.2.6" hooks: - id: codespell args: ["-L", "sur,nd"] - repo: https://github.com/pre-commit/mirrors-mypy rev: "v1.9.0" hooks: - id: mypy files: "^nbconvert" stages: [manual] args: ["--install-types", "--non-interactive"] additional_dependencies: [ "traitlets>=5.13", "jupyter_core>=5.3", "jinja2", "nbformat", "markupsafe", "mistune", "nbclient>=0.9", "defusedxml", "ipython", "packaging", "pandocfilters", "jupyterlab_pygments", ] - repo: https://github.com/pre-commit/pygrep-hooks rev: "v1.10.0" hooks: - id: rst-backticks - id: rst-directive-colons - id: rst-inline-touching-normal - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.3.5 hooks: - id: ruff types_or: [python, jupyter] args: ["--fix", "--show-fixes"] - id: ruff-format types_or: [python, jupyter] - repo: https://github.com/scientific-python/cookie rev: "2024.03.10" hooks: - id: sp-repo-review additional_dependencies: ["repo-review[cli]"] nbconvert-7.16.4/.prettierignore000066400000000000000000000000231461373220400166510ustar00rootroot00000000000000tests/files/*.html nbconvert-7.16.4/.readthedocs.yaml000066400000000000000000000005511461373220400170430ustar00rootroot00000000000000# .readthedocs.yml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 sphinx: configuration: docs/source/conf.py formats: all python: install: - method: pip path: . extra_requirements: - docs build: os: ubuntu-22.04 tools: python: "3.11" nbconvert-7.16.4/CHANGELOG.md000066400000000000000000003006521461373220400154320ustar00rootroot00000000000000# Changes in nbconvert ## 7.16.4 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.16.3...71fde294f623083f364bf68e14f07459dee952e6)) ### Bugs fixed - rst exporter: Re-enable coalescing streams [#2142](https://github.com/jupyter/nbconvert/pull/2142) ([@mgeier](https://github.com/mgeier)) ### Maintenance and upkeep improvements - Revert "Set all min deps" [#2138](https://github.com/jupyter/nbconvert/pull/2138) ([@blink1073](https://github.com/blink1073)) - Set all min deps [#2136](https://github.com/jupyter/nbconvert/pull/2136) ([@blink1073](https://github.com/blink1073)) - chore: update pre-commit hooks [#2134](https://github.com/jupyter/nbconvert/pull/2134) ([@pre-commit-ci](https://github.com/pre-commit-ci)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2024-03-21&to=2024-04-29&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2024-03-21..2024-04-29&type=Issues) | [@mgeier](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Amgeier+updated%3A2024-03-21..2024-04-29&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2024-03-21..2024-04-29&type=Issues) ## 7.16.3 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.16.2...9019037e300dfdbac5a8cb330d0b09eb82e12f62)) ### Maintenance and upkeep improvements - Remove pytest pin [#2129](https://github.com/jupyter/nbconvert/pull/2129) ([@blink1073](https://github.com/blink1073)) - Add Compatibility with Pandoc 2.9.2 [#2128](https://github.com/jupyter/nbconvert/pull/2128) ([@blink1073](https://github.com/blink1073)) - Pin to Pytest 7 [#2124](https://github.com/jupyter/nbconvert/pull/2124) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2024-03-04&to=2024-03-21&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2024-03-04..2024-03-21&type=Issues) ## 7.16.2 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.16.1...8dac97afa73d59e6afcad04ca076355576b6eb51)) ### Bugs fixed - \[HTMLExporter\] Initialize resources before widget filtering [#2118](https://github.com/jupyter/nbconvert/pull/2118) ([@yuvipanda](https://github.com/yuvipanda)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2024-02-19&to=2024-03-04&type=c)) [@yuvipanda](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ayuvipanda+updated%3A2024-02-19..2024-03-04&type=Issues) ## 7.16.1 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.16.0...443b30703078e6f7d5b1044f25fb77e219136aac)) ### Maintenance and upkeep improvements - Fix permissions for prep release workflow [#2112](https://github.com/jupyter/nbconvert/pull/2112) ([@blink1073](https://github.com/blink1073)) - Update publish workflow [#2111](https://github.com/jupyter/nbconvert/pull/2111) ([@blink1073](https://github.com/blink1073)) - fix for tests/ dir not in sys.path, closes #2066 [#2108](https://github.com/jupyter/nbconvert/pull/2108) ([@ivanov](https://github.com/ivanov)) ### Documentation improvements - Update project description [#2107](https://github.com/jupyter/nbconvert/pull/2107) ([@ivanov](https://github.com/ivanov)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2024-02-07&to=2024-02-19&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2024-02-07..2024-02-19&type=Issues) | [@ivanov](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Aivanov+updated%3A2024-02-07..2024-02-19&type=Issues) ## 7.16.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.15.0...87db94d2d31d77ad16eef2285bb764e97a6f3c11)) ### Enhancements made - Add a toggle to skip the svg encoding of images [#2106](https://github.com/jupyter/nbconvert/pull/2106) ([@gwincr11](https://github.com/gwincr11)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2024-02-06&to=2024-02-07&type=c)) [@gwincr11](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Agwincr11+updated%3A2024-02-06..2024-02-07&type=Issues) ## 7.15.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.14.2...dff141e8c8b392b89eed0adbf035f33810706750)) ### Enhancements made - Support configurable width and height of reveal presentations [#2104](https://github.com/jupyter/nbconvert/pull/2104) ([@franzhaas](https://github.com/franzhaas)) ### Maintenance and upkeep improvements - chore: update pre-commit hooks [#2105](https://github.com/jupyter/nbconvert/pull/2105) ([@pre-commit-ci](https://github.com/pre-commit-ci)) - handle xhtml void elements in mermaid diagrams [#2103](https://github.com/jupyter/nbconvert/pull/2103) ([@bollwyvl](https://github.com/bollwyvl)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2024-01-16&to=2024-02-06&type=c)) [@bollwyvl](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Abollwyvl+updated%3A2024-01-16..2024-02-06&type=Issues) | [@franzhaas](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Afranzhaas+updated%3A2024-01-16..2024-02-06&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2024-01-16..2024-02-06&type=Issues) ## 7.14.2 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.14.1...9d8a7a8771d0349e49328efb7fc2b8fb99c7cc1f)) ### Maintenance and upkeep improvements - update to mermaid 10.7.0 [#2098](https://github.com/jupyter/nbconvert/pull/2098) ([@bollwyvl](https://github.com/bollwyvl)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2024-01-11&to=2024-01-16&type=c)) [@bollwyvl](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Abollwyvl+updated%3A2024-01-11..2024-01-16&type=Issues) ## 7.14.1 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.14.0...dedd81acdde7c96204d01f1392af896d2e6dbe1b)) ### Bugs fixed - Fix broken image scaling in case a custom width or height is provided for the image [#2094](https://github.com/jupyter/nbconvert/pull/2094) ([@AndSte01](https://github.com/AndSte01)) ### Maintenance and upkeep improvements - Allow pre-fetch of css files without attempting download [#2095](https://github.com/jupyter/nbconvert/pull/2095) ([@AlexanderRichert-NOAA](https://github.com/AlexanderRichert-NOAA)) - Bump the actions group with 1 update [#2091](https://github.com/jupyter/nbconvert/pull/2091) ([@dependabot](https://github.com/dependabot)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2024-01-01&to=2024-01-11&type=c)) [@AlexanderRichert-NOAA](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3AAlexanderRichert-NOAA+updated%3A2024-01-01..2024-01-11&type=Issues) | [@AndSte01](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3AAndSte01+updated%3A2024-01-01..2024-01-11&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Adependabot+updated%3A2024-01-01..2024-01-11&type=Issues) ## 7.14.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.13.1...0f17b3069d320565af12a4a12da7d9ce3c18dac4)) ### Enhancements made - Convert `coalescese_streams` function to `CoalesceStreamsPreprocessor` [#2089](https://github.com/jupyter/nbconvert/pull/2089) ([@ryan-williams](https://github.com/ryan-williams)) ### Maintenance and upkeep improvements - chore: update pre-commit hooks [#2090](https://github.com/jupyter/nbconvert/pull/2090) ([@pre-commit-ci](https://github.com/pre-commit-ci)) - Fix webpdf test on Python 3.12 [#2088](https://github.com/jupyter/nbconvert/pull/2088) ([@blink1073](https://github.com/blink1073)) - Clean up import [#2087](https://github.com/jupyter/nbconvert/pull/2087) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-12-21&to=2024-01-01&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-12-21..2024-01-01&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2023-12-21..2024-01-01&type=Issues) | [@ryan-williams](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Aryan-williams+updated%3A2023-12-21..2024-01-01&type=Issues) ## 7.13.1 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.13.0...15b2bc2e215bc3d0ab37508eeeb624ede5da0d36)) ### Bugs fixed - Restore removed import [#2086](https://github.com/jupyter/nbconvert/pull/2086) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-12-18&to=2023-12-21&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-12-18..2023-12-21&type=Issues) ## 7.13.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.12.0...c72ad76251d50c9cf3139e23922e9ef3441e9860)) ### Enhancements made - Add table, td, tr to allowed list of tags [#2083](https://github.com/jupyter/nbconvert/pull/2083) ([@yuvipanda](https://github.com/yuvipanda)) ### Maintenance and upkeep improvements - Remove twitter links that cause linkcheck to fail [#2084](https://github.com/jupyter/nbconvert/pull/2084) ([@yuvipanda](https://github.com/yuvipanda)) - Update ruff config [#2079](https://github.com/jupyter/nbconvert/pull/2079) ([@blink1073](https://github.com/blink1073)) - chore: update pre-commit hooks [#2076](https://github.com/jupyter/nbconvert/pull/2076) ([@pre-commit-ci](https://github.com/pre-commit-ci)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-12-04&to=2023-12-18&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-12-04..2023-12-18&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2023-12-04..2023-12-18&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ayuvipanda+updated%3A2023-12-04..2023-12-18&type=Issues) ## 7.12.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.11.0...4f6ab6583de771e74874e72ec88c7fe09a5d4b6b)) ### Enhancements made - Allow to load config from env. [#2075](https://github.com/jupyter/nbconvert/pull/2075) ([@Carreau](https://github.com/Carreau)) ### Maintenance and upkeep improvements - Use ruff on notebooks and update typings [#2068](https://github.com/jupyter/nbconvert/pull/2068) ([@blink1073](https://github.com/blink1073)) ### Documentation improvements - update Python version support in docs [#2037](https://github.com/jupyter/nbconvert/pull/2037) ([@minrk](https://github.com/minrk)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-11-06&to=2023-12-04&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-11-06..2023-12-04&type=Issues) | [@Carreau](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3ACarreau+updated%3A2023-11-06..2023-12-04&type=Issues) | [@gnestor](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Agnestor+updated%3A2023-11-06..2023-12-04&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Aminrk+updated%3A2023-11-06..2023-12-04&type=Issues) | [@mpacer](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ampacer+updated%3A2023-11-06..2023-12-04&type=Issues) ## 7.11.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.10.0...422dd2a1697b191dc8e11806ddeca314df66c282)) ### Enhancements made - Support es modules in js includes [#2063](https://github.com/jupyter/nbconvert/pull/2063) ([@timkpaine](https://github.com/timkpaine)) ### Maintenance and upkeep improvements - Clean up lint handling and list generics [#2065](https://github.com/jupyter/nbconvert/pull/2065) ([@blink1073](https://github.com/blink1073)) - Remove not needed pytest-dependency test requirement [#2062](https://github.com/jupyter/nbconvert/pull/2062) ([@danigm](https://github.com/danigm)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-10-30&to=2023-11-06&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-10-30..2023-11-06&type=Issues) | [@danigm](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Adanigm+updated%3A2023-10-30..2023-11-06&type=Issues) | [@timkpaine](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Atimkpaine+updated%3A2023-10-30..2023-11-06&type=Issues) ## 7.10.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.9.2...48599a4bba00819e4e626fe098eb204977590ee4)) ### Enhancements made - Update to mermaid 10.6.0, docs keyboard navigation [#2058](https://github.com/jupyter/nbconvert/pull/2058) ([@bollwyvl](https://github.com/bollwyvl)) ### Maintenance and upkeep improvements - Fix typing for traitlets 5.13 [#2060](https://github.com/jupyter/nbconvert/pull/2060) ([@blink1073](https://github.com/blink1073)) - Adopt ruff format [#2059](https://github.com/jupyter/nbconvert/pull/2059) ([@blink1073](https://github.com/blink1073)) - Update typings and remove dead link [#2056](https://github.com/jupyter/nbconvert/pull/2056) ([@blink1073](https://github.com/blink1073)) ### Documentation improvements - Update to mermaid 10.6.0, docs keyboard navigation [#2058](https://github.com/jupyter/nbconvert/pull/2058) ([@bollwyvl](https://github.com/bollwyvl)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-10-05&to=2023-10-30&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-10-05..2023-10-30&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Abollwyvl+updated%3A2023-10-05..2023-10-30&type=Issues) ## 7.9.2 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.9.1...8e85303e530013f9e6d29be85f25e9602a443194)) ### Bugs fixed - Restore ResourcesDict to the public API [#2055](https://github.com/jupyter/nbconvert/pull/2055) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-10-04&to=2023-10-05&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-10-04..2023-10-05&type=Issues) ## 7.9.1 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.9.0...6d679efebf8b6b7c65c4ab0dcb0dec97f6d389b9)) ### Maintenance and upkeep improvements - Include tests in sdist [#2053](https://github.com/jupyter/nbconvert/pull/2053) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-10-04&to=2023-10-04&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-10-04..2023-10-04&type=Issues) ## 7.9.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.8.0...0e36347f31ee0b06d461aaa845e458eb7c9f8fc0)) ### Maintenance and upkeep improvements - Update to mermaidjs 10.5.0 [#2051](https://github.com/jupyter/nbconvert/pull/2051) ([@bollwyvl](https://github.com/bollwyvl)) - Update typing for traitlets 5.11 [#2050](https://github.com/jupyter/nbconvert/pull/2050) ([@blink1073](https://github.com/blink1073)) - chore: update pre-commit hooks [#2049](https://github.com/jupyter/nbconvert/pull/2049) ([@pre-commit-ci](https://github.com/pre-commit-ci)) - Fixup typings [#2048](https://github.com/jupyter/nbconvert/pull/2048) ([@blink1073](https://github.com/blink1073)) - Remove redundant link check in CI [#2044](https://github.com/jupyter/nbconvert/pull/2044) ([@blink1073](https://github.com/blink1073)) - Bump actions/checkout from 3 to 4 [#2042](https://github.com/jupyter/nbconvert/pull/2042) ([@dependabot](https://github.com/dependabot)) - Adopt sp-repo-review [#2040](https://github.com/jupyter/nbconvert/pull/2040) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-08-29&to=2023-10-04&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-08-29..2023-10-04&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Abollwyvl+updated%3A2023-08-29..2023-10-04&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Adependabot+updated%3A2023-08-29..2023-10-04&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2023-08-29..2023-10-04&type=Issues) ## 7.8.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.7.4...9e8d252f2bf5b4177bbbeb007fd1a489356926ec)) ### Enhancements made - MermaidJS 10.3.1, accessibility features, handle MIME [#2034](https://github.com/jupyter/nbconvert/pull/2034) ([@bollwyvl](https://github.com/bollwyvl)) ### Bugs fixed - Fix: Prevent error from all whitespace lang string [#2036](https://github.com/jupyter/nbconvert/pull/2036) ([@Adamtaranto](https://github.com/Adamtaranto)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-08-16&to=2023-08-29&type=c)) [@Adamtaranto](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3AAdamtaranto+updated%3A2023-08-16..2023-08-29&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Abollwyvl+updated%3A2023-08-16..2023-08-29&type=Issues) ## 7.7.4 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.7.3...bbb095ba24c005ce26f0e8b47f4ddf19a5debe68)) ### Bugs fixed - Give main tag a height of 100% in css for reveal html [#2032](https://github.com/jupyter/nbconvert/pull/2032) ([@lkeegan](https://github.com/lkeegan)) ### Maintenance and upkeep improvements ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-07-25&to=2023-08-16&type=c)) [@Carreau](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3ACarreau+updated%3A2023-07-25..2023-08-16&type=Issues) | [@lkeegan](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Alkeegan+updated%3A2023-07-25..2023-08-16&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2023-07-25..2023-08-16&type=Issues) ## 7.7.3 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.7.2...73fd3b9eb5e364bc86f9407e027d5577c5c8db9e)) ### Bugs fixed - Restore pauses during webpdf render [#2025](https://github.com/jupyter/nbconvert/pull/2025) ([@jstorrs](https://github.com/jstorrs)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-07-19&to=2023-07-25&type=c)) [@jstorrs](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ajstorrs+updated%3A2023-07-19..2023-07-25&type=Issues) ## 7.7.2 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.7.1...1cbb0a46d97f9f0b2a6a0d359ebf9b4b50178c25)) ### Bugs fixed - Show a warning if an image has no alternative text [#2024](https://github.com/jupyter/nbconvert/pull/2024) ([@brichet](https://github.com/brichet)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-07-17&to=2023-07-19&type=c)) [@brichet](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Abrichet+updated%3A2023-07-17..2023-07-19&type=Issues) ## 7.7.1 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.7.0...86cebfc16920fcdddef557620a7b8a23d84072d6)) ### Bugs fixed - Restore 'media=print' option [#2022](https://github.com/jupyter/nbconvert/pull/2022) ([@brichet](https://github.com/brichet)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-07-17&to=2023-07-17&type=c)) [@brichet](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Abrichet+updated%3A2023-07-17..2023-07-17&type=Issues) ## 7.7.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.6.0...f2fc3e13fe8e8836324550dac5286bbb0e4315bb)) ### Enhancements made - \[Accessibility\] some accessibility improvements [#2021](https://github.com/jupyter/nbconvert/pull/2021) ([@brichet](https://github.com/brichet)) - Adopt playwright [#2013](https://github.com/jupyter/nbconvert/pull/2013) ([@brichet](https://github.com/brichet)) - Update to Jupyterlab 4 [#2012](https://github.com/jupyter/nbconvert/pull/2012) ([@brichet](https://github.com/brichet)) ### Bugs fixed - html: write image/svg+xml data as base64 and skip clean_html [#2018](https://github.com/jupyter/nbconvert/pull/2018) ([@jstorrs](https://github.com/jstorrs)) - Remove HTML escaping JSON-encoded widget state [#1934](https://github.com/jupyter/nbconvert/pull/1934) ([@manzt](https://github.com/manzt)) ### Maintenance and upkeep improvements - Fix lint error [#2010](https://github.com/jupyter/nbconvert/pull/2010) ([@blink1073](https://github.com/blink1073)) - Support Python 3.8-3.12 [#2008](https://github.com/jupyter/nbconvert/pull/2008) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-06-19&to=2023-07-17&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-06-19..2023-07-17&type=Issues) | [@brichet](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Abrichet+updated%3A2023-06-19..2023-07-17&type=Issues) | [@jstorrs](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ajstorrs+updated%3A2023-06-19..2023-07-17&type=Issues) | [@maartenbreddels](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Amaartenbreddels+updated%3A2023-06-19..2023-07-17&type=Issues) | [@manzt](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Amanzt+updated%3A2023-06-19..2023-07-17&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3AmartinRenou+updated%3A2023-06-19..2023-07-17&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2023-06-19..2023-07-17&type=Issues) ## 7.6.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.5.0...60af6d897c083444586829c636f278d84ae81962)) ### Maintenance and upkeep improvements - Update to Mistune v3 [#1820](https://github.com/jupyter/nbconvert/pull/1820) ([@TiagodePAlves](https://github.com/TiagodePAlves)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-06-13&to=2023-06-19&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-06-13..2023-06-19&type=Issues) | [@kloczek](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Akloczek+updated%3A2023-06-13..2023-06-19&type=Issues) | [@TiagodePAlves](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3ATiagodePAlves+updated%3A2023-06-13..2023-06-19&type=Issues) ## 7.5.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.4.0...3dd3a67bf16474042efac25519ef257d708a8d7b)) ### Enhancements made - Add mermaidjs 10.2.3 [#1957](https://github.com/jupyter/nbconvert/pull/1957) ([@bollwyvl](https://github.com/bollwyvl)) ### Bugs fixed - Fix pdf conversion with explicitly relative paths [#2005](https://github.com/jupyter/nbconvert/pull/2005) ([@tuncbkose](https://github.com/tuncbkose)) - Ensure TEXINPUTS is an absolute path [#2002](https://github.com/jupyter/nbconvert/pull/2002) ([@tuncbkose](https://github.com/tuncbkose)) ### Maintenance and upkeep improvements - bump pandoc max version [#1997](https://github.com/jupyter/nbconvert/pull/1997) ([@tuncbkose](https://github.com/tuncbkose)) - exclude bleach 5.0.0 from dependencies resolution [#1990](https://github.com/jupyter/nbconvert/pull/1990) ([@karlicoss](https://github.com/karlicoss)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-05-08&to=2023-06-13&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-05-08..2023-06-13&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Abollwyvl+updated%3A2023-05-08..2023-06-13&type=Issues) | [@karlicoss](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Akarlicoss+updated%3A2023-05-08..2023-06-13&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2023-05-08..2023-06-13&type=Issues) | [@tuncbkose](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Atuncbkose+updated%3A2023-05-08..2023-06-13&type=Issues) ## 7.4.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.3.1...32fcf7b26462f5d51d577f8beda9d49cd3a0f441)) ### Enhancements made - Add ExtractAttachmentsPreprocessor [#1978](https://github.com/jupyter/nbconvert/pull/1978) ([@tuncbkose](https://github.com/tuncbkose)) ### Bugs fixed - Moved ensure_dir_exists to FilesWriter [#1987](https://github.com/jupyter/nbconvert/pull/1987) ([@tuncbkose](https://github.com/tuncbkose)) - Tweak exporter default_config merging behavior [#1981](https://github.com/jupyter/nbconvert/pull/1981) ([@tuncbkose](https://github.com/tuncbkose)) - Revert unintended effects of #1966 [#1974](https://github.com/jupyter/nbconvert/pull/1974) ([@tuncbkose](https://github.com/tuncbkose)) ### Maintenance and upkeep improvements - Fix test_errors_print_traceback test [#1985](https://github.com/jupyter/nbconvert/pull/1985) ([@blink1073](https://github.com/blink1073)) - Ensure toml support in coverage reporting [#1984](https://github.com/jupyter/nbconvert/pull/1984) ([@blink1073](https://github.com/blink1073)) - Use local coverage [#1976](https://github.com/jupyter/nbconvert/pull/1976) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-04-10&to=2023-05-08&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-04-10..2023-05-08&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Akrassowski+updated%3A2023-04-10..2023-05-08&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2023-04-10..2023-05-08&type=Issues) | [@tuncbkose](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Atuncbkose+updated%3A2023-04-10..2023-05-08&type=Issues) ## 7.3.1 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.3.0...3860152ecea3d9833540eebe279ff603b3d47cea)) ### Bugs fixed - Remove overwriting of default KernelManager [#1972](https://github.com/jupyter/nbconvert/pull/1972) ([@tuncbkose](https://github.com/tuncbkose)) ### Maintenance and upkeep improvements ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-04-03&to=2023-04-10&type=c)) [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2023-04-03..2023-04-10&type=Issues) | [@tuncbkose](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Atuncbkose+updated%3A2023-04-03..2023-04-10&type=Issues) ## 7.3.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.10...056dc4ecc8f9f3e9249f0dbddf1221c65228b961)) ### Enhancements made - Allow pattern in output_base [#1967](https://github.com/jupyter/nbconvert/pull/1967) ([@JeppeKlitgaard](https://github.com/JeppeKlitgaard)) - Make date configurable in latex/PDF [#1963](https://github.com/jupyter/nbconvert/pull/1963) ([@achimgaedke](https://github.com/achimgaedke)) - Update jupyterlab CSS [#1960](https://github.com/jupyter/nbconvert/pull/1960) ([@martinRenou](https://github.com/martinRenou)) ### Maintenance and upkeep improvements - Update ci badge [#1968](https://github.com/jupyter/nbconvert/pull/1968) ([@blink1073](https://github.com/blink1073)) - More detailed release instructions [#1959](https://github.com/jupyter/nbconvert/pull/1959) ([@Carreau](https://github.com/Carreau)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-03-14&to=2023-04-03&type=c)) [@achimgaedke](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Aachimgaedke+updated%3A2023-03-14..2023-04-03&type=Issues) | [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-03-14..2023-04-03&type=Issues) | [@Carreau](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3ACarreau+updated%3A2023-03-14..2023-04-03&type=Issues) | [@JeppeKlitgaard](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3AJeppeKlitgaard+updated%3A2023-03-14..2023-04-03&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3AmartinRenou+updated%3A2023-03-14..2023-04-03&type=Issues) ## 7.2.10 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.9...acf41acf6d83cb725f3a2c48686c828eff7b24d8)) ### Enhancements made - Add cell-id anchor for cell identification [#1897](https://github.com/jupyter/nbconvert/pull/1897) ([@krassowski](https://github.com/krassowski)) ### Bugs fixed - Do not import pyppeteer for installation check [#1947](https://github.com/jupyter/nbconvert/pull/1947) ([@krassowski](https://github.com/krassowski)) ### Maintenance and upkeep improvements - Clean up license [#1949](https://github.com/jupyter/nbconvert/pull/1949) ([@dcsaba89](https://github.com/dcsaba89)) - Add more linting [#1943](https://github.com/jupyter/nbconvert/pull/1943) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-01-24&to=2023-03-14&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-01-24..2023-03-14&type=Issues) | [@dcsaba89](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Adcsaba89+updated%3A2023-01-24..2023-03-14&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Akrassowski+updated%3A2023-01-24..2023-03-14&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2023-01-24..2023-03-14&type=Issues) ## 7.2.9 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.8...14b1d7aa75485ea754c2d0ffc67cc528e3984a99)) ### Bugs fixed - Fix handling of css sanitizer [#1940](https://github.com/jupyter/nbconvert/pull/1940) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2023-01-16&to=2023-01-24&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2023-01-16..2023-01-24&type=Issues) ## 7.2.8 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.7...73f7b1b93a4526d7e9d987f5a5b207eaed8171f2)) ### Bugs fixed - always pass relax_add_props=True when validating [#1936](https://github.com/jupyter/nbconvert/pull/1936) ([@minrk](https://github.com/minrk)) ### Maintenance and upkeep improvements - Update codecov link [#1935](https://github.com/jupyter/nbconvert/pull/1935) ([@blink1073](https://github.com/blink1073)) - Fix types and add lint to automerge [#1932](https://github.com/jupyter/nbconvert/pull/1932) ([@blink1073](https://github.com/blink1073)) - Add type checking [#1930](https://github.com/jupyter/nbconvert/pull/1930) ([@blink1073](https://github.com/blink1073)) - Add spelling and docstring enforcement [#1929](https://github.com/jupyter/nbconvert/pull/1929) ([@blink1073](https://github.com/blink1073)) - Add scheduled ci run [#1926](https://github.com/jupyter/nbconvert/pull/1926) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2022-12-19&to=2023-01-16&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2022-12-19..2023-01-16&type=Issues) | [@maartenbreddels](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Amaartenbreddels+updated%3A2022-12-19..2023-01-16&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3AmartinRenou+updated%3A2022-12-19..2023-01-16&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Aminrk+updated%3A2022-12-19..2023-01-16&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2022-12-19..2023-01-16&type=Issues) ## 7.2.7 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.6...a32c3c1063e081d7e639b7f1670788d220b93810)) ### Bugs fixed - Fix Hanging Tests on Linux [#1924](https://github.com/jupyter/nbconvert/pull/1924) ([@blink1073](https://github.com/blink1073)) ### Maintenance and upkeep improvements - Adopt ruff and handle lint [#1925](https://github.com/jupyter/nbconvert/pull/1925) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2022-12-05&to=2022-12-19&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2022-12-05..2022-12-19&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2022-12-05..2022-12-19&type=Issues) ## 7.2.6 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.5...788dd3c4de1b6333e807250d0f33b59b80d5b202)) ### Maintenance and upkeep improvements - Include all templates in sdist [#1916](https://github.com/jupyter/nbconvert/pull/1916) ([@blink1073](https://github.com/blink1073)) - clean up workflows [#1911](https://github.com/jupyter/nbconvert/pull/1911) ([@blink1073](https://github.com/blink1073)) - CI Cleanup [#1910](https://github.com/jupyter/nbconvert/pull/1910) ([@blink1073](https://github.com/blink1073)) ### Documentation improvements - Fix docs build and switch to PyData Sphinx Theme [#1912](https://github.com/jupyter/nbconvert/pull/1912) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2022-11-14&to=2022-12-05&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2022-11-14..2022-12-05&type=Issues) ## 7.2.5 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.4...e5fefbb17b0bf3d6b5bbeb9a2ee62412d75ab0d8)) ### Bugs fixed - Fix for webpdf print margins [#1907](https://github.com/jupyter/nbconvert/pull/1907) ([@JWock82](https://github.com/JWock82)) ### Maintenance and upkeep improvements - Bump actions/upload-artifact from 2 to 3 [#1904](https://github.com/jupyter/nbconvert/pull/1904) ([@dependabot](https://github.com/dependabot)) - Bump actions/checkout from 2 to 3 [#1903](https://github.com/jupyter/nbconvert/pull/1903) ([@dependabot](https://github.com/dependabot)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2022-11-09&to=2022-11-14&type=c)) [@dependabot](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Adependabot+updated%3A2022-11-09..2022-11-14&type=Issues) | [@JWock82](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3AJWock82+updated%3A2022-11-09..2022-11-14&type=Issues) ## 7.2.4 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.3...90ca66ccf02abc59052f4f38dcc657b0d2c34a07)) ### Maintenance and upkeep improvements - Handle jupyter core warning [#1905](https://github.com/jupyter/nbconvert/pull/1905) ([@blink1073](https://github.com/blink1073)) - Add dependabot [#1902](https://github.com/jupyter/nbconvert/pull/1902) ([@blink1073](https://github.com/blink1073)) - Add Py-typed marker. [#1898](https://github.com/jupyter/nbconvert/pull/1898) ([@Carreau](https://github.com/Carreau)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2022-10-27&to=2022-11-09&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2022-10-27..2022-11-09&type=Issues) | [@Carreau](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3ACarreau+updated%3A2022-10-27..2022-11-09&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2022-10-27..2022-11-09&type=Issues) ## 7.2.3 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.2...04180fdb015c56ac320d5062a81da065791c5726)) ### Bugs fixed - clean_html: allow SVG tags and SVG attributes [#1890](https://github.com/jupyter/nbconvert/pull/1890) ([@akx](https://github.com/akx)) ### Maintenance and upkeep improvements ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2022-10-19&to=2022-10-27&type=c)) [@akx](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Aakx+updated%3A2022-10-19..2022-10-27&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2022-10-19..2022-10-27&type=Issues) ## 7.2.2 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.1...a9566befb6e457b51373b61debffc78050d41273)) ### Bugs fixed - Fix default config test [#1885](https://github.com/jupyter/nbconvert/pull/1885) ([@blink1073](https://github.com/blink1073)) ### Maintenance and upkeep improvements - Add ensure label workflow [#1884](https://github.com/jupyter/nbconvert/pull/1884) ([@blink1073](https://github.com/blink1073)) - Add release workflows [#1883](https://github.com/jupyter/nbconvert/pull/1883) ([@blink1073](https://github.com/blink1073)) - Maintenance cleanup [#1881](https://github.com/jupyter/nbconvert/pull/1881) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2022-10-06&to=2022-10-19&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2022-10-06..2022-10-19&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Apre-commit-ci+updated%3A2022-10-06..2022-10-19&type=Issues) ## 7.2.1 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/v7.2.0...5cfa5893e3e8fe830eec2b8abf791199a52aad07)) ### Bugs fixed - Fix version handling [#1878](https://github.com/jupyter/nbconvert/pull/1878) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2022-10-06&to=2022-10-06&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2022-10-06..2022-10-06&type=Issues) ## 7.2.0 ([Full Changelog](https://github.com/jupyter/nbconvert/compare/7.1.0...e4e85b60c4c130f33db02c4ce209cc4704c7001a)) ### Maintenance and upkeep improvements - Prep for jupyter releaser [#1877](https://github.com/jupyter/nbconvert/pull/1877) ([@blink1073](https://github.com/blink1073)) - Add support for jupyter_client 8 [#1867](https://github.com/jupyter/nbconvert/pull/1867) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/jupyter/nbconvert/graphs/contributors?from=2022-10-03&to=2022-10-06&type=c)) [@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbconvert+involves%3Ablink1073+updated%3A2022-10-03..2022-10-06&type=Issues) ## 7.1.0 - Fix markdown table not render bug by @Neutree in [#1853](https://github.com/jupyter/nbconvert/pull/1853) - Replace lxml.html.clean_html with bleach; drop lxml dependency by @akx in [#1854](https://github.com/jupyter/nbconvert/pull/1854) - Remove CircleCI badge from README by @akx in [#1857](https://github.com/jupyter/nbconvert/pull/1857) - Added support for section (slide) "data-\*" attributes by @bouzidanas in [#1861](https://github.com/jupyter/nbconvert/pull/1861) ## 7.0.0 - Update to Mistune 2.0.2 by @TiagodePAlves in [#1764](https://github.com/jupyter/nbconvert/pull/1764) - Add qtpdf and qtpng exporters by @davidbrochart in [#1611](https://github.com/jupyter/nbconvert/pull/1611) - Add recursive flag for glob notebook search by @paoloalba in [#1785](https://github.com/jupyter/nbconvert/pull/1785) - Encode SVG image data as UTF-8 before calling lxml cleaner by @emarsden in [#1837](https://github.com/jupyter/nbconvert/pull/1837) - Fix lab template output alignment by @dakoop in [#1795](https://github.com/jupyter/nbconvert/pull/1795) - Handle nbformat 5.5 by @blink1073 [#1841](https://github.com/jupyter/nbconvert/pull/1841) - Remove downloaded CSS from repository by @martinRenou [#1827](https://github.com/jupyter/nbconvert/pull/1827) - Switch from entrypoints to importlib-metadata by @konstin in [#1782](https://github.com/jupyter/nbconvert/pull/1782) - Updates for sphinx 5.0 support by @blink1073 in [#1788](https://github.com/jupyter/nbconvert/pull/1788) - Fixed unique div ids in lab template, fixed #1759 by @veghdev in [#1761](https://github.com/jupyter/nbconvert/pull/1761) - WebPDFExporter: Emulate media print by @martinRenou in [#1791](https://github.com/jupyter/nbconvert/pull/1791) - Fix fonts overridden by user stylesheet by inheriting styles by @dakoop in [#1793](https://github.com/jupyter/nbconvert/pull/1793) - Fix lab template output alignment by @dakoop in [#1795](https://github.com/jupyter/nbconvert/pull/1795) - Clean up markdown parsing by @blink1073 in [#1774](https://github.com/jupyter/nbconvert/pull/1774) - Switch to hatch build backend by @blink1073 in [#1777](https://github.com/jupyter/nbconvert/pull/1777) ## 6.5.0 - Support bleach 5, add packaging and tinycss2 dependencies by @bollwyvl in [#1755](https://github.com/jupyter/nbconvert/pull/1755) - Drop dependency on testpath. by @anntzer in [#1723](https://github.com/jupyter/nbconvert/pull/1723) - Adopt pre-commit by @blink1073 in [#1744](https://github.com/jupyter/nbconvert/pull/1744), [#1746](https://github.com/jupyter/nbconvert/pull/1746), [#1748](https://github.com/jupyter/nbconvert/pull/1748), [#1749](https://github.com/jupyter/nbconvert/pull/1749), [#1757](https://github.com/jupyter/nbconvert/pull/1757) - Add pytest settings and handle warnings by @blink1073 in [#1745](https://github.com/jupyter/nbconvert/pull/1745) - Update cli example by @leahecole in [#1753](https://github.com/jupyter/nbconvert/pull/1753) - Clean up workflows by @blink1073 in [#1750](https://github.com/jupyter/nbconvert/pull/1750) ## 6.4.4 - HTMLExporter: Respect the embed_images flag for HTML blocks [#1721](https://github.com/jupyter/nbconvert/pull/1721) ## 6.4.3 - Remove ipython genutils [#1727](https://github.com/jupyter/nbconvert/pull/1727) - Add section to customizing showing how to use template inheritance [#1719](https://github.com/jupyter/nbconvert/pull/1719) ## 6.4.2 - Adding theme support for WebPDF exporter [#1718](https://github.com/jupyter/nbconvert/pull/1718) - Add option to embed_images in Markdown cells [#1717](https://github.com/jupyter/nbconvert/pull/1717) - HTMLExporter: Add theme alias and docs [#1716](https://github.com/jupyter/nbconvert/pull/1716) - Add basic support for federated labextensions themes [#1703](https://github.com/jupyter/nbconvert/pull/1703) - Always hide the collapser element [#1712](https://github.com/jupyter/nbconvert/pull/1712) - Raise pyppeteer requirement to >=1,\<1.1 [#1711](https://github.com/jupyter/nbconvert/pull/1711) ## 6.4.1 - Handle needs_background cell metadata [#1704](https://github.com/jupyter/nbconvert/pull/1704) - Fix styling regression [#1708](https://github.com/jupyter/nbconvert/pull/1708) - Fix DOM structure of markdown cells in lab template [#1709](https://github.com/jupyter/nbconvert/pull/1709) - CodeMirror style bleed fix [#1710](https://github.com/jupyter/nbconvert/pull/1710) ## 6.4.0 The full list of changes can be seen on the [6.4.0 milestone](https://github.com/jupyter/nbconvert/milestone/23?closed=1) - Allow passing extra args to code highlighter [#1683](https://github.com/jupyter/nbconvert/pull/1683) - Prevent page breaks in outputs when printing [#1679](https://github.com/jupyter/nbconvert/pull/1679) - Add collapsers to template [#1689](https://github.com/jupyter/nbconvert/pull/1689) - Optionally speed up validation [#1672](https://github.com/jupyter/nbconvert/pull/1672) ## 6.3.0 The full list of changes can be seen on the [6.3.0 milestone](https://github.com/jupyter/nbconvert/milestone/22?closed=1) - Update state filter [#1664](https://github.com/jupyter/nbconvert/pull/1664) - Add slide numbering [#1654](https://github.com/jupyter/nbconvert/pull/1654) - Fix HTML templates mentioned in help docs [#1653](https://github.com/jupyter/nbconvert/pull/1653) ## 6.2.0 The full list of changes can be seen on the [6.2.0 milestone](https://github.com/jupyter/nbconvert/milestone/21?closed=1) - Add the ability to fully customize `widget_renderer_url` [#1614](https://github.com/jupyter/nbconvert/pull/1614) - Enable users to customize MathJax URLs [#1609](https://github.com/jupyter/nbconvert/pull/1609) - Add CLI configuration for disable-chromium-sandbox [#1625](https://github.com/jupyter/nbconvert/pull/1625) - Enables webpdf to be rendered with templates [#1601](https://github.com/jupyter/nbconvert/pull/1601) - Adds dejavu [#1599](https://github.com/jupyter/nbconvert/pull/1599) ## 6.1.0 This release is mostly a long list of bug fixes and capability additions. Thanks to the many contributors for helping Improve nbconvert! The following 31 authors contributed 81 commits. - Adolph - Alessandro Finamore - Angus Hollands - Atsuo Ishimoto - Bo - David Brochart - Frédéric Collonval - Jeremy Howard - Jim Zwartveld - José Ignacio Romero - Joyce Er - joyceerhl - Kyle Cutler - Leah E. Cole - Leah Wasser - Nihiue - Matthew Seal - Michael Adolph - Mohammad Mostafa Farzan - Okky Mabruri - Pill-GZ - ptcane - Raniere Silva - Ryan Moe - Stefan Lang - Sylvain Corlay - Tobin Jones - txoof - Yuvi Panda ### Significant Changes - Dropped Python 3.6 and added Python 3.9 [#1542](https://github.com/jupyter/nbconvert/pull/1542) and [#1556](https://github.com/jupyter/nbconvert/pull/1556) - Convert execute preprocessor wrapper to resemble papermill [#1448](https://github.com/jupyter/nbconvert/pull/1448) ### Comprehensive notes - Feature: support static widgets in Reveal.js slides [#1553](https://github.com/jupyter/nbconvert/pull/1553) - Feature: add speaker notes to Reveal.js template [#1543](https://github.com/jupyter/nbconvert/pull/1543) - Add correct output mimetype to WebPDF exporter [#1534](https://github.com/jupyter/nbconvert/pull/1534) - Set mimetype for webpdf correctly [#1514](https://github.com/jupyter/nbconvert/pull/1514) - Fix docstring issue and a broken link [#1576](https://github.com/jupyter/nbconvert/pull/1576) - Add CLI example for removing cell tag syntax [#1504](https://github.com/jupyter/nbconvert/pull/1504) - Include output of stdin stream in lab template [#1454](https://github.com/jupyter/nbconvert/pull/1454) - Don't use a shell to call inkscape [#1512](https://github.com/jupyter/nbconvert/pull/1512) - JupyterLab export as HTML with widgets fails to load widgets [#1474](https://github.com/jupyter/nbconvert/pull/1474) - Move note inside Reveal.js HTML slideshow [#1510](https://github.com/jupyter/nbconvert/pull/1510) - fix issue 1507: broken command line option --CSSHTMLHeaderPreprocessor.style= [#1548](https://github.com/jupyter/nbconvert/pull/1548) - Fix order of template paths [#1496](https://github.com/jupyter/nbconvert/pull/1496) - Changed documentation of external_exporters [#1582](https://github.com/jupyter/nbconvert/pull/1582) - Fix template precedence when using a custom template (#1558) [#1577](https://github.com/jupyter/nbconvert/pull/1577) - add pip to docs envt [#1571](https://github.com/jupyter/nbconvert/pull/1571) - Fix CI By Adding PIP to conda envt for docs build [#1570](https://github.com/jupyter/nbconvert/pull/1570) - Explicitly install pip in docs environment.yml [#1569](https://github.com/jupyter/nbconvert/pull/1569) - small update to docs hide cell [#1567](https://github.com/jupyter/nbconvert/pull/1567) - Allow child templates to override mathjax [#1551](https://github.com/jupyter/nbconvert/pull/1551) - Allow get_export_names to skip configuration check [#1471](https://github.com/jupyter/nbconvert/pull/1471) - Update docs: Tex Live package on Ubuntu [#1555](https://github.com/jupyter/nbconvert/pull/1555) - Test jupyter_client [#1545](https://github.com/jupyter/nbconvert/pull/1545) - Update jupyterlab css [#1539](https://github.com/jupyter/nbconvert/pull/1539) - Webpdf: Use a temporary file instead of an URL [#1489](https://github.com/jupyter/nbconvert/pull/1489) - Applied patch for marking network changes [#1527](https://github.com/jupyter/nbconvert/pull/1527) - Change webpdf display name [#1515](https://github.com/jupyter/nbconvert/pull/1515) - Allow disabling pyppeteer sandbox [#1516](https://github.com/jupyter/nbconvert/pull/1516) - Make pagination configurable in webpdf [#1513](https://github.com/jupyter/nbconvert/pull/1513) - Fix Reveal.js version in documentation [#1509](https://github.com/jupyter/nbconvert/pull/1509) - Fix dangling reference to get_template_paths() [#1463](https://github.com/jupyter/nbconvert/pull/1463) - Solved svg2pdf conversion error if Inkscape is installed into the default path on a windows machine [#1469](https://github.com/jupyter/nbconvert/pull/1469) - fix typo [#1499](https://github.com/jupyter/nbconvert/pull/1499) - Update version dependency of traitlets [#1498](https://github.com/jupyter/nbconvert/pull/1498) - Update execute.py [#1457](https://github.com/jupyter/nbconvert/pull/1457) - Fix code output indentation when running nbconvert --no-input [#1444](https://github.com/jupyter/nbconvert/pull/1444) - fix issue (i'd call it a BUG) #1167 [#1450](https://github.com/jupyter/nbconvert/pull/1450) - #1428 add docstring [#1433](https://github.com/jupyter/nbconvert/pull/1433) - Update nbconvert_library.ipynb [#1438](https://github.com/jupyter/nbconvert/pull/1438) - Supports isolated iframe when converting to HTML [#1593](https://github.com/jupyter/nbconvert/pull/1593) ## 6.0.7 Primarily a release addressing template extensions issues reported since 6.0 launched. ### Comprehensive notes - Comment typo fix [#1425](https://github.com/jupyter/nbconvert/pull/1425) - Documented updated to default conversion changes from 6.0 [#1426](https://github.com/jupyter/nbconvert/pull/1426) - Allow custom template files outside of the template system to set their base template name [#1429](https://github.com/jupyter/nbconvert/pull/1429) - Restored basic template from 5.x [#1431](https://github.com/jupyter/nbconvert/pull/1431) - Added proper support for backwards compatibility templates [#1431](https://github.com/jupyter/nbconvert/pull/1431) ## 6.0.6 A range of bug fixes for webpdf exports ### Comprehensive notes - Removed CSS preprocessor from default proprocessor list (fixes classic rendering) [#1411](https://github.com/jupyter/nbconvert/pull/1411) - Fixed error when pickling TemplateExporter [#1399](https://github.com/jupyter/nbconvert/pull/1399) - Support for fractional height html / webpdf exports [#1413](https://github.com/jupyter/nbconvert/pull/1413) - Added short wait time for fonts and rendering in webpdf [#1414](https://github.com/jupyter/nbconvert/pull/1414) - Updated template documentation - Minor fixes to the webpdf exporter [#1419](https://github.com/jupyter/nbconvert/pull/1419) - Fixup use with a running event loop within webpdf [#1420](https://github.com/jupyter/nbconvert/pull/1420) - Prevent overflow in input areas in lab template [#1422](https://github.com/jupyter/nbconvert/pull/1422) ## 6.0.5 - Revert networkidle2 change which caused custom cdn-fetched widgets in webpdf ## 6.0.4 ### Comprehensive notes #### Fixing Problems - The webpdf exporters does not add pagebreaks anymore before reaching the maximum height allowed by Adobe [#1402](https://github.com/jupyter/nbconvert/pull/1402) - Fixes some timeout issues with the webpdf exporter [#1400](https://github.com/jupyter/nbconvert/pull/1400) ## 6.0.3 Execute preprocessor no longer add illegal execution counts to markdown cells [#1396](https://github.com/jupyter/nbconvert/pull/1396) ## 6.0.2 A patch for a few minor issues raised out of the 6.0 release. ### Comprehensive notes #### Fixing Problems - Added windows work-around fix in CLI for async applications [#1383](https://github.com/jupyter/nbconvert/pull/1383) - Fixed pathed template files to behave correctly for local relative paths without a dot [#1381](https://github.com/jupyter/nbconvert/pull/1381) - ExecuteProcessor now properly has a `preprocess_cell` function to overwrite [#1380](https://github.com/jupyter/nbconvert/pull/1380) #### Testing, Docs, and Builds - Updated README and docs with guidance on how to get help with nbconvert [#1377](https://github.com/jupyter/nbconvert/pull/1377) - Fixed documentation that was referencing `template_path` instead of `template_paths` [#1374](https://github.com/jupyter/nbconvert/pull/1374) ## 6.0.1 A quick patch to fix an issue with get_exporter [#1367](https://github.com/jupyter/nbconvert/pull/1367) ## 6.0 The following authors and reviewers contributed the changes for this release -- Thanks you all! - Ayaz Salikhov - bnables - Bo - David Brochart - David Cortés - Eric Wieser - Florian Rathgeber - Ian Allison - James Wilshaw - Jeremy Tuloup - Joel Ostblom - Jon Bannister - Jonas Drotleff - Josh Devlin - Karthikeyan Singaravelan - Kerwin.Sun - letmerecall - Luciano Resende - Lumír 'Frenzy' Balhar - Maarten A. Breddels - Maarten Breddels - Marcel Stimberg - Matthew Brett - Matthew Seal - Matthias Bussonnier - Matthias Geier - Miro Hrončok - Phil Austin - Praveen Batra - Ruben Di Battista - Ruby Werman - Sang-Yun Oh - Sergey Kizunov - Sundar - Sylvain Corlay - telamonian - Thomas Kluyver - Thomas Ytterdal - Tyler Makaro - Yu-Cheng (Henry) Huang ### Significant Changes Nbconvert 6.0 is a major release of nbconvert which includes many significant changes. - Python 2 support was dropped. Currently Python 3.6-3.8 is supported and tested by nbconvert. However, nbconvert 6.0 provides limited support for Python 3.6. nbconvert 6.1 will drop support for Python 3.6. Limited support means we will test and run CI on Python 3.6.12 or higher. Issues that are found only affecting Python 3.6 are not guaranteed to be fixed. We recommend all users of nbconvert use Python 3.7 and higher. - Unlike previous versions, nbconvert 6.0 relies on the [nbclient](https://github.com/jupyter/nbclient/) package for the execute preprocessor, which allows for asynchronous kernel requests. - `template_path` has become `template_paths`. If referring to a 5.x style `.tpl` template use the full path with the `template_file` argument to the file. On the command line the pattern is `--template-file=`. - Nbconvert 6.0 includes a new "webpdf" exporter, which renders notebooks in pdf format through a headless web browser, so that complex outputs such as HTML tables, or even widgets are rendered in the same way as with the HTML exporter and a web browser. - The default template applied when exporting to HTML now produces the same DOM structure as JupyterLab, and is styled using JupyterLab's CSS. The pygments theme in use mimics JupyterLab's codemirror mode with the same CSS variables, so that custom JupyterLab themes could be applied. The classic notebook styling can still be enabled with ```bash jupyter nbconvert --to html --template classic ``` - Nbconvert 6.0 includes a new system for creating custom templates, which can now be installed as packages. A custom "foobar" template is installed in Jupyter's data directory under `nbconvert/templates` and has the form of a directory containing all resources. Templates specify their base template as well as other configuration parameters in a `conf.json` at the root of the template directory. - The "slideshow" template now makes use of RevealJS version 4. It can now be used with the HTML exporter with ```bash jupyter nbconvert --to html --template reveal ``` The `--to slides` exporter is still supported for convenience. - Inkscape 1.0 is now supported, which had some breaking changes that prevented 5.x versions of nbconvert from converting documents on some systems that updated. ### Remaining changes We merged 105 pull requests! Rather than enumerate all of them we'll link to the github page which contains the many smaller impact improvements. The full list can be seen [on GitHub](https://github.com/jupyter/nbconvert/issues?q=milestone%3A6.0+) ## 5.6.1 The following authors and reviewers contributed the changes for this release -- Thanks you all! - Charles Frye - Chris Holdgraf - Felipe Rodrigues - Gregor Sturm - Jim - Kerwin Sun - Ryan Beesley - Matthew Seal - Matthias Geier - thuy-van - Tyler Makaro ### Significant Changes #### RegExRemove applies to all cells RegExRemove preprocessor now removes cells regardless of cell outputs. Before this only cells that had outputs were filtered. ### Comprehensive notes #### New Features - Add support for alt tags for jpeg and png images [#1112](https://github.com/jupyter/nbconvert/pull/1112) - Allow HTML header anchor text to be HTML [#1101](https://github.com/jupyter/nbconvert/pull/1101) - Change RegExRemove to remove code cells with output [#1095](https://github.com/jupyter/nbconvert/pull/1095) - Added cell tag data attributes to HTML exporter [#1090](https://github.com/jupyter/nbconvert/pull/1090) and [#1089](https://github.com/jupyter/nbconvert/pull/1089) #### Fixing Problems - Update svg2pdf.py to search the PATH for inkscape [#1115](https://github.com/jupyter/nbconvert/pull/1115) - Fix latex dependencies installation command for Ubuntu systems [#1109](https://github.com/jupyter/nbconvert/pull/1109) #### Testing, Docs, and Builds - Added Circle CI builds for documentation [#1114](https://github.com/jupyter/nbconvert/pull/1114) [#1120](https://github.com/jupyter/nbconvert/pull/1120), and [#1116](https://github.com/jupyter/nbconvert/pull/1116) - Fix typo in argument name in docstring (TagRemovePreprocessor) [#1103](https://github.com/jupyter/nbconvert/pull/1103) - Changelog typo fix [#1100](https://github.com/jupyter/nbconvert/pull/1100) - Updated API page for TagRemovePreprocessor and TemplateExporter [#1088](https://github.com/jupyter/nbconvert/pull/1088) - Added remove_input_tag traitlet to the docstring [#1088](https://github.com/jupyter/nbconvert/pull/1088) ## 5.6 The following 24 authors and reviewers contributed 224 commits -- Thank you all! - 00Kai0 - Aidan Feldman - Alex Rudy - Alexander Kapshuna - Alexander Rudy - amniskin - Carol Willing - Dustin H - Hsiaoming Yang - imtsuki - Jessica B. Hamrick - KrokodileDandy - Kunal Marwaha - Matthew Seal - Matthias Geier - Miro Hrončok - M Pacer - Nils Japke - njapke - Sebastian Führ - Sylvain Corlay - Tyler Makaro - Valery M - Wayne Witzel The full list of changes they made can be seen [on GitHub](https://github.com/jupyter/nbconvert/issues?q=milestone%3A5.6+) ### Significant Changes #### Jupter Client Pin The `jupyter_client` dependency is now pinned to `>5.3.1`. This is done to support the Parallel NBConvert below, and future versions may require interface changes from that version. #### Parallel NBConvert NBConvert `--execute` can now be run in parallel via threads, multiprocessing, or async patterns! This means you can now parallelize nbconvert via a bash loop, or a python concurrency pattern and it should be able to execute those notebooks in parallel. Kernels have varying support for safe concurrent execution. The ipython kernel (ipykernel version 1.5.2 and higher) should be safe to run concurrently using Python 3. However, the Python 2 ipykernel does not always provide safe concurrent execution and sometimes fails with a socket bind exception. Unlike ipykernel which is maintained by the project, other community-maintained kernels may have varying support for concurrent execution, and these kernels were not tested heavily. Issues for nbconvert can be viewed here: [#1018](https://github.com/jupyter/nbconvert/pull/1018), and [#1017](https://github.com/jupyter/nbconvert/pull/1017) #### Execute Loop Rewrite This release completely rewrote the execution loop responsible for monitoring kernel messages until cell execution is completed. This removes an error where kernel messages could be dropped if too many were posted too quickly. Furthermore, the change means that messages are not buffered. Now, messages can be logged immediately rather than waiting for the cell to terminate. See [#994](https://github.com/jupyter/nbconvert/pull/994) for exact code changes if you're curious. ### Comprehensive notes #### New Features - Make a default global location for custom user templates [#1028](https://github.com/jupyter/nbconvert/pull/1028) - Parallel execution improvements [#1018](https://github.com/jupyter/nbconvert/pull/1018), and [#1017](https://github.com/jupyter/nbconvert/pull/1017) - Added `store_history` option to `preprocess_cell` and `run_cell` [#1055](https://github.com/jupyter/nbconvert/pull/1055) - Simplify the function signature for preprocess() [#1042](https://github.com/jupyter/nbconvert/pull/1042) - Set flag to not always stop kernel execution on errors [#1040](https://github.com/jupyter/nbconvert/pull/1040) - `setup_preprocessor` passes kwargs to `start_new_kernel` [#1021](https://github.com/jupyter/nbconvert/pull/1021) #### Fixing Problems - Very fast stream outputs no longer drop some messages [#994](https://github.com/jupyter/nbconvert/pull/994) - LaTeX errors now properly raise exceptions [#1053](https://github.com/jupyter/nbconvert/pull/1053) - Improve template whitespacing [#1076](https://github.com/jupyter/nbconvert/pull/1076) - Fixes for character in LaTeX exports and filters [#1068](https://github.com/jupyter/nbconvert/pull/1068), [#1039](https://github.com/jupyter/nbconvert/pull/1039), [#1024](https://github.com/jupyter/nbconvert/pull/1024), and [#1077](https://github.com/jupyter/nbconvert/pull/1077) - Mistune pinned in preparation for 2.0 release [#1074](https://github.com/jupyter/nbconvert/pull/1074) - Require mock only on Python 2 [#1060](https://github.com/jupyter/nbconvert/pull/1060) and [#1011](https://github.com/jupyter/nbconvert/pull/1011) - Fix selection of mimetype when converting to HTML [#1036](https://github.com/jupyter/nbconvert/pull/1036) - Correct a few typos [#1029](https://github.com/jupyter/nbconvert/pull/1029) - Update `export_from_notebook` names [#1027](https://github.com/jupyter/nbconvert/pull/1027) - Dedenting html in ExtractOutputPreprocessor [#1023](https://github.com/jupyter/nbconvert/pull/1023) - Fix backwards incompatibility with markdown2html [#1022](https://github.com/jupyter/nbconvert/pull/1022) - Fixed html image tagging [#1013](https://github.com/jupyter/nbconvert/pull/1013) - Remove unnecessary css [#1010](https://github.com/jupyter/nbconvert/pull/1010) #### Testing, Docs, and Builds - Pip-install nbconvert on readthedocs.org [#1069](https://github.com/jupyter/nbconvert/pull/1069) - Fix various doc build issues [#1051](https://github.com/jupyter/nbconvert/pull/1051), [#1050](https://github.com/jupyter/nbconvert/pull/1050), [#1019](https://github.com/jupyter/nbconvert/pull/1019), and [#1048](https://github.com/jupyter/nbconvert/pull/1048) - Add issue templates [#1046](https://github.com/jupyter/nbconvert/pull/1046) - Added instructions for bumping the version forward when releasing [#1034](https://github.com/jupyter/nbconvert/pull/1034) - Fix Testing on Windows [#1030](https://github.com/jupyter/nbconvert/pull/1030) - Refactored `test_run_notebooks` [#1015](https://github.com/jupyter/nbconvert/pull/1015) - Fixed documentation typos [#1009](https://github.com/jupyter/nbconvert/pull/1009) ## 5.5 The following 18 authors contributed 144 commits -- Thank you all! - Benjamin Ragan-Kelley - Clayton A Davis - DInne Bosman - Doug Blank - Henrique Silva - Jeff Hale - Lukasz Mitusinski - M Pacer - Maarten Breddels - Madhumitha N - Matthew Seal - Paul Gowder - Philipp A - Rick Lupton - Rüdiger Busche - Thomas Kluyver - Tyler Makaro - WrRan The full list of changes they made can be seen [on GitHub](https://github.com/jupyter/nbconvert/issues?q=milestone%3A5.5+) ### Significant Changes #### Deprecations Python 3.4 support was dropped. Many of our upstream libraries stopped supporting 3.4 and it was found that serious bugs were being caught during testing against those libraries updating past 3.4. See [#979](https://github.com/jupyter/nbconvert/pull/979) for details. #### IPyWidget Support Now when a notebook executing contains [Jupyter Widgets](https://github.com/jupyter-widgets/ipywidgets/), the state of all the widgets can be stored in the notebook's metadata. This allows rendering of the live widgets on, for instance nbviewer, or when converting to html. You can tell nbconvert to not store the state using the `store_widget_state` argument: ``` jupyter nbconvert --ExecutePreprocessor.store_widget_state=False --to notebook --execute mynotebook.ipynb ``` This widget rendering is not performed against a browser during execution, so only widget default states or states manipulated via user code will be calculated during execution. `%%javascript` cells will execute upon notebook rendering, enabling complex interactions to function as expected when viewed by a UI. If you can't view widget results after execution, you may need to select `File --> Trust Notebook` in the menu. See [#779](https://github.com/jupyter/nbconvert/pull/779), [#900](https://github.com/jupyter/nbconvert/pull/900), and [#983](https://github.com/jupyter/nbconvert/pull/983) for details. #### Execute Preprocessor Rework Based on monkey patching required in [papermill](https://github.com/nteract/papermill/blob/0.19.1/papermill/preprocess.py) the `run_cell` code path in the ExecutePreprocessor was reworked to allow for accessing individual message parses without reimplementing the entire function. Now there is a `process_message` function which take a ZeroMQ message and applies all of its side-effect updates on the cell/notebook objects before returning the output it generated, if it generated any such output. The change required a much more extensive test suite covering cell execution as test coverage on the various, sometimes wonky, code paths made improvements and reworks impossible to prove undamaging. Now changes to kernel message processing has much better coverage, so future additions or changes with specs over time will be easier to add. See [#905](https://github.com/jupyter/nbconvert/pull/905) and [#982](https://github.com/jupyter/nbconvert/pull/982) for details #### Out Of Memory Kernel Failure Catches When running out of memory on a machine, if the kernel process was killed by the operating system it would result in a timeout error at best and hang indefinitely at worst. Now regardless of timeout configuration, if the underlying kernel process dies before emitting any messages to the effect an exception will be raised notifying the consumer of the lost kernel within a few seconds. See [#959](https://github.com/jupyter/nbconvert/pull/959), [#971](https://github.com/jupyter/nbconvert/pull/971), and [#998](https://github.com/jupyter/nbconvert/pull/998) for details #### Latex / PDF Template Improvements The latex template was long overdue for improvements. The default template had a rewrite which makes exports for latex and pdf look a lot better. Code cells in particular render much better with line breaks and styling the more closely matches notebook browser rendering. Thanks t-makaro for the efforts here! See [#992](https://github.com/jupyter/nbconvert/pull/992) for details ### Comprehensive notes #### New Features - IPyWidget Support [#779](https://github.com/jupyter/nbconvert/pull/779), [#900](https://github.com/jupyter/nbconvert/pull/900), and [#983](https://github.com/jupyter/nbconvert/pull/983) - A new ClearMetadata Preprocessor is available [#805](https://github.com/jupyter/nbconvert/pull/805) - Support for pandoc 2 [#964](https://github.com/jupyter/nbconvert/pull/964) - New, and better, latex template [#992](https://github.com/jupyter/nbconvert/pull/992) #### Fixing Problems - Refactored execute preprocessor to have a process_message function [#905](https://github.com/jupyter/nbconvert/pull/905): - Fixed OOM kernel failures hanging [#959](https://github.com/jupyter/nbconvert/pull/959) and [#971](https://github.com/jupyter/nbconvert/pull/971) - Fixed latex export for svg data in python 3 [#985](https://github.com/jupyter/nbconvert/pull/985) - Enabled configuration to be shared to exporters from script exporter [#993](https://github.com/jupyter/nbconvert/pull/993) - Make latex errors less verbose [#988](https://github.com/jupyter/nbconvert/pull/988) - Typo in template syntax [#984](https://github.com/jupyter/nbconvert/pull/984) - Improved attachments +fix supporting non-unique names [#980](https://github.com/jupyter/nbconvert/pull/980) - PDFExporter "output_mimetype" traitlet is not longer 'text/latex' [#972](https://github.com/jupyter/nbconvert/pull/972) - FIX: respect wait for clear_output [#969](https://github.com/jupyter/nbconvert/pull/969) - address deprecation warning in cgi.escape [#963](https://github.com/jupyter/nbconvert/pull/963) - Correct inaccurate description of available LaTeX template [#958](https://github.com/jupyter/nbconvert/pull/958) - Fixed kernel death detection for executions with timeouts [#998](https://github.com/jupyter/nbconvert/pull/998): - Fixed export names for various templates [#1000](https://github.com/jupyter/nbconvert/pull/1000), [#1001](https://github.com/jupyter/nbconvert/pull/1001), and [#1001](https://github.com/jupyter/nbconvert/pull/1001): #### Deprecations - Dropped support for python 3.4 [#979](https://github.com/jupyter/nbconvert/pull/979) - Removed deprecated `export_by_name` [#945](https://github.com/jupyter/nbconvert/pull/945) #### Testing, Docs, and Builds - Added tests for each branch in execute's run_cell method [#982](https://github.com/jupyter/nbconvert/pull/982) - Mention formats in --to options more clearly [#991](https://github.com/jupyter/nbconvert/pull/991) - Adds ascii output type to command line docs page, mention image folder output [#956](https://github.com/jupyter/nbconvert/pull/956) - Simplify setup.py [#949](https://github.com/jupyter/nbconvert/pull/949) - Use utf-8 encoding in execute_api example [#921](https://github.com/jupyter/nbconvert/pull/921) - Upgrade pytest on Travis [#941](https://github.com/jupyter/nbconvert/pull/941) - Fix LaTeX base template name in docs [#940](https://github.com/jupyter/nbconvert/pull/940) - Updated release instructions based on 5.4 release walk-through [#887](https://github.com/jupyter/nbconvert/pull/887) - Fixed broken link to jinja docs [#997](https://github.com/jupyter/nbconvert/pull/997) ## 5.4.1 [5.4.1 on Github](https://github.com/jupyter/nbconvert/milestones/5.4.1) Thanks to the following 11 authors who contributed 57 commits. - Benjamin Ragan-Kelley - Carol Willing - Clayton A Davis - Daniel Rodriguez - M Pacer - Matthew Seal - Matthias Geier - Matthieu Parizy - Rüdiger Busche - Thomas Kluyver - Tyler Makaro ### Comprehensive notes #### New Features - Expose pygments styles [#889](https://github.com/jupyter/nbconvert/pull/889) - Tornado 6.0 support -- Convert proxy handler from callback to coroutine [#937](https://github.com/jupyter/nbconvert/pull/937) - Add option to overwrite the highlight_code filter [#877](https://github.com/jupyter/nbconvert/pull/877) #### Fixing Problems - Mathjax.tpl fix for rendering Latex in html [#932](https://github.com/jupyter/nbconvert/pull/932) - Backwards compatibility for empty kernel names [#927](https://github.com/jupyter/nbconvert/pull/927) [#924](https://github.com/jupyter/nbconvert/pull/924) #### Testing, Docs, and Builds - DOC: Add missing language specification to code-block [#882](https://github.com/jupyter/nbconvert/pull/882) ## 5.4 [5.4 on Github](https://github.com/jupyter/nbconvert/milestones/5.4) ### Significant Changes #### Deprecations Python 3.3 support was dropped. The version of python is no longer common and new versions have many fixes and interface improvements that warrant the change in support. See [#843](https://github.com/jupyter/nbconvert/pull/843) for implementation details. #### Changes in how we handle metadata There were a few new metadata fields which are now respected in nbconvert. `nb.metadata.authors` metadata attribute will be respected in latex exports. Multiple authors will be added with `,` separation against their names. `nb.metadata.title` will be respected ahead of `nb.metadata.name` for title assignment. This better matches with the notebook format. `nb.metadata.filename` will override the default `output_filename_template` when extracting notebook resources in the `ExtractOutputPreprocessor`. The attribute is helpful for when you want to consistently fix to a particular output filename, especially when you need to set image filenames for your exports. The `raises-exception` cell tag (`nb.cells[].metadata.tags[raises-exception]`) allows for cell exceptions to not halt execution. The tag is respected in the same way by [nbval](https://github.com/computationalmodelling/nbval) and other notebook interfaces. `nb.metadata.allow_errors` will apply this rule for all cells. This feature is toggleable with the `force_raise_errors` configuration option. Errors from executing the notebook can be allowed with a `raises-exception` tag on a single cell, or the `allow_errors` configurable option for all cells. An allowed error will be recorded in notebook output, and execution will continue. If an error occurs when it is not explicitly allowed, a 'CellExecutionError' will be raised. If `force_raise_errors` is True, `CellExecutionError` will be raised for any error that occurs while executing the notebook. This overrides both the `allow_errors` option and the `raises-exception` cell tags. See [#867](https://github.com/jupyter/nbconvert/pull/867), [#703](https://github.com/jupyter/nbconvert/pull/703), [#685](https://github.com/jupyter/nbconvert/pull/685), [#672](https://github.com/jupyter/nbconvert/pull/672), and [#684](https://github.com/jupyter/nbconvert/pull/684) for implementation changes. #### Configurable kernel managers when executing notebooks The kernel manager can now be optionally passed into the `ExecutePreprocessor.preprocess` and the `executenb` functions as the keyword argument `km`. This means that the kernel can be configured as desired before beginning preprocessing. This is useful for executing in a context where the kernel has external dependencies that need to be set to non-default values. An example of this might be a Spark kernel where you wish to configure the Spark cluster location ahead of time without building a new kernel. Overall the ExecutePreprocessor has been reworked to make it easier to use. Future releases will continue this trend to make this section of the code more inheritable and reusable by others. We encourage you read the source code for this version if you're interested in the detailed improvements. See [#852](https://github.com/jupyter/nbconvert/pull/852) for implementation changes. #### Surfacing exporters in front-ends Exporters are now exposed for front-ends to consume, including classic notebook. As an example, this means that latex exporter will be made available for latex 'text/latex' media type from the Download As interface. See [#759](https://github.com/jupyter/nbconvert/pull/759) and [#864](https://github.com/jupyter/nbconvert/pull/864) for implementation changes. #### Raw Templates Template exporters can now be assigned raw templates as string attributes by setting the `raw_template` variable. ```python class AttrExporter(TemplateExporter): # If the class has a special template and you want it defined within the class raw_template = """{%- extends 'rst.tpl' -%} {%- block in_prompt -%} raw template {%- endblock in_prompt -%} """ exporter_attr = AttrExporter() output_attr, _ = exporter_attr.from_notebook_node(nb) assert "raw template" in output_attr ``` See [#675](https://github.com/jupyter/nbconvert/pull/675) for implementation changes. #### New command line flags The `--no-input` will hide input cells on export. This is great for notebooks which generate "reports" where you want the code that was executed to not appear by default in the extracts. An alias for `notebook` was added to exporter commands. Now `--to ipynb` will behave as `--to notebook` does. See [#825](https://github.com/jupyter/nbconvert/pull/825) and [#873](https://github.com/jupyter/nbconvert/pull/873) for implementation changes. ### Comprehensive notes #### New Features - No input flag (`--no-input`) [#825](https://github.com/jupyter/nbconvert/pull/825) - Add alias `--to ipynb` for notebook exporter [#873](https://github.com/jupyter/nbconvert/pull/873) - Add `export_from_notebook` [#864](https://github.com/jupyter/nbconvert/pull/864) - If set, use `nb.metadata.authors` for LaTeX author line [#867](https://github.com/jupyter/nbconvert/pull/867) - Populate language_info metadata when executing [#860](https://github.com/jupyter/nbconvert/pull/860) - Support for `\mathscr` [#830](https://github.com/jupyter/nbconvert/pull/830) - Allow the execute preprocessor to make use of an existing kernel [#852](https://github.com/jupyter/nbconvert/pull/852) - Refactor ExecutePreprocessor [#816](https://github.com/jupyter/nbconvert/pull/816) - Update widgets CDN for ipywidgets 7 w/fallback [#792](https://github.com/jupyter/nbconvert/pull/792) - Add support for adding custom exporters to the "Download as" menu. [#759](https://github.com/jupyter/nbconvert/pull/759) - Enable ANSI underline and inverse [#696](https://github.com/jupyter/nbconvert/pull/696) - Update notebook css to 5.4.0 [#748](https://github.com/jupyter/nbconvert/pull/748) - Change default for slides to direct to the reveal cdn rather than locally [#732](https://github.com/jupyter/nbconvert/pull/732) - Use "title" instead of "name" for metadata to match the notebook format [#703](https://github.com/jupyter/nbconvert/pull/703) - Img filename metadata [#685](https://github.com/jupyter/nbconvert/pull/685) - Added MathJax compatibility definitions [#687](https://github.com/jupyter/nbconvert/pull/687) - Per cell exception [#684](https://github.com/jupyter/nbconvert/pull/684) - Simple API for in-memory templates [#674](https://github.com/jupyter/nbconvert/pull/674) [#675](https://github.com/jupyter/nbconvert/pull/675) - Set BIBINPUTS and BSTINPUTS environment variables when making PDF [#676](https://github.com/jupyter/nbconvert/pull/676) - If `nb.metadata.title` is set, default to that for notebook [#672](https://github.com/jupyter/nbconvert/pull/672) #### Deprecations - Drop support for python 3.3 [#843](https://github.com/jupyter/nbconvert/pull/843) - Default conversion method on the CLI was removed (`--to html` now required) #### Fixing Problems - Fix api break [#872](https://github.com/jupyter/nbconvert/pull/872) - Don't remove empty cells by default [#784](https://github.com/jupyter/nbconvert/pull/784) - Handle attached images in html converter [#780](https://github.com/jupyter/nbconvert/pull/780) - No need to check for the channels already running [#862](https://github.com/jupyter/nbconvert/pull/862) - Update `font-awesome` version for slides [#793](https://github.com/jupyter/nbconvert/pull/793) - Properly treat JSON data [#847](https://github.com/jupyter/nbconvert/pull/847) - Skip executing empty code cells [#739](https://github.com/jupyter/nbconvert/pull/739) - Ppdate log.warn (deprecated) to log.warning [#804](https://github.com/jupyter/nbconvert/pull/804) - Cleanup notebook.tex during PDF generation [#768](https://github.com/jupyter/nbconvert/pull/768) - Windows unicode error fixed, nosetest added to setup.py [#757](https://github.com/jupyter/nbconvert/pull/757) - Better content hiding; template & testing improvements [#734](https://github.com/jupyter/nbconvert/pull/734) - Fix Jinja syntax in custom template example. [#738](https://github.com/jupyter/nbconvert/pull/738) - Fix for an issue with empty math block [#729](https://github.com/jupyter/nbconvert/pull/729) - Add parser for Multiline math for LaTeX blocks [#716](https://github.com/jupyter/nbconvert/pull/716) [#717](https://github.com/jupyter/nbconvert/pull/717) - Use defusedxml to parse potentially untrusted XML [#708](https://github.com/jupyter/nbconvert/pull/708) - Fixes for traitlets 4.1 deprecation warnings [#695](https://github.com/jupyter/nbconvert/pull/695) #### Testing, Docs, and Builds - A couple of typos [#870](https://github.com/jupyter/nbconvert/pull/870) - Add python_requires metadata. [#871](https://github.com/jupyter/nbconvert/pull/871) - Document `--inplace` command line flag. [#839](https://github.com/jupyter/nbconvert/pull/839) - Fix minor typo in `usage.rst` [#863](https://github.com/jupyter/nbconvert/pull/863) - Add note about local `reveal_url_prefix` [#844](https://github.com/jupyter/nbconvert/pull/844) - Move `onlyif_cmds_exist` decorator to test-specific utils [#854](https://github.com/jupyter/nbconvert/pull/854) - Include LICENSE file in wheels [#827](https://github.com/jupyter/nbconvert/pull/827) - Added Ubuntu Linux Instructions [#724](https://github.com/jupyter/nbconvert/pull/724) - Check for too recent of pandoc version [#814](https://github.com/jupyter/nbconvert/pull/814) [#872](https://github.com/jupyter/nbconvert/pull/872) - Removing more nose remnants via dependencies. [#758](https://github.com/jupyter/nbconvert/pull/758) - Remove offline statement and add some clarifications in slides docs [#743](https://github.com/jupyter/nbconvert/pull/743) - Linkify PR number [#710](https://github.com/jupyter/nbconvert/pull/710) - Added shebang for python [#694](https://github.com/jupyter/nbconvert/pull/694) - Upgrade mistune dependency [#705](https://github.com/jupyter/nbconvert/pull/705) - add feature to improve docs by having links to prs [#662](https://github.com/jupyter/nbconvert/pull/662) - Update notebook CSS from version 4.3.0 to 5.1.0 [#682](https://github.com/jupyter/nbconvert/pull/682) - Explicitly exclude or include all files in Manifest. [#670](https://github.com/jupyter/nbconvert/pull/670) ## 5.3.1 [5.3.1 on Github](https://github.com/jupyter/nbconvert/milestones/5.3.1) - MANIFEST.in updated to include `LICENSE` and `scripts/` when creating sdist. [#666](https://github.com/jupyter/nbconvert/pull/666) ## 5.3 [5.3 on Github](https://github.com/jupyter/nbconvert/milestones/5.3) ### Major features #### Tag Based Element Filtering For removing individual elements from notebooks, we need a way to signal to nbconvert that the elements should be removed. With this release, we introduce the use of tags for that purpose. Tags are user-defined strings attached to cells or outputs. They are stored in cell or output metadata. For more on tags see the [nbformat docs on cell metadata](https://nbformat.readthedocs.io/en/latest/format_description.html#cell-metadata). **Usage**: 1. Apply tags to the elements that you want to remove. For removing an entire cell, the cell input, or all cell outputs apply the tag to the cell. For removing individual outputs, put the tag in the output metadata using a call like `display(your_output_element, metadata={tags=[]})`. _NB_: Use different tags depending on whether you want to remove the entire cell, the input, all outputs, or individual outputs. 2. Add the tags for removing the different kinds of elements to the following traitlets. Which kind of element you want to remove determines which traitlet you add the tags to. The following traitlets remove elements of different kinds: - `remove_cell_tags`: removes cells - `remove_input_tags`: removes inputs - `remove_all_outputs_tag`: removes all outputs - `remove_single_output_tag`: removes individual outputs ### Comprehensive notes - new: configurable `browser` in ServePostProcessor [#618](https://github.com/jupyter/nbconvert/pull/618) - new: `--clear-output` command line flag to clear output in-place [#619](https://github.com/jupyter/nbconvert/pull/619) - new: remove elements based on tags with `TagRemovePreprocessor`. [#640](https://github.com/jupyter/nbconvert/pull/640), [#643](https://github.com/jupyter/nbconvert/pull/643) - new: CellExecutionError can now be imported from `nbconvert.preprocessors` [#656](https://github.com/jupyter/nbconvert/pull/656) - new: slides now can enable scrolling and custom transitions [#600](https://github.com/jupyter/nbconvert/pull/600) - docs: Release instructions for nbviewer-deploy - docs: improved instructions for handling errors using the `ExecutePreprocessor` [#656](https://github.com/jupyter/nbconvert/pull/656) - tests: better height/width metadata testing for images in rst & html [#601](https://github.com/jupyter/nbconvert/pull/601) [#602](https://github.com/jupyter/nbconvert/pull/602) - tests: normalise base64 output data to avoid false positives [#650](https://github.com/jupyter/nbconvert/pull/650) - tests: normalise ipython traceback messages to handle old and new style [#631](https://github.com/jupyter/nbconvert/pull/631) - bug: mathjax obeys `\\(\\)` & `\\[\\]` (both nbconvert & pandoc) [#609](https://github.com/jupyter/nbconvert/pull/609) [#617](https://github.com/jupyter/nbconvert/pull/617) - bug: specify default templates using extensions [#639](https://github.com/jupyter/nbconvert/pull/639) - bug: fix pandoc version number [#638](https://github.com/jupyter/nbconvert/pull/638) - bug: require recent mistune version [#630](https://github.com/jupyter/nbconvert/pull/630) - bug: catch errors from IPython `execute_reply` and `error` messages [#642](https://github.com/jupyter/nbconvert/pull/642) - nose completely removed & dependency dropped [#595](https://github.com/jupyter/nbconvert/pull/595) [#660](https://github.com/jupyter/nbconvert/pull/660) - mathjax processing in mistune now only uses inline grammar [#611](https://github.com/jupyter/nbconvert/pull/611) - removeRegex now enabled by default on all TemplateExporters, does not remove cells with outputs [#616](https://github.com/jupyter/nbconvert/pull/616) - validate notebook after applying each preprocessor (allowing additional attributes) [#645](https://github.com/jupyter/nbconvert/pull/645) - changed COPYING.md to LICENSE for more standard licensing that GitHub knows how to read [#654](https://github.com/jupyter/nbconvert/pull/654) ## 5.2.1 [5.2 on GitHub](https://github.com/jupyter/nbconvert/milestones/5.2) ### Major features In this release (along with the usual bugfixes and documentation improvements, which are legion) we have a few new major features that have been requested for a long time: #### Global Content Filtering You now have the ability to remove input or output from code cells, markdown cells and the input and output prompts. The easiest way to access all of these is by using traitlets like TemplateExporter.exclude_input = True (or, for example HTMLExporter.exclude_markdown = True if you wanted to make it specific to HTML output). On the command line if you just want to not have input or output prompts just use --no-prompt. #### Execute notebooks from a function You can now use the executenb function to execute notebooks as though you ran the execute preprocessor on the notebooks. It returns the standard notebook and resources options. #### Remove cells based on regex pattern This removes cells based on their matching a regex pattern (by default, empty cells). This is the RegexRemovePreprocessor. #### Script exporter entrypoints for nonpython scripts Now there is an entrypoint for having an exporter specific to the type of script that is being exported. While designed for use with the IRkernel in particular (with a script exporter focused on exporting R scripts) other non-python kernels that wish to have a language specific exporter can now surface that directly. ### Comprehensive notes - new: configurable ExecutePreprocessor.startup_timeout configurable [#583](https://github.com/jupyter/nbconvert/pull/583) - new: RemoveCell preprocessor based on cell content (defaults to empty cell) [#575](https://github.com/jupyter/nbconvert/pull/575) - new: function for executing notebooks: `executenb` [#573](https://github.com/jupyter/nbconvert/pull/573) - new: global filtering to remove inputs, outputs, markdown cells (&c.), this works on all templates [#554](https://github.com/jupyter/nbconvert/pull/554) - new: script exporter entrypoint [#531](https://github.com/jupyter/nbconvert/pull/531) - new: configurable anchor link text (previously ¶) `HTMLExporter.anchor_link_text` [#522](https://github.com/jupyter/nbconvert/pull/522) - new: configurable values for slides exporter [#542](https://github.com/jupyter/nbconvert/pull/542) [#558](https://github.com/jupyter/nbconvert/pull/558) - improved releases (how-to documentation, version-number generation and checking) [#593](https://github.com/jupyter/nbconvert/pull/593) - doc improvements [#593](https://github.com/jupyter/nbconvert/pull/593) [#580](https://github.com/jupyter/nbconvert/pull/580) [#565](https://github.com/jupyter/nbconvert/pull/565) [#554](https://github.com/jupyter/nbconvert/pull/554) - language information from cell magics (for highlighting) is now included in more formats [#586](https://github.com/jupyter/nbconvert/pull/586) - mathjax upgrades and cdn fixes [#584](https://github.com/jupyter/nbconvert/pull/584) [#567](https://github.com/jupyter/nbconvert/pull/567) - better CI [#571](https://github.com/jupyter/nbconvert/pull/571) [#540](https://github.com/jupyter/nbconvert/pull/540) - better traceback behaviour when execution errs [#521](https://github.com/jupyter/nbconvert/pull/521) - deprecated nose test features removed [#519](https://github.com/jupyter/nbconvert/pull/519) - bug fixed: we now respect width and height metadata on jpeg and png mimetype outputs [#588](https://github.com/jupyter/nbconvert/pull/588) - bug fixed: now we respect the `resolve_references` filter in `report.tplx` [#577](https://github.com/jupyter/nbconvert/pull/577) - bug fixed: output metadata now is removed by ClearOutputPreprocessor [#569](https://github.com/jupyter/nbconvert/pull/569) - bug fixed: display id respected in execute preproessor [#563](https://github.com/jupyter/nbconvert/pull/563) - bug fixed: dynamic defaults for optional jupyter_client import [#559](https://github.com/jupyter/nbconvert/pull/559) - bug fixed: don't self-close non-void HTML tags [#548](https://github.com/jupyter/nbconvert/pull/548) - buf fixed: upgrade jupyter_client dependency to 4.2 [#539](https://github.com/jupyter/nbconvert/pull/539) - bug fixed: LaTeX output through md→LaTeX conversion shouldn't be touched [#535](https://github.com/jupyter/nbconvert/pull/535) - bug fixed: now we escape `<` inside math formulas when converting to html [#514](https://github.com/jupyter/nbconvert/pull/514) ### Credits This release has been larger than previous releases. In it 33 authors contributed a total of 546 commits. Many thanks to the following individuals who contributed to this release (in alphabetical order): - Adam Chainz - Andreas Mueller - Bartosz T - Benjamin Ragan-Kelley - Carol Willing - Damián Avila - Elliot Marsden - Gao, Xiang - Jaeho Shin - Jan Schulz - Jeremy Kun - Jessica B. Hamrick - John B Nelson - juhasch - Livia Barazzetti - M Pacer - Matej Urbas - Matthias Bussonnier - Matthias Geier - Maximilian Albert - Michael Scott Cuthbert - Nicholas Bollweg - Paul Gowder - Paulo Villegas - Peter Parente - Philipp A - Scott Sanderson - Srinivas Reddy Thatiparthy - Sylvain Corlay - Thomas Kluyver - Till Hoffmann - Xiang Gao - YuviPanda ## 5.1.1 [5.1.1 on GitHub](https://github.com/jupyter/nbconvert/milestones/5.1.1) - fix version numbering because of incomplete previous version number ## 5.1 [5.1 on GitHub](https://github.com/jupyter/nbconvert/milestones/5.1) - improved CSS (specifically tables, in line with notebook) [#498](https://github.com/jupyter/nbconvert/pull/498) - improve in-memory templates handling [#491](https://github.com/jupyter/nbconvert/pull/491) - test improvements [#516](https://github.com/jupyter/nbconvert/pull/516) [#509](https://github.com/jupyter/nbconvert/pull/509) [#505](https://github.com/jupyter/nbconvert/pull/505) - new configuration option: IOPub timeout [#513](https://github.com/jupyter/nbconvert/pull/513) - doc improvements [#489](https://github.com/jupyter/nbconvert/pull/489) [#500](https://github.com/jupyter/nbconvert/pull/500) [#493](https://github.com/jupyter/nbconvert/pull/493) [#506](https://github.com/jupyter/nbconvert/pull/506) - newly customizable: output prompt [#500](https://github.com/jupyter/nbconvert/pull/500) - more python2/3 compatible unicode handling [#502](https://github.com/jupyter/nbconvert/pull/502) ## 5.0 [5.0 on GitHub](https://github.com/jupyter/nbconvert/milestones/5.0) - Use `xelatex` by default for latex export, improving unicode and font support. - Use entrypoints internally to access Exporters, allowing for packages to declare custom exporters more easily. - New ASCIIDoc Exporter. - New preprocessor for sanitised html output. - New general `convert_pandoc` filter to reduce the need to hard-code lists of filters in templates. - Use pytest, nose dependency to be removed. - Refactored Exporter code to avoid ambiguity and cyclic dependencies. - Update to traitlets 4.2 API. - Fixes for Unicode errors when showing execution errors on Python 2. - Default math font matches default Palatino body text font. - General documentation improvements. For example, testing, installation, custom exporters. - Improved link handling for LaTeX output - Refactored the automatic id generation. - New kernel_manager_class configuration option for allowing systems to be set up to resolve kernels in different ways. - Kernel errors now will be logged for debugging purposes when executing notebooks. ## 4.3 [4.3 on GitHub](https://github.com/jupyter/nbconvert/milestones/4.3) - added live widget rendering for html output, nbviewer by extension ## 4.2 [4.2 on GitHub](https://github.com/jupyter/nbconvert/milestones/4.2) - `Custom Exporters` can be provided by external packages, and registered with nbconvert via setuptools entrypoints. - allow nbconvert reading from stdin with `--stdin` option (write into `notebook` basename) - Various ANSI-escape fixes and improvements - Various LaTeX/PDF export fixes - Various fixes and improvements for executing notebooks with `--execute`. ## 4.1 [4.1 on GitHub](https://github.com/jupyter/nbconvert/milestones/4.1) - setuptools fixes for entrypoints on Windows - various fixes for exporters, including slides, latex, and PDF - fixes for exceptions met during execution - include markdown outputs in markdown/html exports ## 4.0 [4.0 on GitHub](https://github.com/jupyter/nbconvert/milestones/4.0) nbconvert-7.16.4/CONTRIBUTING.md000066400000000000000000000045261461373220400160530ustar00rootroot00000000000000# Contributing We follow the [Jupyter Contribution Workflow](https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html) and the [IPython Contributing Guide](https://github.com/ipython/ipython/blob/master/CONTRIBUTING.md). ## Testing In order to test all the features of nbconvert you need to have `pandoc` and `TexLive` installed. In your environment `pip install -e '.[all]'` will be needed to be able to run all of the tests and to test all of the features. If you only want to run some of the tests run `pip install -e '.[test]'`. ## Documentation NbConvert includes a substantial amount of both user and API documentation. We use sphinx to build the API documentation. Much of the user documentation is written in Jupyter Notebooks and converted on the fly with nbsphinx. To build nbconvert's documentation you need to have `pandoc` and `TexLive` installed. If you want to build the docs you will need to install the docs dependencies in addition to the standard dependencies. You can get all of the dependencies by running `pip install -e '.[all]'` and if you want only those needed to run the docs you can access them with `pip install -e '.[docs]'`. Full build instructions can be found at [docs/README.md](docs/README.md). ## Code Styling `nbconvert` has adopted automatic code formatting so you shouldn't need to worry too much about your code style. As long as your code is valid, the pre-commit hook should take care of how it should look. `pre-commit` and its associated hooks will automatically be installed when you run `pip install -e ".[test]"` To install `pre-commit` manually, run the following: ```bash pip install pre-commit pre-commit install ``` You can invoke the pre-commit hook by hand at any time with: ```bash pre-commit run ``` which should run any autoformatting on your code and tell you about any errors it couldn't fix automatically. You may also install [black integration](https://github.com/psf/black#editor-integration) into your text editor to format code automatically. If you have already committed files before setting up the pre-commit hook with `pre-commit install`, you can fix everything up using `pre-commit run --all-files`. You need to make the fixing commit yourself after that. Some of the hooks only run on CI by default, but you can invoke them by running with the `--hook-stage manual` argument. nbconvert-7.16.4/LICENSE000066400000000000000000000030641461373220400146230ustar00rootroot00000000000000BSD 3-Clause License - Copyright (c) 2001-2015, IPython Development Team - Copyright (c) 2015-, Jupyter Development Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nbconvert-7.16.4/README.md000066400000000000000000000073751461373220400151060ustar00rootroot00000000000000# nbconvert ### Jupyter Notebook Conversion [![Build Status](https://github.com/jupyter/nbconvert/actions/workflows/tests.yml/badge.svg?query=branch%3Amain++)](https://github.com/jupyter/nbconvert/actions/workflows/tests.yml/badge.svg?query=branch%3Amain++) [![Documentation Status](https://readthedocs.org/projects/nbconvert/badge/?version=latest)](https://nbconvert.readthedocs.io/en/latest/?badge=latest) The **nbconvert** tool, `jupyter nbconvert`, converts notebooks to various other formats via [Jinja] templates. The nbconvert tool allows you to convert an `.ipynb` notebook file into various static formats including: - HTML - LaTeX - PDF - Reveal JS - Markdown (md) - ReStructured Text (rst) - executable script ## Usage From the command line, use nbconvert to convert a Jupyter notebook (_input_) to a a different format (_output_). The basic command structure is: ``` $ jupyter nbconvert --to ``` where `` is the desired output format and `` is the filename of the Jupyter notebook. ### Example: Convert a notebook to HTML Convert Jupyter notebook file, `mynotebook.ipynb`, to HTML using: ``` $ jupyter nbconvert --to html mynotebook.ipynb ``` This command creates an HTML output file named `mynotebook.html`. ## Dev Install Check if pandoc is installed (`pandoc --version`); if needed, install: ``` sudo apt-get install pandoc ``` Or ``` brew install pandoc ``` Install nbconvert for development using: ``` git clone https://github.com/jupyter/nbconvert.git cd nbconvert pip install -e . ``` Running the tests after a dev install above: ``` pip install nbconvert[test] py.test --pyargs nbconvert ``` ## Documentation - [Documentation for Jupyter nbconvert](https://nbconvert.readthedocs.io/en/latest/) - [nbconvert examples on GitHub](https://github.com/jupyter/nbconvert-examples) - [Documentation for Project Jupyter](https://jupyter.readthedocs.io/en/latest/index.html) ## Technical Support - [Issues and Bug Reports](https://github.com/jupyter/nbconvert/issues): A place to report bugs or regressions found for nbconvert - [Community Technical Support and Discussion - Discourse](https://discourse.jupyter.org/): A place for installation, configuration, and troubleshooting assistannce by the Jupyter community. As a non-profit project and maintainers who are primarily volunteers, we encourage you to ask questions and share your knowledge on Discourse. ## Jupyter Resources - [Jupyter mailing list](https://groups.google.com/forum/#!forum/jupyter) - [Project Jupyter website](https://jupyter.org) ## About the Jupyter Development Team The Jupyter Development Team is the set of all contributors to the Jupyter project. This includes all of the Jupyter subprojects. The core team that coordinates development on GitHub can be found here: https://github.com/jupyter/. ## Our Copyright Policy Jupyter uses a shared copyright model. Each contributor maintains copyright over their contributions to Jupyter. But, it is important to note that these contributions are typically only changes to the repositories. Thus, the Jupyter source code, in its entirety is not the copyright of any single person or institution. Instead, it is the collective copyright of the entire Jupyter Development Team. If individual contributors want to maintain a record of what changes/contributions they have specific copyright on, they should indicate their copyright in the commit message of the change, when they commit the change to one of the Jupyter repositories. With this in mind, the following banner should be used in any source code file to indicate the copyright and license terms: ``` # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. ``` [jinja]: http://jinja.pocoo.org/ nbconvert-7.16.4/RELEASE.md000066400000000000000000000031201461373220400152110ustar00rootroot00000000000000# Making an NBConvert Release ## Using `jupyter_releaser` The recommended way to make a release is to use [`jupyter_releaser`](https://github.com/jupyter-server/jupyter_releaser) from this repository. - Run the ["Step 1: Prep Release"](https://github.com/jupyter/nbconvert/actions/workflows/prep-release.yml) workflow with the appropriate inputs. - You can usually use the following values for the workflow: - branch : 'main' when releasing from the main branch - "Post Version Specifier" empty unless you do a beta or rc release - keep `since_last_stable` unchecked - "Use PRs with activity since this date or git reference" - Review the changelog in the [draft GitHub release](https://github.com/jupyter/nbconvert/releases) created in Step 1. - You will need the URL to the created draft release in the form `https://github.com/jupyter/nbconvert/releases/tag/-` for next step. - Run the ["Step 2: Publish Release"](https://github.com/jupyter/nbconvert/actions/workflows/publish-release.yml) workflow to finalize the release. ## Manual Release To create a manual release, perform the following steps: ### Set up ```bash pip install pipx git pull origin $(git branch --show-current) git clean -dffx ``` ### Update the version and apply the tag ```bash echo "Enter new version" read new_version pipx run hatch version ${new_version} git tag -a ${new_version} -m "Release ${new_version}" ``` ### Build the artifacts ```bash rm -rf dist pipx run build . ``` ### Publish the artifacts to pypi ```bash pipx run twine check dist/* pipx run twine upload dist/* ``` nbconvert-7.16.4/check_requirements.py000066400000000000000000000013321461373220400200440ustar00rootroot00000000000000"""Verify that the "all" reqs are in sync.""" import sys from tomli import load with open("pyproject.toml", "rb") as fid: data = load(fid) all_reqs = data["project"]["optional-dependencies"]["all"] remaining_all = all_reqs.copy() errors = [] for key, reqs in data["project"]["optional-dependencies"].items(): if key == "all": continue for req in reqs: if req not in all_reqs: errors.append(req) elif req in remaining_all: remaining_all.remove(req) if errors: print('Missing deps in "all" reqs:') print(list(errors)) if remaining_all: print('Reqs in "all" but nowhere else:') print(list(remaining_all)) if errors or remaining_all: sys.exit(1) nbconvert-7.16.4/docs/000077500000000000000000000000001461373220400145435ustar00rootroot00000000000000nbconvert-7.16.4/docs/Makefile000066400000000000000000000164441461373220400162140ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* rm source/config_options.rst html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/nbconvert.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/nbconvert.qhc" applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/nbconvert" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/nbconvert" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." nbconvert-7.16.4/docs/README.md000066400000000000000000000027421461373220400160270ustar00rootroot00000000000000# Documenting nbconvert [Documentation for `nbconvert`](https://nbconvert.readthedocs.io/en/latest/) is hosted on ReadTheDocs. ## Build Documentation locally 1. Change directory to documentation root: ``` $ cd docs ``` 1. Create conda env (and install relevant dependencies): ``` $ conda env create -f environment.yml ``` 1. Activate the newly built conda environment `nbconvert_docs` ``` $ source activate nbconvert_docs ``` 1. Create an editable install for nbconvert with doc dependencies using ``` $ pip install -e '..[docs]' ``` or if you want, `cd ..` and `pip install . -e`. But then you will need to `cd docs` before continuing to the next step. 1. Build documentation using Makefile for Linux and OS X: ``` $ make html ``` or on Windows: ``` $ make.bat html ``` 1. Display the documentation locally by navigating to `build/html/index.html` in your browser: Or alternatively you may run a local server to display the docs. In Python 3: ``` $ python -m http.server 8000 ``` In your browser, go to `http://localhost:8000`. ## Developing Documentation ### Helpful files and directories - `conf.py` - Sphinx build configuration file - `source` directory - source for documentation - `source/api` directory - source files for generated API documentation - `autogen_config.py` - Generates configuration of ipynb source files to rst - `index.rst` - Main landing page of the Sphinx documentation nbconvert-7.16.4/docs/api_examples/000077500000000000000000000000001461373220400172125ustar00rootroot00000000000000nbconvert-7.16.4/docs/api_examples/template_path/000077500000000000000000000000001461373220400220415ustar00rootroot00000000000000nbconvert-7.16.4/docs/api_examples/template_path/make_html.py000066400000000000000000000013441461373220400243560ustar00rootroot00000000000000""" this script builds html files with either classic or classic_clone templates Note: nbconvert 6.0 changed ``template_path`` to ``template_paths`` """ import nbformat from traitlets.config import Config from nbconvert import HTMLExporter nbfile = "quiz_notebook.ipynb" the_ipynb = nbformat.read(nbfile, as_version=4) c = Config() c.TemplateExporter.template_paths = [".", "./project_templates"] for template in ["classic", "classic_clone"]: c.HTMLExporter.template_name = template html_exporter = HTMLExporter(config=c) (body, resources) = html_exporter.from_notebook_node(the_ipynb) with open(f"{template}.html", "w") as outfile: outfile.write(body) print(f"\n{'*'*20}\n{template} succeeds\n{'*'*20}\n") nbconvert-7.16.4/docs/api_examples/template_path/media/000077500000000000000000000000001461373220400231205ustar00rootroot00000000000000nbconvert-7.16.4/docs/api_examples/template_path/media/image1.png000066400000000000000000001077351461373220400250060ustar00rootroot00000000000000PNG  IHDR B6 iCCPICC ProfilexTSiǿ^z%D:7A: FH B ؕQTDE X dP }vv|ws}}9}H +&y2cbx)-p3E!!AW}Fm>R%drBPerP>ZW$A Mr)t1Z &??wbCP@p|Q?3GP([ y!(r8'P6<䌗p2~)TΪs;R%3E$EWg5)2/ ao*~$3a;p%)3+bϰ8=T_0H?-LNg8') 0AF; 5gxV,5 Lk1imiedNO xrX_Cdڠ턝. \8{ڇt 0h}`b2I lylA8pM\W G@ K0 >qA6dA r| ( >$$h3TCe!: ]A=B_`tX6,0΀s\x\ WF| K2@tsx!H,uH>RT"H ҉F+3as3b2002L s sӏ|RX3+yl 2.v1pF8?.[+5q=Wś]x> ߋ???m5K6JG m^a@4 :<*bx8H')H.pR2i#TOLzLzG&uɎEdy||OLQR(K(6J5JRݩ,6j-")MB-Ǔ[/W.(+Z(o !L>GD-W DC/:r } c4E+`4BţJJ>J<\JhME6ӎ.8MOЏӻJʶʑ+˕)KÐf2'_h0g9s>$4UTQMQݡڤD fHm~j\|5` SP5njijii4j^|rJڥզ5Mvh>`2K:::C:]:FttXzz:Fѯh@4`$14hhdeŰpHňmcTgؘjfa\i|g2I1gm ڙ&2fzb:έgN1063`XYlhx=O^:}L<J>>e>O}u}u~v~;ؚl.=6R %0,,Yi8e `,.l OBB2B~][|P5aaG>{?0DtDG.U%6FZ 9[;gŃK-hʥז-K]vnrSqظq_9JX<;"~}s$$' %$'];#InI%I^2dSSS&RRiqigJt="3QHᔱ;cT(ʄ2f6gaX?5<ӊV*tUC99?ƬXfkůX>w 5IS6rS6jn<WFjm8s~]@G/޹RW^ykN^g]oa3v˾ín=mnn{߾r}݅w{Eܻ߷OzwA7?8“O+7Aj/=YسG܁du09yɐPpH/_^*^>7GG߈L-|>3s痨/C+⿖~3=㉴ G̙DV@ InzF4=OO<=GO \h  (k;mlde&XO"7I;t6ěobbib[ZC?LR@76`帛IDATxwx?'л `AT@;vk՟]^{^{.(JUzo 3?6@d>sr;#R Fhc[W@h4;>Zl4Fhh4MFh4MF49Zl4FXۺB[6kIE7FƦo{Qs_TPW9(0 ^uhh45BJ$BXllEiZl4MR3fPYY#H$H&nݚݻM55_˚ۄuF͝;,kU [~J)̙CǎبL:۶0`J)LdŊaFc:OѳgZD駟(--e]vo߾,SZH5rrUWq2rH.R*y晴읧zB~5wuv￟O?{wr<̛7/]ʯy^)%Ǐgsu/*++3f SN0 LgX־5y.qPJr衇H$9a駟N9묳(+[j(f+H$jҤI}jѢEʶmL&U,SJ)UUUI{ҥ]UDB)TIIU~UU7om[)e+TiiirU^^>nL͝;WCM8QUVV~W^y%]jɒ%u]RRt+VPmaÆ_~E)T2OW\qSHD}gjSB庮R*#x~?~gu~Yfꫯ//RPP@0{sΌ7/^̟ɵ^g'|-BFFp~N:q'ӭ[7;Zń;˹k9묳{kXp!/O>,^{wc2}t.ҴfȐ!̞=8:ubŊiaƕW^ȑ#q]4G#  0`&LHG>p8΋/H"`ԨQ~oߞ1cpUW/SVVSO=ѣ뮻c=بNiR5/I*2+98R~MuY-[,}.]>X͝;W-YDvajܹJ)F.2RݺuSƍSGU PJ)5du 7(z衇߯T~~Ւ%KԐ!CT߾}… ?RVs*++S첋_TUU:tz7mjwW?RJ_~Y 0@b15vXEYF0 5{l%TZpaڕRj„ P/BSjѢEJ)ѨPWVoVnP޽{{Wjɒ%3TB|r8տ/kzx5;.zdS3K2k~?=+]Uvki3f`>[eSQ\r%t Gy_ŋhѢt￰SXXȨQ{mC9^z+Wr1ppB:vȹK6me]С:ub;  GVVeѾ}{fϞͬYXd ~;D ߳j*~a9{!8c׻GAQQBi7pWK/!n /7ߤ9sL&Bжm[̛7/ S7xG}x}1Ms4͡y[ԏo<_5݋O&{-qGy$p]wq%Haض>@2=zctޝ|:w޽;{&33g}0/>o5N(XbEQpg3n8>~)S0n8FA׮]kPJdڵkDZK9ӹ뮻8ꨣX|VP|F-EMxb|A;0Fv:N=zPPP>"L2rZ3g2a.[Ɯ9sҽmum)€[n͠AxGYѦMZ֭[رcԩ|0g}6GdΜ9tx8938䓹{kͥ ONNNy5`Cr#dtM!x9K8 Bw}{s1< ><}MǏ租~u}m۶|7wNNN96`vZ\?x:(Jv7nB+zMv(((>`ocرdddp5א؏r&FI=B͜SJ&ʶt/^}*\xzR* [a{xZ۷5nS˗/W3nJ) MӎzZlF:{R^g}VXQyRsǩuV\.$>]VVzJV_T&M"]]{M6*u\_ZZ233,0 ݛAy#!={6kҳםM*ݚԜ`Omu´S۴iCaa!Y!z> @mے~&CCV;4k2Zn>GV|H)c}w_4͠A# ERફ²,|ɴ90*77VZ.RJx:v\iLe;v8}׬%WE6@n X'fhbauW-\ȸO_&M ! [nmڴiJoRT@CH5l 0Xt)v13O疛ofԩF*ݻ7?sT֚ꙺBcj&\j@K)) g2ר&,+}\l+w}I G'|^j_m j7Qs O˯`6@HhI8.R/^߮QAc֛o/?`ƨG}?ujTfϞgIn88.\YjozwܙK{ۺ-}u7u_>klW>y+Koj`ظRݻ뮻wԭcǎu2ki8—|1}1'bX5FFA(/駟SOe\wL2֏LqLNmSQQOyy9htǹKӧ'tRdN̙3),,L JD,c g=|SHϲ RhRhQr Wpna6$#J$ͦEr$ aУGzqρ_/_'Ofӣ ۶ VGNm ~'L"rc9ZR?fnK ɓCj'D.mouhH)~'wOt\r!4wslꢱy3R8Jqq|R)PԊ}=ǵW]hbj,Y¤I8CkMB0xڷkG0Hc>XJmݸuLj pWҾCw゙ %>n#77wx4i'r(/rpgvq>yW,sRqܱ kl.ǵ-䶻n=b}lM5J9N4'ΙòK|豔v֬Ydee1dv\HtR״olmY&f.Ѷ]tYYY8Cvcn$Tmxx JOyw.M88q}{r;,+)#Y-_#nڴq)#E097.ffh_I-5?͉?U>>J^|y}xtԉkG1p >z/ ~VsεcOw~3g7`E0Ç7 !@)N>.Z7Ce,]^^w}t֭҅[ך3{,oFR a"1f~JHL!PJJ-_Nd82m]eMIY1yt؆M]1mF-b~#8S94)9s&})| -OgϞ;my63{lvm7/^NEEYYӧLϑH+9c^˗B$ b(o߾ɯu]~7***ͥ{7ߐî+Vp9ȣҮ]m\ F?fs#6FqŸ//2vԈ>fːa,[o?2F\~I_#=:I8iQ巘<.{͝{>caEA GmŒ>(Mj3駟h]\L75'S_QkHN#)%]u#dŊ¦'`8@F޶Fa͙x5TC{zFi +WW`:ics%%oe6՘OR$ "pMdmsAǫYB*kѢE|3a&B.]taذaP>&E*0>B77s҈$ JR/Ɵ}&,͌t2.:p.$?+Dҕ@ۥ+"Ӳo,yҥ̝3??cTVUm 8^Mh뺞Cp JyEu8`m*؆2ˊLu5 gdTlnuFm:!ͶG)t]eqUWrЖ*m틙Ϋ<ƟyM֪TTT0x鼮9c]Rۺu矿uJ5J)| s~Z:OCr|.Զ@Ji|vNL%ɈI.nd&|=cF 2)??O9C$LhR@#9U\w%:h2(**ZH%LW ègQ3 `ϳ֫RY`ۇsom !g9WQ2(מfߪfAOY|zPM6Z*sf{z1}CY*6)1mI'2`󁵑\B*+*+1N:x7BmșgQsPq6i׬1HD:ߒ?'! XIޝ | Mŀ]vҽmLw]rd0h6D yj:4HXVZ9kE988p ?c)k$ٺ@msd6~#8b(AMlRfΜʕ+Yt)'N_~$_={cƌ`=[n/& 9̤N;5FU4է% w^տБEq^na>囔V\L즫fjy/Y\ӱrg-EQdYy:mFk֬?[uQgJgmR*++Y`FD)oYA\Co{DNj%%#>l|>{;5{=H6wmnx Wo&*6! @0g~ ѓNafvb>Qi7fCx{b;/ . @`Y)PJKٓǍc졇nsE,!1$38⋜tI[vrMI;tO#vBmS<q"RjZՓ*û^usk`i aaoNk a&W\qSN%pifR%zpEӦ-qC*Yusk3( Oɮ#%Mujښگ)O{]ә% "(=-fUi|0> Ƕ7뼚#6c6oelNݢѭ!0辝1?Σ_n=ߑIYS‰]t0?D#ϩ/sz1lDq-w+0QTF-TDDz6|]ĉ edзo_bh1'nˏjɘ oQ{ٶ\͆Iʐӫ6^8v|A^}]LlA#YlA9#`JJhV0}tw2N*yYi9%a^pΖKcsٷ {5U1 .$R?J#ڷ̮{y筍" .cf|tWz+ /m!L[ԚGgeOJ\pj|41Tm_f%[n Rh\ 3q,AW!DX0(唪U}e4MMˎʤF5&M"''ޤU4|joo{ ?uR"6rcmX! [#[ǒZ)BI$ri=m+79B9 jخ˪zuFh0_yznBIhA-6[T#H$裏0M "±m.]8?aذa(4K7_2y|uL~ >cpzW)L?|qjDU/ty}vRܚ-'ܩOfq׃Qz fN!WЊ6Rb1cNtԩl:u̠AQZxblDM3M,'{qؘ\SM}H-ARkW,0XAd,CT݄hZ7R#)%9s%!cҷom[@*޺ض2gSP^YLKbFnMf4 |>geZ>-M9҂b HRtܙI'8D"Zjk2B9.i+`_*ZF6DA޽ݻF4)Zl1%jEhh$F-Fh-6Firh4bh4&A;ZҺޞ4 ~hHAXmfG MMk喘b{Dz, ԙz;dGdszezY5-X,֔uV \!XH$Ң^II{Cj4͋3R0JIc~Tc9ydF-kjYd [8,v\;d.ЇqJ2̿uNC~^'sW^éWyMs@dbo@JE0dehK@K4a]woMwץ]0u Í.6[`ZQ@atviobG6X 'Н!Rk4Xp4ܛ҄h4-6㠔q-ܺDaf6xQiٞ~tBlڦ:5Հg\ !PRjN7)M(++~]v{5aH > Ν>OV^.#z#?`PRD~ΝEʌJI&3'B"VF؀3l4wL,6lu3Lf3z-8dde3∣ ]R~d)~oRСCbbH.]xGRuqg1wtݥXoU) ]L0G#::=ioքpw]} X_'0x@lxևRLW>F}lRS;ճgk&EcR );_yJJWd:R)IcTX^5۔Nb::6pe;B K84p6c()){n-U!|R>/=r2- ñVga6<ӻBvUݬiV?of;{ƛ4^fv|-J[kj6.k4bh4&GFh-6Firh4bh4&GFh-6Firh4bh4&GFh-6Firh4bh4&GFh-6Firh4bh4&GFhXFa`&&ibBB]Fh4u"$cQb5$+ Ƒ %2Vhh6fIE}'# u\´,*]:+=h6MA)(?* IB2Su)( )MP0Mp㐈JRIMKNIӢb١P]JU eavܵ)!(O4 O(\I Di!hl(PJ0χey ($ekZSJUj"(h7Z AEVbD%*de'PER;a` a_`r\,@d`2$;"rcY $Ɍzuul)ahlhlW()Q0|& @"KcS^VFy̤j$*א%SNSBIB~쐟Ev2 3[!00HP )IWOJ$fmEj\PMI**@92[FV2r ؓ̎kە܂| )h$;N\G"Hg-h/h5)? kd!@b ǠdJL'R?),W. Zw}}Ÿ j >UިifGyF460l!k$& mWKl i&L*`G,bIYF&zQ3їvPغ jQMTGbi(%'0L?J''ʈP $/7 y )z#U(E)gFH75oQSi!Z.#T$fLAv!t7CyKOJe$fڋ!""̝#nt݇=.$L&1L!G}%RfȪ$*؎tg)\1/ 0, S c+֬o {dMQQxlh4-6mCr},[g_7'ΦS0 $"nZX`@ZX7G'5M ?Ey6 N⣏z?T>ڴ$\xSztfFՑK(G҅w{U؜w]$.!cq\ݺ+`|VZ']˻_>MC/〣:-Q5i*uǬXq]0ڳ-UpG-ra(%a~ lۀ+I}\y|1èh>!NDywßj!Ѥd80+3aBhiZl4MPŴPyqËZTգ,kʤ&f2,>YqNךKr|`~I_Yės`ܐ=>S4X,C6/G]ӽGǭOj>Um0-*=?c ^V}9 #PUZSM"~zA5ǎ$o@* -0 W Nݻ5Q,WX$)ɲp3cYQ)Lܸn!3 ,אDPaW*$3+WR ȤDJvZ AI YI-UP4VD.G>>ib{Tve<42iÝG#T\b~XA8i2__\œUql gQȹtRL.# }~+i*C b~]³?A8g׍i/x5JH ~i%YM%2,̘G=B #ġg_JAq1GP ÄU%L FՅ!V3֎:7L_O,~[=uȠ(_˘k?f/q[K8kXW*W`'>=]2By;>1/ӍeIyd.ûgHŽ_󺓗mqܣsCrKqٹS&?1ϻy~5xA W(OVpOWrt\f2$#7)(*0I % M_vfMKa$$h`:dy?ԭW7> &iu0h^;zת54y{HxڋɾGJQf1birDP`HM~fSXߌJvCUBr^scwYUblWq+ؿg6۝%`FOؙy~)3*٣k&;r63@a)m3;/fWQv(|4W*uⰡ`exO\Iɐ!MzCTR2{}fSļiRj(g֔ } ze/> G(!#II"J$(iL21M ӲeS?m:"7CV~]/j*wBR{*w#kKfN&麒<<8SV:(4O|j^;#$ Q)eZ4Qve\qh;L!5B EORS,~'}SCJUz L^eP:ٲށy0Ʋ)jneC2?)]܄JIkP"0 !axf7U$!0jOub~/\,͟ _Qc u6ፘLV-)Ͻ30O?lCh4B@2Ե#zf|rrQ|A_xᴮ[HE}9d{; Vࣙ\0'8wJt~*K c/Psq#0Ѥ;S*8{D1eI][/+\9e6g¦mo^NYSPq'$] @u?ߖ0kUIvIr7>Y_^[TWL~5WإM)R `*=sw/5PL?}v20 7?G,Ŀ^B̷u]}ع3,IŬ_gӨ\]BF)on%%]F~bT`?;KWE=5p(ɸKa۶wj>a@FvN{c$R}$PJ4+|>ova ]Y@I8C|?# HTXhSTXA&Qe1c5IGQXgPO,U7g:ҵ0 4΍,c#.MqӞ[ 'v %SrmsL^簤"ɘ9 Iv|gAi ^`t}t.=[XXf6>xEiόv0琰٣k&9!9,众K ӊGh*dAoMT&J)u"ޜ #xf8v|"WOlN$Z2|P=FmK2|^m@זC`'%>wsʶ3Orl8so[eC?};dd ~ o?r?~&^2[SZ̘8gogcF &燙_W|?q:HJ), ^6V. y=HNa.Ox) B*_ ~p]}85+S?7V-gɼtۗdm]Oݓ)O{nг.f}G:DZo:^nh L/a9 =Gfc OvJ MMT;!&&!qv&`ّ۫'s"R+JZ Wn-;.TI|Ũ Ǯ]V;;)^yPw9›5Ou4iWcQQje~I8ɮ}.[ F)B(L7\g?|lpĢddf 2u~2rH,K飷B`}y=ݳ?mp%2h*_& @@~qE%\ko<vLߔ}]1?.K./tx2]3dD5zd* t,.ze^\:`!)I$. YJZur Y6=O}('~?9g%)I$&HJIFɏ}Ϊ% (l1cL~}twQ tݙ?c b ` sqe{PgrKXjEH5]A.ϢwϘ6'\v͇.;νO.CVw?^ …²sĴ[;ژ`ǽ|ma^r2*n:ha8 !$^qܟa3A9Ƀ$ض;ߖV(I܇!Wt=WwsEu?|zR 0I&&|iݱ͡g_c'bU9GkJy|c`|I0fqv:wYŔub*D%J n0Չ`% y߿=I&ߌ% H"Q٠jMVETO>*4?i'H LiHjB*(x4A,YR|G?:=*l lRJAK- :F0 KV2/s$b03ʅeKSDxKyHt)$9ʫVkG7B ]+jCFV6p5T.!u+cyu.^W'?>9Os/c1c)$#3 ut73\9\ a?5F#\ 0 aI?-6m0M"al6#X=~.#;IAde&2ac[ OJ`C~( \l13wOz2?<*pR58זô¢dBڰ ''*|S!K:@ '+Xysyϟ™SU%}PpIna. b_Gew Gd=a Y2{&i͸alĦBfc&R)o!/a2l7JJewq}rn'WlQ?;:4L:kkSCNm!0 /WYW|`ٞH#x^kZcѰCUl힭.~OKo:p֬rU.+M:CvA+*JWQ o\G9 $Z%9윋8UOׁxx}aD+]93n;g_گ^#afs֍gggjs9!QU:I&b<5z}h )'fA~Fuᇰ|,'/s1'y:H>:| izv&W"]=JjFmlJHRZX3  vH2oE+)M̒]ڏa;Ѧ8˄X"Ve&n PD*qi{Wkbj',(nq_ܩAFfzhF줋g:3k}eÉ]A{o|<v`y鄲ģ.ewqtݟ_}PUVPض{9V)~GLR/jNq썇Go#y-6fGJEe:?{dyKX`̟k#9um}zW%#NQnE9A,A:* Qչjkp Q=I^ȖT$b*MPR"XYf,F`ݗtaDdM z&0EΞ Drtk7B$c/6; *^c\R3! ޛM"v3gLXG HD:wށkCddXě(8[H%hSm4-6fM d.I["Ctց:H<'aB?O|RZeZ]f$)ALA}&ey"XI.)Ak'8w+?.vHn&tXQ J"Iw׽6ҩGwDFWd1hu0DuqqiD]dM!e]4 C`xD0 [1j\ÏmH jDԉd{Q1Yd2ʂ`[.NtqETvd ƒP#"B EwǮ;{#_`MT?{ltVXUMk!Kovޭ7(vӭhlԜW D oҠA4ϤMa&kk+ޠE,%I&$d89c&mw '?d5+(iBBdBdd @ _U=$D+ZQ6 PoMVǼIb%iB@2搈JoTIbaXw_@.\p/˳u{aLLLYQW[R! N>Fw=/ =뚪@kĎ8$Rj}uGEktD)bv4@g{ݮ͎HZuA+p¦k.:.9A|:?t$/ɯK λAxHDj^/ ѬE)M\I}i&3<{fHG6(CiUIґSykZ FӢ$3Ǽ+3gM~nNashZ$_'\s/\+XihѴX&ü}i &heCuAxѧ-WbhZ"Zl4->Kp^l8ړ$ qn(z4'7{WkJѴ\hZJ)Pg3_.$k'mn)@J2b?gr}zFP.OFyB2hBBo0cryL6l=GbiQH!'K>CsN$Mdap(,*q,^PB'MA:.~C?ǶNI[a@2{{_}8~i9hѴ\!7HSraEBlхiuֿ"i98t%ٹ~:iCr2e$ޫ ǩy,=S"b١R Y,\Oo=ORh.撚y]iA2OM @fEJIoPVѵCض;pA?xWCO͎R  Bl3ے '=Ĺ@pmm|>~3O͎͎s_37]8g]<1u<|IJV,}l~=SòC 74:q%-yq)};Sh.^U=?{1+;σ (ڸj<~f~ x灛8o7;hf{g0 U6w{]soȅdMqp#Gᾬ|+#L MCQJa V-+SFpFkkb ثWr,eT^`XfWhY %U[=y55'^|UlPb`& O?/=}lܜ5Q |>+ys۵8 g8;Y̷ztα뉌 N "jr7.Ozl?8N@ Ӡ]ģ \^^f3u #½=qVD*x }x=B([fԉGc(z>jB~BěCV9hٴ$JlbcMAݙ<ƍ\pZOT4Y ŕ/4x=b6l!Bcn:H姪:KY M aQf`}=sádlC\UK߷ MMOl!imDz4z&K >$D̛$GJ࿯Q7ѮS F١[90VӲ_3o-!7,:G"\nobHx'N}ީhs+TqCFf53 2 Q@) G~`h*BY4+aɷe$;022(**5j)6)6RJ `ɒ%<(J*~;!n(-)%!p8DB#l5fE3*I'J:ŵ uaYi6b̰(0L %o ʧs TE]n0`˖-kʁ8y뭷xᾫֱX,٤JInv NʚrιLM7ˈ{1񭫉D:̹YJIan&| >4!6m[ד:@H\=?m+7 ]E+5h4uiUyw}wv4H egiQ*UT4Z\ڶ.$M`lߤA(:p<~VJߞDni/dEI?K<rBzNM3u$ Fll3UZlҦ0 dBaP\T@R\Gf(@qqqAfƴiF6)\vH&mnZJEV(o<]WVwRAf]/g.5aLt@u%ݨsj$mŦ9Ḯ7%~r;ǻt{L}֍56ڹn4f/]Qݾ50MA8`]4uy.8kʓe.X|2"^ +#X:vx֞Ni gZ4Vw1MHm譼i4ƛ =NjәFѬH AIoTm)^Yƈ=Fӥ}}h4Ŧ#9K<2r:Zr| ±^;Uh4:-:Ae8ʩoidj 0r1cmzh4[-6uJEopy*lǩ;."#(x; :'Lh6:0 Ϝ6_:w؛g^J^ʞR*| *#8)a$FAt LӠ"G2eVk~^Bf4 VFx38$IҪh4@FR08aQP45bٮPʛmY&>Db4pT}wI؍k~9!24tB h1s]w>C7Z 2{cPU/5rbnRL2b٪$mP0@nv&Y$!L:Z;Jº2p\Yki,ӂM,)w Orn4:1]Rg鬾wZ[΀>=xӦ2\~|tN9|Ɵt0*1 4⺛6),Vs_fRVa;|4ںAe$^}z0yW߮2l\G=і\Zl4)L<!+y1rZ]i\WҮu!/$HKVұ]dKv[Y=0n=>f2?h9кU>B)O4 !8Ѵ.v9|kA?ٸ2Mި&JX+Jy&Ǜ|4ky:}?[ZZ{/:S`”]Ge# //G3|מUVi:h4[M~{ucRV2t HnW;+#Ql0&,+PFWwcL}u$F똃!/' :TPVR)ũ{+u RJLﳰ,L: iӏ:P0R z^ONfܬ`ԅ#%]pOp76e;1A!dFYvM'%h6Mѹ-5f/2L#a'),JEV(I%(ccNC~6ʴf;+ܡV9u: CV{C-%?iE~<29BP Χf\e85e;|MaUwdI#sIQ6B8O*2A?U$f A" k.<;8KyOy= *?W>_4 \= p1iLSl0I69z0*5(h[TE˩G 39o1Z/n9ncxL*U).* 7'%%h>xvo-2u 3YUA lph/ V5ٷ:FӬO`̜!Ͻ9/yلc#УS;*Ŷ7>ޕ%};}]IH$mD B`;m9C]O/ϛ|+%*dUGnLH6+ϟI^v%k)]m`WdO4BCl?Db.U7W[gmf.+bi!m¼lǥ|ݯ8}G3<#Ͽuk-u%wPeSp$H)4 Q5 qy(-dUz.g# 2Gғ8s`u|حMcѵCzuoβUkx١c ӏKi 7ƧF^t[Q^cfh4{ i]ǿn~Ώd(hۺz1rBpu ӣFeaϑ %fuBmN;bߋ?/aàsމkRO;"-Pw"\| v8?LȜKw'VOSeH&m-6 4 "1>v4Ϙ/k~6{@e²y Wh kF5UXeq)3|0aű /ܘpս#n0 bdJQO$k7 A,g-qGL$NS7gh4՘ K0xNTp ( -EF0X1{'i;DQbh4`p4fbh4u}75Fhh4MFh4MF49Zl4Fhh4MFh4MF49Zl4Fhh4MFh4M΍٦(Rz"<\w1M"SK+ {*֧McFMPJ"H%(ީh| @W(wqGR\G^+8BRr\~ьأ?hR*BA>0~;B,4 ۙDqⶇ_b疋W0q*>H%^ƲUT O҆[Ƕ\:Hڶ.Ib٪R껟gɨa Gh$._f-*U)»//s.dĞ8b=9ow1j@k+4m6?\rBLOKEe0JDbqf.D>q !^U4&Af,Uk*׹̣z ZSi +U?:aBAЋByUl3eҕX]_N;[.>5bȮ= q=OqAMF0enXix#P(ȁ{c}JnDd|4Mulؑ{ruY OFq5~=Y.5z X^?f/d\I[,YQB֭N?@n=p<•Π-)% oeƪp؋av{DҦ2!lj |tktˍ;OMN9|B|de) sGO$x/xp]p"XE#(Y] cbdEi4&$ʒ2~';%3+MG6R etj,$?7,/#Hbs0=.~8W*J*}+J˪6 7^t2N <וB`ǥmQR*֔qM(Y]LG2b0 NLn4i\s tj[DYEP(HFG&2yƜ@x"ɇOLUw>C0o r2~xmMcFxf!#eҥ}1!>{!O Ww|ځл{Gv٩3: w:n Y!I{b* 2uF*o:X"ANGq_a!9< C@zA~2 ˴\|˿h9,cʟmWF8tP^xsVsa#G=x"LόK$ӣv&+3~=fTKh-6D2N]S^aᲕ)* 7;O;|myJ:}=2_?_ݷ{wup?3;?p &RTmP)*EHM< UU)IԪU ڪUJTmB?*F P^{g}e!֦p~Ҿwά=;h>ӿc ~njxKGʬA{<׋1FcQL@Ì1F]"^nTU^i5lΣ1A$޿qnq2mX`7}]l+$RĢa=]õ?1<"9(xFX/fx*u(/yN{xyl.\4ã`s+F679p`+ ^۱۲pmɶKĸs8>0Ȃv8q<]sZijW ۶)x>GO~Dzwa[6s|p!a\˶#ad*Ϳ0K{;{|4Xn}-.]s ˻T2pY2`PI<.â9 ^P,/,O2E݄Z[ݤ9>Gg{ m-MŝnF~>ymy(pgJAZBM"J9|x4R؎G# |_;b˲HĢx_Wc 2 lx,R|V0T"< :~CP4E< G4)+ic烒*h>dY %7*BphZ!Bs0nșT:S9KN6F¶-֌i˲-t1bg9~'d*]q\kM^%]eYJMlM*j"&e2|q&3L 6vgr⦛A!͗ӓ9ō=t"S'~BlJ #_{I4PJ2%* uWQs^P|\wOƭR['+ߟ wLiA2ф6|Ŭ-8ôqp] QZS_gq]wZaڃ?ݧ"ܸ9ǩ0mh(۷~Pd(XRkvӷ+-OWBq4RjB BS^.#!5'q !9 6B!jNB`#$!9 6B!jpK-%iIENDB`nbconvert-7.16.4/docs/api_examples/template_path/media/image2.png000066400000000000000000005303771461373220400250110ustar00rootroot00000000000000PNG  IHDRXmd iCCPICC ProfilexTSiǿ^z%D:7A: FH B ؕQTDE X dP }vv|ws}}9}H +&y2cbx)-p3E!!AW}Fm>R%drBPerP>ZW$A Mr)t1Z &??wbCP@p|Q?3GP([ y!(r8'P6<䌗p2~)TΪs;R%3E$EWg5)2/ ao*~$3a;p%)3+bϰ8=T_0H?-LNg8') 0AF; 5gxV,5 Lk1imiedNO xrX_Cdڠ턝. \8{ڇt 0h}`b2I lylA8pM\W G@ K0 >qA6dA r| ( >$$h3TCe!: ]A=B_`tX6,0΀s\x\ WF| K2@tsx!H,uH>RT"H ҉F+3as3b2002L s sӏ|RX3+yl 2.v1pF8?.[+5q=Wś]x> ߋ???m5K6JG m^a@4 :<*bx8H')H.pR2i#TOLzLzG&uɎEdy||OLQR(K(6J5JRݩ,6j-")MB-Ǔ[/W.(+Z(o !L>GD-W DC/:r } c4E+`4BţJJ>J<\JhME6ӎ.8MOЏӻJʶʑ+˕)KÐf2'_h0g9s>$4UTQMQݡڤD fHm~j\|5` SP5njijii4j^|rJڥզ5Mvh>`2K:::C:]:FttXzz:Fѯh@4`$14hhdeŰpHňmcTgؘjfa\i|g2I1gm ڙ&2fzb:έgN1063`XYlhx=O^:}L<J>>e>O}u}u~v~;ؚl.=6R %0,,Yi8e `,.l OBB2B~][|P5aaG>{?0DtDG.U%6FZ 9[;gŃK-hʥז-K]vnrSqظq_9JX<;"~}s$$' %$'];#InI%I^2dSSS&RRiqigJt="3QHᔱ;cT(ʄ2f6gaX?5<ӊV*tUC99?ƬXfkůX>w 5IS6rS6jn<WFjm8s~]@G/޹RW^ykN^g]oa3v˾ín=mnn{߾r}݅w{Eܻ߷OzwA7?8“O+7Aj/=YسG܁du09yɐPpH/_^*^>7GG߈L-|>3s痨/C+⿖~3=㉴ G̙DV@ InzF4=OO<=GO \h  (k;mlde&XO"7I;t6ěobbib[ZC?LR@76`帛IDATxw|ƿJ Bh 7A@ ^^^v{/W+ N2?sgwvvwvyygRҊVhE+PhE+ZъVvZъ_f~&%({J o= -oO_zN;5|݊1c԰hE+j[a-[m-rD6i4y?p{:Dz[DzomȲ2D4TVd9.,D( "'7y6n굧{Kc/\A99O+h _ύAK~^bm:";uK.qYR}T]u9(c.y ʊ_"Oӆ 9&[4Hg r/+Gn؀rԱ?s1V܊?/L W[Q wv; dz%ve@tCdw}">GAVV ͅHѶ[˓śh9vgD]ϻ;HۡcOXZ6rJȹ?aWW@ς/8rX YU DDAoDj{,\ E !z#:t["׬BnX\ѽ BN."-r2hڤ7DZ~Qȕˑ% %CG&r p{FLn[ {9 A._ :vHl)l.DVD^=zJ>H\ Fl,e(ȲRDl.ZHmҳG3iD]rjD^7dMrtUK"Q:tDt ]T| wD&jj[CCwj#81ȻK[%T5o.Ы^ (wmx_O+AAhw܍HOGnێu ӯ=TU^+5z}-{(@y9@]p"BvDZss~¼&Ǐ2h i ˑ}B{ wr!-xPUWQN:{X}} (7݁BpkӼ|8YRuϝ9W?Ő z5vm~{s ߆${1P唵dg]w3Jw܆7p="1 ZO )]bd /hwӐmP'LĜ5eDldvňCM4DymżJl-3PN8O(vei^|!JvBISO"Cao5h5ʭ -DgsAF(TA6+)zYۋv ("Wĺv^B2ѫO6p:' _{Ws AOCt萅\}4浗c0A8/@R&tAv`ϙvc=$/:q"'!~]b]O@ENpeAScP/ &Lѳ'ʠ!5'Rp>2-o nr[1'<|.ض_~ 9g&D=0mc2K#sQ/{ bً"Drrvې@Ν ql/XHL@6j%rWzEe+vm Yvѣ'rdE%"%r9J=E^\jQsy>Yw!.qD٧PFNzN)w "#XX/zYo(ٳ0OЊVVT86߶>|1>3^}>F^v (C!zFzz]gwUzԱ9@mz?}|rd]ܲiS?a(~`9'c/Yd4AzDN٨i)s8e̘V|"3ѿ?}&zʩHMAR~jQƍ)f&`ϛ)~ C An)kҵL \S\Y^]Ѯ-j^ge A鿻F9tDF:1GA|;!E9djsX&dfz+dg9-[mt[C?5*Mqԕ_~)de8 !C4ѱMrETdԌPE8x>)_: Y/>޶Jːe ADhwANZ$q :d#xHia=짪VAd:sμm#+*7.@!j߉,X6$/D7| u(͙Ba#NBL: a\.DJ 2mb+ vq14P vd+ t ףt`B.[HNE4 +`:dJغD}"1mC7II0u l ݐ}\{c ֮}q"-cֺ.Cxkx^݈6I!@P o-zh5ʭBt=>luEVV`&ΰcNQt(MoJi<68;GΜye(λҿӾ3㺥kKJFgZUpQ qV x +D54c@c*4c7lĸA"iSwᄾ33QztdٮmrZ| PÞ1`' ݃1`s\vsPo sފ^kV;9! cEOއ?aZ2z Bn; ugIsh _χO-+1z%}x}!PIJ:C]-r&LU۶"z;5Ӫj!ڤ!'pk^2; _-نFt΅H%?P'x0cAҩXӧ"u(Æ\7.EEQnşyGc|c;$XQ[Ȏb!:,堉 I)+ӎA0ѲSh 7 ؃# \r*u:s@M AUTCu3p|Ke4nH݃u-[CA]ִ\C+Vb? TUB$ȟf5\p"}!:wzMDPGnz>-^h5wEX̑?OMsb#3;4O F$^|tAtvQȕKDD;tґop S=!~]JBXeDzdHB>7G{׊DSOo,K@^l)J!ѧ"l/AxٳNĠ Pu Rs6x=(}{c}ʤMC8L44 kvn_F^4Νn ;=tCi1dJgy(W^ <CyI8;5Neey.1 Wzmi F:T) u&/(cF#]f54T;:f)/ڷUA9x~3ΆNM6v"G891eDܛQξ=ug>{4DZ:1{XҐc0љ9tHr0dX׎׃8d9vX,]&ۿ:'N:S'qMHG=d}Jx…@{&ă[je;!̟W;͆g8@$*1|۹(}}QPQ76ʕ:7h$5⯇UZGs_ta _zf23NAdwD{F,r% @z־_9b4zV dVO)iZooηaV`7;Nce6|sP=6siy{'8;-ヘPۋQ/ KU!^N: KvLj ?gtm )aP2= ~ˠaOuB _ 0dp*g)5H |Ő{C hVV!aoSQQg woE+~ !D<Ju bFDy|؝;;`6e6i2$**u5l(܀i'0USh׎td3W E! qAQI lTWWs3/ן#4ڦbo )%^δ[ǩD"τZ $6:ÊGM}@BEu=kr9"Ms={BC?/Rs/D4\Rv;PA Ym>!]Q ;BJUx&ErCaD w2>/cK'b{-4hx؉S)ټK<>jcΜLÚO4.靗JSX2̕_0|$o6]{{;>3E*0\oxpd.W!%]UD=83뷏gnlU9[WhW|*̛ 'Og Beͮl\:rWi\H6MU֮is4؃_7 ?Kح8uin5F Fo?@U[MU@ȘFTUp)٘ķL]#=G铧0S15OUUTUC0M4w{!4 KF0_uixC똦m8U溮#˴,B6p] %EMLQ?UƮ36H2l>SP,m[6g8?M6f#o۝mMa_% v a:u"+3h !D];眠ՀCHo[uT.歄C_`Zۅo-&5ke@B-#ؖ?cu|DB:PJ}mM6.";\DO\cuUUE,;ni qvhX =*~}FPѷb.iTʪ,ZQE "$ H};/z XQTCIwS`h 4^cU5 -RSqX UWl\,$7;`nیeRj9YAZ*Toq ׮&MF; D&6Ė*Ae| ];QMPFtA5X.X|~!G(.F,Qu -1 ۲].*-0i$bҶ]:%,۶)8ws Ķ)OEh.$X_bϐR/J7m3ڀhTtXR6qc.k`v7߾7FUlJJNn+C>f}5yHHNxátIq,(ظv5} Lj9mvK, gZ.aPdoMZ(QUs5bfc[UT]ʻN+ϳX,FT+TT,K"tm#s㽗qT)m"P4qe( P-p5 W;#xW8#xPUGEɎg}_?bf F\6_ %4FV[E$S؆0N@a:6W'ѥG>gFPjX2w_uHs"0+~-F4fL*Jr--`支)R*dV/]((w9Deil\_A$BU5!X,?R++s!DwUj'%5Xl!.>3ۅx=p:nBGr0--k|-Uө(!'7^y\Y]͆Vd3`1J6' 雯r5r<s0{jض=.6fRSU*}٤Ϣښ*6]ŏN9US1b+R]^J}MuVqh2ʀiZ$$H55,IO0w5j),㦋hoK=-_ۏ..SR3鞝qtwFr6EExYփx|^  n^/?I;h"Ѩ5.A7`_Mb <In W-S>doW^\9䄣9K2n<7&w\~3N.`gHyX8kśs ̽3sgaYmpyg雯pΡ0cgx|Z!%l.\OFjTeG+;l&p6N~ ?|]\fъu{|L<^9RJt]-!sJ<^x8rՕeQӱSg._[=?Q]UEXh>۷;oa[1.Z͘N?OB}fr)dzd,T[otkW/炣&}wpUTsNO弣&j||>q̦H[)ЩG_cM%4z''DRXi~D'tC EJ MRzV.^F=VP9Mfndg >zu4Uaقy|DaO~|[Zk~ðP)@MU=eGo?SCtO:o?^{H8gwߢÆ3j!DBa|߬[vC7 A(4LL{< 50bx W&!)C?.=0m$-=#O;B".UWs5t!ZJVzc &ey} ;a8aήA@!es ,@JgARڤswooq9gֳO5? Pk/qyp1A>u7rv$w.<L#w=7”c&Q]YA,& 8+\}Y:7S]Y3(g7V&f ɉtf^M\CrωGG*O=>uw~.< c $%%'^$MWE>hnˋ &sgbQr˃eZDQITUTQW]@b۷IGP m%)\0l05TUy} Ӿsn{l;eDÜuUTrWRa=?LGUy g$TW:;%=}jz--1BUA*B}Dl4ʖZb9'GcżY{|YL x>z5NlR8x(ٰ~}batr!eԿG쩓/y޻8#9ع3{C.t(pU[xƩc,=?|>x:$\PqQqQrEdEgqڹga_{r(mEQ4b$g]xczx/yh i˿AvRz=WǶ5u@Fه/U%9m=.գƑQPtuQf(ʢP0px -Y5`0)Itزq+1IJI 19-[x:4]cOHJNk~_>2;)I>7rLAt,"KWr{.;TW3d8r>3z2RiՕD>=T0MRIpD)\W̖81HJ4fY˥NsOw:ŭji qs|)I0M6ITp.P\iHiunCFF2.!]{ޏ#GXl)m6@\nb-TWwDzEv^.9ݺֶU[YtCF]z];+ΙcC"AǜIYt1d̻96d"ad>uEu2.95bM0mzuKbRkuЈ۰(-.&5޻eskV,g̙6ҡcGd{.f݊5_d4Ue|٧LO*kEr%W[eB]_}O-ï7#\療#]mtK,f4Ȏeh8L4%!%fLPmڪ:ۤ oS>0HFVBD#!L)E"D#a )D"N@#fyD"1AA,G Qv+/D}GފᄂUJn-#`_< "P⃏w2g3o ))H=h@YE5SQXE.lݽD9HȤP~?o<h Ҏۯ = Ƶ,pRJ ҔuՔVۣ'[61kn+㧩a],/eӾvHH  Gg$"E"NF%s}KqV.\K xUӔ$&z2y+0dĎO>lb =|;~~ZV#Wc:Nj61nXHOr6]:%ld"+v ۶]. A"v Nuw/WpϵPWDeUG9\O79td{8C.u 1ip㎇^rI5 ~ArmФk*ul*cCc?)%_~5\|.k.t>R3CzE$mM,uBEMU=)?cޠQL8X| SSP5=zmV&uռ+:|6HT2p(F?^|Qaa[NnLڱvuHaXh>P-|m:ХgjA4Tۭ~rtZnW!Q(Od؇k!@63p6B5'WWBQ{_,\SckыT6r~Ae,-o.#LM^~jk->\*-rp}"ޣp |d?BNRڴ$T劻"19/ M(}a oB!z$TM[*\tEmn|)o݆b mVv o\K^µ?)z5{ =v&ZQ˥6%} ;[>k.=/ͥdkcGcݓRrYS וh' !o}2u+V`6\u=)iTUDܵE @0Ƚ/Em_ʁGͧDzmLSrƥW1é,-o]Cjzp+|Ԍ RRsM91 ]qursϋQQZ1nD01ٙ:.FYXԠkPvIQ a8J?a )2_[, 59Ў|D6icKPlFU5yhGk'{8ڏԙwH'7) ow^|0`~tKÈСKH%Ń7\ŗMdwa'Hg %7͐#uA0+ Ns9l\]^́GödY| pw%pwpUW~\v۽X`@24j}wx#C? =6_D'u*<7y. Nʑ`Rna%1yp«ŧ%x W"1AIV)lUe(~c-@b" )m2ځCn"a:ĶiZtIČ@(duŲ,̘E,$#jچtL +' _# &:92;!R>yevĪ%\.C8\[@iBbuHKZ}vv&KUe-/!ȼEP[Of5X''1~$/Yf#zBimFuX ʠ4e0iZЉ9FؖA;fxwMױ-)5I6ni8O *];oU,V.GQJI)2I5(f8aVS(ŃeK'aXTT˶A,CQ5۩,a*B9:?$fH4vmea[ ÐHi4*1P RbJBLjBH\Xe2kM!-'@ڀT:ܾ%pu5&&TrڄT}oZ>$j2EzRI4X 1ęUxATM hOT#G2tH,"! #42k"ikh2MA4J0kh߶ #Fuv6,01t^_׳c⢐;!4ݪe9+z -&g= ;v BM+qqCǏCwpj (Ƣg>UkIJ `-{{&vfY6Z>b,=CGd#rH# l|uZM,Hi9F?>R5 K%ѠE--=TY|],W$T".ݓ!oà-Q*·SKﷲ߀T9 ڥUxlg^ë,#-H#(W4BQŚKq{\L8Fp Hcm㦶.yŽiՆADݷ}yP}3.´OK0_5r4a#4UU6xPcDf՚BjL]8͆F}m5o<=]Fƈ \hm„ꚦEmPh޾ x( ,v2S >PײQX̤Snu"8(i"aB!eeYb1aЭ&566cێpUi)8$33i4 GSR[UMd@UFKNdzv!\G(cͪU:mڸa,!y/?ఎ W04?bJjHg QD-FJG`|{B*W(1 ˠ1lk|f2gr IIXkhԙ")۾X,#u_W_C4^MX ¡_Gi(ERG$b$p D4jqŊG !{D4 oƗҞvmMSeSyhBT߯8mX@]< u1,Kyq{XQ Nv$D `Hm+P_kk*[PW/)G̐XSRB6-eGDĠM f783 QD>XBr:w$6nᛮ] z}^3N4b8шbҙkNLVٰ}D"8 ! (^k6bj>~5.N4i=*DB4 '/IEW Ot= 7/V1#gGB 6S? 6HQ$NɃ3@X2r`c$c~>Y|*˖Vҭg"Ù"% [6x8CpeNgd3=7nϠz娪7V.ZKOUe%Cnjs/YNfBڴmiYH6{7rïrИ8n0Ư$sUص~0J3Y,!>EӜwޖxmGcM23.r>x(9^E â?HH ']zD(7sҹt"~%ǟ}ˏ<2O?grwhV-YI_"$o<ӽ;r?e ?p^yCt<ɞXpl@g7Mz6[ڑ=_g!pՅgԄwL2LKZuob?QW[KBR2a2xxl+iSٴn .F8TËÇ29]F9ϖMETUQ_[ҹsذf%ugHBb5+7ngD~dWvƪaE-vsqtVl`l`z; )).C'-M:@b8T}=l!<>q̈́C;x3O^>_ҫFΧʢfbs۷m!';ۊ_%I ۴Kt6>'^|K9:5S;fӶZrztt8GJCڏ~e2ЃWL4MeͲ%>`Nbl*dڗryHh4*PSSGiy??xǧz-zN 3_Ogcq5`G-Q.[4qkѰJmmeENmO^h$̲6f<]u) wCƌeETWVOH^%ӵ;"HsΦc<̘N '[/2;eqA,=s= dL:4>4mXNǮ=X6wg_yu4Uq~$6 zU tKDyݹ;ϫ9O}! fРÁArBzf7= ˏ>-[7dۊ7)=yy\agSYҭ[ظj9F!%- iҩ,om6(J$lS]}=ƶ%nmU穪d{ 7Ovuvmr[nS:ۧ1ٔl}Cd*^2;0o$$&Ѯmo3j u&fLQf޶| àmz|L#N’_̧Wijw|a[6pս:&M.L8fWsi'389㢋xc!AMU%u\L8(6_G³D#ʼn;o̶bꪫy則uDκy%>|EL<ʲdducG3PUa uO'bb2 T*j)Ndpb;6'oHrʉG"m 1Mzێ '︅ҭw)lܰ_B4)jbJ8\G6ܻxv6}6 `Xhۺ/)%fݦx~r|P׋ׯ8t4tllt݅΢=RJJMU(Gڠ@8C\1#FBP'k7>}-R8ضgԙ ͭ3`AlD]x^ky{]:HA `[8 FO<[GBRkA_0nU{4$")\]6TTB*dul5hxVƊEdYϼ?Iߡ('ƶ[x֍6ցmlzfW_,?yacHhT͛M]M b&^o?h8mO=I^Ϟ1i,kkpf T5m. LR)p(_JI4ERusP\à0*b!৕w@0ƴv H{u _wd&V?/X`ԁ'rΕױjR^{>XwCtR֊?LUUhX|>'W#quJq/-).)E@`E",߰s>m?lNpz[FU ȉ(=o~F ͠4,\.X&\g 3q5 ۶8FLe{lQFllo!rVK Ij<|"I /~kPHVڲ-eRRJ\NeE5[*Œڅ#D<dE-4MnhDuνiõ5=TGi9h}_|GeBrZWEUy#O? U@}}T.6 LjF N:b:{W h MU1MhY}r_giie }^:`$j mxMl\CFλ+ڌۆO^[֒rRSx{%)5A%Kw:pft0EM&s2y}ؾO9 00Me۴=AEYǞu!Xڪ({Y9]dtʻĖ&Fl*\ǞHʪ-M^}EYJ8m=i $/}FހUճhO޶-T(E;!%:;Vq,b:kB+ pQ$T/9S+ٴ-5qRm7 \CU * Deʚmx>>b:"cNaf}1cjӆu֮ 6dv!#q_I]MQA$jF6ZhBS`'vR"9a"q .{]u4,z)1MEQvxO;F1l~kxbF5Yϰam1y⭍?0I:bշ0PMNDF n Q)}svò, vع uTǜg~(*a#MFԠ[ᄄ1g҈BqDmL$abIv^7ah۶LIJMň>/)]:$ך;+H(Uk7Rн;q1H)i͍5(I=h@u_UU $h躣^WkbVcj`sM_ؑ]rĴLGuws~ҶYےN; mUg^"˶Q|hfł;hX4iu%Clp;$ 7ʥ5Mh<_.kt7zRĽY1: %Q60mM SUSٺ)g']׏CJeٸ RT?4̥6kP W1(~FmN(JmM}-ۋHMoL ׿nX۶q{u}I>%?&KWS 4 <^h `04_<[Cg $P]2њ_z\9h.zYWƧv50`EbM{B`:<Uiy~N~~*k.DuGnCц҆m4J62{vI,`0v9TWE#q侤mx3+ l][8r5 !ՠ7ѐ&mVD@IY\AUUE5A]].^[D4# T( >Ѓ )m|$&{T\K0ч7SQHHƇm/Gj* P4˅ B(hky]7]h.dP]-pS>|YNWЊfRůֳiRtNNb>54GhEAFb, 92Rh\4;o7P_Wn|$[+TOY2Gh*e[q5<^1o[ TG糷^cNڟ4UUu)VzeoڬyH nϾ3|K#mՆPߐU[[GqEn=1Z48Lp铿f|?5;,mt,#ƥ'ςYxkYb)"n-HJ.ՔԧߝXnYLGڪJr{^dy̜^ƊCun!x\̙>W9HIkG$bpLfLe[=:;yMO9Cc_⹳5m*R_[K-̘2ˌrZ oNeyRwkqVDN]W۲-ٰ̽:Mvb-GP0b4M;7Cx{J'q*<^Dzؾi_N%f&%au<}0`bS6o(PSY^ˏ5E !ǝmnJ_P]UA ,++F̞6%6gy]*ڮB&N؎묾e1cqlZYx(#f ͽ+ሆ{,7מ~m30)XsIJJ V,'ᒛnac,3$-m#@=(kW,%5 /? It^zY:6r:3tD?.[Gү_WW1b6Bt=NqAӝĤđrkLd1[vCGԭdRdˡ}vJ)2ouwPH"J攃:p,_쓺hɽIi(.AU-j2<>?iڳnjmj*=N蟤k+O<3ܭ' fc#Σdz~m"z-??`LR32c״iENμSX˲?cg]v9[xGIoێUK1o+q{|XC(:ڷM4_0m[r 9|"usWNtFSbIEe 6m{ ^~EaM&|)vOHk0Q0 ;7(*\7Qѣ$$#x'ؑ[Qo?~/ab<6m(``R0cʷ\zs?_۶هwֹtӏ?Ҧjο&'y}_t&!шEnݨXVwfRjLʪsȺEw-9hAAX8I䵏1騚$ $'// ,/{Ĥdyix̞ ,"KGιj:a**m X0s&ӿG|.̓(?l$+'&aՒɚKy㙧7{&{*?M/!e+qoD`ݪuĔ_FritґCplϮx[IPX͌ԭ&vNrBWUE9]z{|{)r')9osŗ.{y+Ky;:f,w<0G4-tMpr7ԋ.%T_+O<°Q(4?N:q ++_W2COӹ{f6K&-#63G񋍲i$%I2+ASvIu}`GV lakbjcLJ2M`Pa== Y^۲h#):fTG*NeYCӄ)ݺk6S^Ė"6nn=Euu+J"c6pQ(Akb,XY I}NB&†2=z24ДQ9 >e 灴Y6>r3')%#pJ!5#`0@ X\nnSy[\@B"h]w.9..`@ڴKuo0֯Yedfgݥ3 IdoO}m3}'J6m{'bK4-V@UM}cӥS&Fsg3nxb^Ci:й{W,X?yW^A}]%{oP*i2p$Go<^irTl/; -GGCS5gq!Ug-$iTEﰡDc6GmK*+HLJG>x.:wLjŜOnK%5x WF4Pwf 2 Y; ":Z)q E!D,5ظYIJX< #i;gB(*cZ&tWP]~Æ1t\x\~ƙLSRڦ Y̘2E(Dc=TI$l:! @;s;Yt3Ncظ ,5Uuidѭw_R۵D. ){'KPXTǢ5N(϶%nzuIrfK(DU6VQvk~W/GƸᔋ.g\ˏ>H\te`ĢeeBd\.y5HiJ.&{g^<,ťheZbZ:D#(FLF[%gBT4jqbMޚP6m%3\;GZ6Z\ϳwiJxv }E|B4Yo?~ĺKƫ7lhdLӤpdzBu(J4髯aZM, "q}"0ioHKaⅎrdBhYOma;)8fLҭ Yor{) HmQbFxۖ)[՜b IMZFIYd)=sۅpR>M U0UĶ@oUuL%1ltV6AZ,fe3dX:d>?xAƐB>ꬥ,t'۲2-\n7²G6 &/ *ѫQr BS%-il.lM5CHIM"޽bxE$ֻ7kΜYT\ 7̎TWLHBJ dGjX Ehס#@o󮹁,b̡3}ƵkXd1I))6Q4ܼn|g<̝9d,WA}HH i::OX0{Gv&.ϏG 8{wk(+ ѨAm Xn!#&!c~eNr|~x8ʫP51@"EHFUUb( f4E{F 7"3({EiƁH듂1k +v`Yۈ]*P E=PA8dwr QPo)%#M`ix~xHǛ=ܙIoɄ#!Pu?\w3is7ddf2v.;g͙Up{,5˲9t/W#29FQ-䈶 RJ\.7TbƈzUUDYa3lݮqVDpѐݢ˲\[HIKN2(۾n\v=o*bIƈElN8" ֒?(bഋ/GwleKK#1c&1;\rHkd$19܋0b?6+IGѾc'¡(|TU[QnXMm}NFG},X9#q$)SWvxzusv֖!:LI>z V|^Y'Уu}3+$)9 ǏaXhTz"\nM'-*A,*??9DУo:x:u%uC~1֫m;d!c>יSiF%((Z ?mRݿ*%(`r'tm6>G"NEXu16{8kx] @b )RNo(:lx!ٶM$!-DZ6eѡs8qhCۙ-H8FZؑXԌwh(>$`,"`d̘3 ˲wr40 ٪+DӠh*2D{5QUPM-[UN2-5i`ìT}!'41c@= +($th}ӣoݴmV6Hh8F>#2e8ՊбmeZ;'bFcD#1[>XCg.XI,f& 8\{`[Mj (`CQ4UE6?LI6GU+%3%'<30l$A&?' wt֯k\‘i;pWL EQt o4@)m2d_.KMɀ)01@ޟYHU7#q]z ՚ŕ<44 |dvU=^LN:Ne Mg7⋭fUwIEhX5_M6p,5+cͦ~;'l)Q]k 9hQe9)$ 4 GuKp1w^Qxb8q Dmۄ 77L8AQbQGE̲F4-Ll^RlƊFTetgh*WdSZ,mV,U9VdHn&NFP= KTVyKii)M{_OD]m*$K6 F"q P|G[ Յ 4eh2qB4 MYUEAl|WʃֵhH mX:U奬XԴt{Ѕ|ͯ1{=) yk ¥ƥ6ӏ· Iw1u Vg M٬\ `?mU\ꅪ $4m[ed䑔F4mrօHh\[mvD,k4ȍUFU|.HE| "/r;=x|][ N~r .K^~$ VQ]o5*H$|M5̞0ww U<Lj7w+A4>ti|^4r^w!x=.j;k1{\.3w^ћqА2TWls!ucRt;-UUT7ӒH  o,¥p@ztg oK iǮ||^ƽq@@ض`$gTTߋH)to]A]&JT-a]wb̞6%sWyB àMj`V_.JNn:^}yo<;M}3nŠp/>9kљx 7E>HsRӎΩww 5H ͦe5[䟃Fٺf1aYo:c<1cQE6ECAuVii1rG ޭVǨp] ~2;{P ]*J)PH>xF?"BN׮Xڍ*V3g|J!3 b3)߶ ?Lh8̘C@US?6 9H(._M/:hIC^ˏͯ_'Rrk,_ UGn玘 p닶Ca]3y܄#߾ "X]qZg_ "T##5= /GٶdwɣG~J$b?QUQIԵ'is5J YhҶ'$w>[5F@z ֮\ipQ'E Yr?:~damֆvRlϐa?}* Fw)t9Yv7&zu\]g'/vm\4\窍ul ;9--I.A7-&5x6->v7%iƐWA_aْIB^pRo 3{cm[#a}ѐ+][bYJׂ]֞muV/[kO>ʜrp{Qϧԝ7rEGCٛGgE̛=^z> gMvr ֭?Oxiҳg>~,ϐ|(޴ Ǎ(ٴ./ 5PflZO֭0CYp>+Wrҭ/r&3wߊiFxVa8`͢9|*ua:Pv|[^n7E&l)q\l*Z ;k‰Fi.v/m*ƍO`3x~dzQDZrbŒ)_s 70ixt ~N="!J~<*+BH hEN\@4%g1`@֭XG"4}*X:w.G?1_~NVNtI =Ȕgތ?|kc^WؾQզ]F$;7#ŵΪQlQ=q-a D wǠtHvrt5Z@SX*zwO]=?vu%3VI;/Wli)`yQ}%ix|^Jxꑧؼaq .]rB0c;.q`@>mڷ+y5+KJ<>/6#ORi#c>Q]R۰a֯XJFfG2eq]!kV,#HFfQWey_WQYS>K.`êel\ユX4r1'pyUw aʊ7gl d,US E(V';}:OsRtnjZs9 `mڶg?ƵkyGe1n go BQ ;ar#jP[UixٗFw#<]zP~-eʩfXt)۷UPSYA^~up}-v=S>|r*>xyBU{?cnJ.J^AνFz 7dn6xY07h VZXHJbƙsTS]Fma)8+A~V/ohş  ZG񊅸]]AIKB]Uř/fAeㆧ$Ѓ6,"1+:!?VQQQ˭SYVFJ:: [|6*Jc rfmQ^ZFeYҭ%ν1- *`3Y0k&}"_?4Q0`e!0M~Æq]˯ƴLοzxGv titA~0Y)m<T/.1%[JYa"[6IOO62o{[W]efX`` `[2QcH}5p(eTWz)/ێ$!Tbk[Zضl gAGźKⳝUu# Q[S͏Swao_EfvxSθJ~fe3p(y1?fLUiK2sޫ/'--Կ* +?lpEݱ(E`HtI$q)ѻn@CZU. DQEĥ5h6QvB ;@iIU|)[x?kiQ9u!MtJʲ%zeCVHn_L<|I֯.$ bB{elb7_cbZS8Xb3ϫ(:ƍۮgQG3O:3`ٷkVduӏ.={zb7` lsp6)$bY %F,b1(HnGΟKv1-kLgÒq8=7E0M6T1J徠Wxrξ 3j|9|-֮X?G'S'K5A/߰L4n26]۫Xv뎦{6y s/?#g>>rl G%`_ =^$8q8D_z)Ot畉l.SnVhlHJI0Wףj +د!@f`=֮>j[ +hsְlmq}e^!ӂW>/Kg#7\i[Jʊ5T\:f'sn;8+`wT;vw'`  ,]ޜz~%_~u{w晹sgs>sTMeɂyXIQb*f"!)]˹WeyTΝCwP6sQ֩+Y475STVBddgE=AyY~3yEu$%3%_ԖN=H>A8tx-PSHaWs;WߊEVTZ[tnL0m"01D]!;@UBu v4wX6\#SnKu;B" 3giFs瑔Bc]]JJI)^r x8uƪ!`s. \YI"`b)1gFW #39=sJll+ ӿs| s0N|H,Z@[Ăٳݿ?f? X+gQ{Y ;VZ3=_ oO<8 8; R_3I? PkeY ~7vzN~o\D˄ !mAN~@"?`1xS#I*`c[Y 26xt z܋R 6ǐ$W[>; ÆĔtw (FyI[BGcʵ(F];" mu,oF@Qew{`1Db?aT:6|h8󩫩e hjhs.C?>x??)#O9?̯~c|Ề`ڵ|d % OM: ,o K.QѣtϋcCiNg`8_XD$]ܶ$!ذa |^ЁX$nvHN/νln#P|*s*8pDָ -,dXXhP d!H$;JHv,Ń $یώ,cQ$YAQY4nJ#QwAfc}Fr 3̿.7bP5[82ALRѲ,cZm,lv~c!6;۲vh F755uT/]@߮enƝP o {M(476t]e,!D8+s0b1X qeF,F4tǔe0 6jԦi E[{#l7[{uَ[> I`Y6I1c^A.8B`;٩!'eI8tKU*gr/n'yO5_>&RwXٛ[*'^q6G;Y! y;z$vSc|^Q~ykNn3߿wnq-g76ϔ3}:imel;93Gh'N,o RSYPudV[-_[[>l'-}5z;,AnJ-r.CL疳K>#,oB4y ۖmݍaی$8ڑh&W4"FD@nޅ?\JMYi*Jh1Wح+C dl)KTҽs:xmg 05x W Ɲwg;$ʕԋ|u(؁ 8vc@Kzz-̀~]#,\5s pEQpLW&?d7[0o˻2N [MFYݼr~|L_P-7% ;jjdo vbJ R.&(WrE:-vxZBU2S= ?S+9;M1N% heoy7@,^0D9B"̘TqȺg (X45 GخLkV"c¬ZDiyGDh=]Ϳ:t݃1?VxMkJ嬩}]nb)lhб, gznӑ:$tLXM& '͏Pܹ7ɻ ,!Gg4mα)xTP}?MšC` kT.[igθ 4Uk /E1w<e9Pڹ;U:V8"o9w~; t* Pl>f7;kA%Ae^R=nO<ȜrP'\v\  nZcnFNUPϊثWiBի3b pԿ-¼Ud'O 8<*BO$5#sw>yc$ID]:"Rri=['W! ~>.@j8. 7s*ZS~KE dqyLvv1ʖeHFQ/hey7.!1OZ Hx;(^jL:g%e :&"Q+QrKel :& 6vcm :&7 o(r?7]M,q'uI¶MjaF똻XOՂdѓ]ɻ<O1DSi׹3wC]bί)Qض NVpc+o^tK'* ƎAfz .l|` <əgfa=;(hST]ZQo$ 6]ڧX^W8]w9}{לqkVyԸ~A;0]{|o<('Oql$IFMgoŦ*|IVVy4.gIůx}P_ W xZߢ>]_QXXJiYFldo,1?|˰z ڎ];ZDŽsAgPx MS6|zuk{ߜ,1}"K;Mv߆vJ9ħRu3* m{xҭWvHMLŬx<ۡ^Y>\}᭧Ge0ba4MW:~,kV,[o}Xr۳V8DhW4#D>% 6ccDCxj$g8i`oiK+x'DœxEϲj1_%׋ڕkYb)C8_Oz E8|K|{Z̩ï$!1y q1'0pdwسcj7Mh{7_˯ WiyBz4֮\UuUDB!&|45ԳzY߼6Yn࿜w( , o{/A5fV) 3?Z؍! Y>{2aZxi;TFwdgc\˪2~)ZdƲk吓iZwQ6 dR 3qn=hj$p(-J@3Wb <BͶ~*7fԟ~dYT̉̚Xf5 (Ё"ztk,KhYX8w/oH̙W|t0H<;t 5#ܟ5+11@ŌϾw>pqpy^""+'8^{pu7h\ kÌ_1w$ Jӡ[93!P]f Gο*FydW5 t Fldo[,3mr&zvŒDwB]TW2iZGGb]y\m/zwğv~UQd_JA.$&6#vPܱbl0mSYT-b{SHRrI;×epĉ1#y7x bB $ EQF¤gfs1G1øg8㩭^OBb2H84"Y~ 9zM9hj7× (ⲮSx E<ߏ_~͜2`Ȑ8[8d/>n={d͝߅ļ&rJ۝OC 8NE ٳN!x)B$o'qAP=*}:3f-dY ;#6ik' @՚۷]ҷC}gm âmiMrKփgC-;[^A8lsЮK7i^CrW}wsGړ5Eͧm6d_TLzVx;cF¹5utӟ?+ַzWut? yw/W甋SX\%'_3C}Z*Bsc|2+.o:u+#=+Ҏ+ 5[p>|U nDyLȿKdU&fUce`⿺Pڍ.!dz߶0gq<~/Ufm-.o8i6(yiTMcjL6$6l`y :D1P8 I^>:_ᒳ;ㄭm ϸF08()-"# :/O<~4MH8?/e8G`1mU!j/_ YA84ԮI&1)M'^ux}IȊmh[ObR;2J|"lv=xXVy゚bƒ#,Pۏe)>%/pCJ We\75d}n7pjup%ѱS;be]|\.:h"ͮ{Xr-=9y_sw9cq'%_ɬ&pF͋н ,QHS%f m+ث?SZoOOFV-_}DA'Y t_ IKHqC8MpYКǗ,O&MI)YHc;d2r.@Q5L5iYiiSJbJH2m#+Kx%ndEAV=ȊNvTݏH,]^z=퉆w~R8aV}מ)㒮%j`\ ( *Ioە5;]w|gt й{G?w~N̬X ‰v@{zDHn+ON،W=@;dX̦krZո]F9ʝ-uLevqP/)>$ LU7Ӫ`#-`cCX4$ aDPQBq0V.4EXٺpb(ma;Ծqlb(q0 %X 9XYض{VsUR>w݇T'jo-] "cL_"k nt!u5j'x`e[>CIYN^As x4TɞJՂt//YA8-*fkCXo% ˴$1 sA+X>9f4u7Z^ꪙ:G45400͍+ 4a% I[4Uz&eqY>~{651LMweK# 衋x8v\x~98E$UMt(4ſF0e76p>_~NqDnܼVxɎi*m}Niԯי3l/My4u1ozbt+/A]UC@R&Cܝ~!eKO12vQa I<~oHdMg.bǟɛo3cV/]SwN$Ԅ,+Ȓ7ӹVecGPݣZ hRƺUy(ﮉ(~/j|!7?[%`L..hg0|p*KN>puo:fc )^.)]=:&BŒ&ԎnO@au\yQr b_v$|kx0&@ IJJwBwelo2Shj a4m>B(?MrXt3 H4v;;(_AXGSmEݶ(Ir˞^S/w1+s\s|0Fzxd `I\BM ^!`3i 2a6gN8̒yqlϏ$KXd'2&ϝCchZDqt-\(~6^j8yIU3y;gԗ|/I֐8Iϧ"'k~Ov#perA~x %7B<̷?Wq2LjD4ݒ̭XE?|OrjREUB0qCf̜5U{7% WHIIFRG}3$T"m.we }9$IIY!r dI3Ġ%|BX] 7_㰓Nc:($$R_ Y3u-ddgn*N~{|0w_u~4s(_7}Ͼx)n߉u <L7tN8"{Ķ7ʣXr^s=ދ[zԮ_Uw?Ȟɘ_ƒwӮKϟKRrJ<<:!LbgnrrF+cZ*cK(jȋo/18v<.<t6cxJ@&IHdm(!QUu^8_f7 , G.ƶ?GYƓ[oɵ#eZٓdW|/k=Ǹ&c6?3n7?KCKhL 2PStnEJ s1LO$¥8x˖L[;; OY²mZg\ )_Xj ^Vo֊I4`؊l[_yQtكz}=מxj֯^IS},56R~-pW=ψ8h1H^}ꮻo˴ g^DRJ &]aq pcӦqH8ͧSN㪑ҵw?Lӈv #p!k'X,IM{P@=PN_֣zdk ?LGiua_i g;#\p5K:;B$MSҮ=ؿ+nM_9>zyۖ?Kmݣ\vY_,eo!9_f2d^l!@u-\Ƃ1 ;`t'jpcoR)H}suյlZ0y>YSU>MM,ؖY^Y'|EmfJcCz`7O"G}xY+8McC=~˴eEqIV˪%ZZEJf:`3Uu^4֭ZÚ+93JgOHDUκ:~)O=U"Ex٧u`c#OLd(/)[=CT-XH(䈓O%+'}>В8B›#C]˷㷍cӹޤ' J\|e:'rݫ[Ö^VyT{n~|~۶pߎ c>[ڲv^X0,IMǮ]`ftElIO!8f;ȦDw܆mE<?JA{o>}5*+sn9HAJfD͘*ٿ") 8MڕV/[Jd<Ƃ9sXp>`3 ?_x˖ Oh|-GЮKglj3>汫NX7n=LS +acKgl૟rB$) /h`zv06rFu}_Xu/K;~ϓ%1s(.Yڪqq{wB]m#_,?)X[X 28Vm(nNQwx=dYƣ{tdYzM <m5제r(٨9o<وȶ JV>'ol73zp,g$I"drŗK;}9`S]zh"q4/?k1#(.+G=igʏߓEFNC?eyWD$^&YY6efjnѣmp$$dIFݾpm};V/[I$̆ukHLNc(2huV{ޔuinifTJ9c9Jl)1ybD.U9eHؖتP$I8ȓTe н>:KrZ:0P8(؅ +;ܣ75u&')CO: 4 6%tڋ m4z ܋e 8mtݗX̀>Î"%-Zn}9P䊑GMÐÎbk8"n{F-&MS[($TB+~ɯ<3re4GlfEWXSjrDm'~2h1*_[wr4d0DC6Wut+k]O_W8| D6È]8 I:SOcͧbnt%[;WG㑕NEZjmrqLOx" ݻ7: A.Y/s7c*j" ~ի98ܣٰ|5L^B1Rx`Oc)-/3kˌ`HHSkAn<:t'+' $%q՗ѽo4ífKz Ԯ_Efv:\m۵g!CWX?cџnrNy;i)ؑGo+G͚+xٿ?ǟs=0z&I|YQԮ= 5&ءFI²S|SVCUqÛbc=kn Ya:uǮoϙ7ak$WRV@5! rIT1vҧ/űQʠ `n2M$$ ~74z#f\EQZIǞ-X"Y1baaߢ(O8_36gSqB&nSye$i铉d"+5Q7|>n "/;>qx cؖMJesIOf&1oI3 {B)y$Iҳ: ok/߂,_Wj5AvfX/TG 3w1Q7X"*>/~7>{Qޭ[;N@S+qQT5몱D J0 uQ!dߊI| )2FaƄ_((.&H݆fOưs7JڕpWc'$pE8&?!2d̘<9'a6r#ip]2s66ҳ_?ʺvd5D#Q=$?@;s˅b2<C+.EXqrŭw_P{0{ KHL⪻%-;GE`:[HD4bСc{H5}^YV],{dd+$,agk}$Loh6jjbĢV|,%% :!r?7b1LÈ)QbF,X$F)ckaƈE`Dc8޵L#l;QwX Èmw~/f%=p2 N($ ;hFr s"KIYAלa $m>\D^q=q#J (Ua ϙBϲDv$I`]lҮ( {|79!)˫O>G5\xαꛐe[^/w_:ܬV[d<.z m bۜ|r2EݹHT-Yŗrghʺի oXf^vya RHNuW}^TMm=$&{Q {X0k/Yaʄddd0ۯXHظQ& (DB1AV8>۲h&u6^#8ヒn6'$EHIt4{}1c֬a֯>uPBM!rQDAiHDͺ5ţC4lmukÍeڤz gZE=)kX!^^.UBfS21D*C}-㝕rV'z]IBeM-7[rk.!C߯eUFsS/I6/]l{6wq6C'rd(x q{>3'f#ҵc "⮪F A :x X*]* ѦF.Ci@{cce >J;t/JRw!x=YU͸_ؖ ;G8ڎ'!{Z$ei81#wľX;B {u>f2m;RҾH(+zE4!+3$d5i<4Ԯ!jv V^̘8hO$ak˯dliBh[p@=m plEBEy>̚2UYj-M[wB͍w!}}"fb3'M fwcP61b.6-MLAY Ǟu&C&{ dr!ˮYL1IΉ\>r:0@d7BG$$y, jC|•eZZW"ҭ][moF6nu6ݶ}k-ec[^y뉄@к="v6;^Nook6 %7Gp뙇Q^GO@YDzM 쐅*rʨgs)?-Hjj: u:EsQjڗ6EZrI1_)%KmKke @%ۮ1hϾDP9G8|7v 0m&/Bmr^н֯7Obn=eμ*F '[ (-@X&ZA.P~jkYQcW EPgҸ1G~ 2R5|Mj<gJx}*H{Gr6Yt9\x ׬? +? $ E$5{gapƒĝr p)g2sL~ɩ勫;7ŸJ),iGԆ6EwAy_~ \x <85-lK׾@ .}MA9yGy|munWر98LJw`u ёaCAN]83< 'ĭJ ´Iz^>|W(K'2l^*^d;P^h4~{ vHH$hZ^0-hn4G ]ijtW~GBV@@0,67r!Diq;E;F6M/ M =`ϩrI>Rx$cGG瘣J1ld?!(-G}u39m ܻ' uJ:"3 9Ň56"1oi$%5FmpAb~\'"!-Pd˲y/kDQlۦG2=fy`oC/~ONg޽#2 {|t :}1ubi@ L8j2WPxtu|>?re/Oߡ[DX~xŀ p޵7ɩɌxQddes" 7YW\%lq! F3ϤǀAnv".'5-UйU+@O$11@RY9鄂Gq.dѱgus7xo:ue%dfܝ.'fq)g"+ CllMb7"KpkbQa_88`#1y*TEnd1 ao]/^Iy PO.y/Y͵wN,jU5?|cϺKP1s&=捧F19mUlXzKaqq>eq7c >~5.şr\~1tsXL0=N:YR|:iN8b2s雯0b1*˯ew?0f-g]b[Q$2%N|{}ߵ7E~ ǕSuF4>3udtJv3e˼)B?m$IHCA}qT_OK%idv''?׿FTUc{g? M ;Glɿ̠sY! x=s)?\ɵ>A8lQ_[K~-K` DeE9,"5,M3HHG`i Mcۂaǟ/=K(hB1rO z$ _eZŇ?1 G8ˡ)JQv* IȲJI8CBVTr PUe`v\`AQ=h847Fڧ`ǃ&q<ASC6EamW-B m_S_f/Hc-a;R# Œ,KD@㬗y4$6*F:-ZqgG۲̜<U'!1B W͇/?Gv^} ~陙,{/>?0vtTIӏ8{n$I&+'YEf#hMQ1<0D,Xe+Qdᅨ ,W{/Yd꫃ &QܮVlkƮsOqԵ_dhBsch@J܇AD N9s8mda:Z3{g?{hXڔwmY>ѨKrP=2kWFBd $=5D,/]GaY~3/[~1|*"fl.$H8B~a!o{~=Gi:gesU1W=gbɂyx $w߲lB$as؉roQ[]/1doBSC]k H D/I 7]aX! o% T7p%%t74O=pc<ºUjڵM%!@WYQ(ðQd Yb )^zIX7KD196ݏ盱S[kri^XpS x¶I tƌ/SqPz~/f,bڢ zޅ-KnLTIIIbNEۢDYv:!K43YYk:_/=ϊ%ˑePs3~D}m5@׃ (u3&BJF}:n.KJK7_[C$EBuYFBğ# 1YrTjl#ȮGCU桤]|>Ud)>_2,fϨ"~ZN)˒D,fѶVt⇐ CI^"Zt V8p(ϯs=Kx .:k+IsW`z(,aE-u[|מLℳ&X8&=m۷'Цm)S~ˢEXeDC!,uz4lӲxȲBjFi[{^|?n ]$A I)T]m[$!`"mDB!s&$Sؖ o<!-M1h8BȚ}ЃPT+.BHҚY=M>|iR<}g/2 wAz Pd 3Dt eh*e D,Ɔ†HH` $t$W2 Ij'G%)FI2-$`w+`692k$;C$ ѨAzV6= לvk2 16/m [fպ0T0,Kei8qFMM#K2u{8p͙0w9hnldeaD(`1"PA 56צ >xYn^mRR-$ rmwpqG1/.f T̘E~Q>~1Gv&lne¡mk y~.Ibr2a{C!0]SެZ̾4m!i^K/^/ `2`)"sEAy ުQ"?֞\}Ô!dG 9]ɣaGc Ce0 fT(:rQhZȻI^lݶd,ytj=pQޭpmf"![W|LYltF ?U[9sO]2,$'LCJә<55[ In5XgrBN832kn@%:/r26hI6G=ɗe|7_fq!}#s>^̛2uM0s4:ŠJ h߫7Guu5MWoeL rr#I̢fZkf P> #&>0:r΍t,f#]s/㫷_ȳ/%1%wz^{OyN  CN;]~̬q"+:4, ސ, n$sؓP|C$&i{Y$^}v2rp#M~o<|7TrŃγw^Ә׬a|KX45÷$&GS [S_r;SM󛆠CNz2AӓLg:R1 YcdrOrǣ3>vm M@fp0Hba#\z]M_ &C= \1~l˦=?(F IHi\x-b|R<4ד˥B}m3 )XEе'\x _~5&lFL F܊#At5t/rS-P< ,}eϏM䢻^eо, IgŲ5oSƮOBGaZ=-,$ [L@lb(ex}(B4(#˭lWPmŽ!i.HM`Yom$#7_xq\H옱u&W>cUetlW6-$}zId]g 1OgνD*W~ h,օ$98B$2UMcʥdfa&^vcsZy:BQ-i8-l!3bfMHv'$1, ݷx;vgh<ۓè3s+Xp#_6%lXw =uk3y<_wz )%hrT,]L~Y0}2-*MY{W5yFYL fueO R DԢmq*IK7csedE&%)#۞|\qNW$!{УRf.jf(#_.gL;={WI elAQ$d3Wu0)*iKs+3>&w1LKzjf2z(4"cEVWXYU7 2,#%yd^ΘBs}- Azpl#CVtX$J[ZBCtˈ Ǔզ-."" 8Q!c;$$'3,mt]'딋8L2wG@K3MS$ Dy65=] GyĂA69<zhp(,Gd/OiTTh0!&^]gl *)%l\,flvf0Ii)mߤ)"M1?|#)#pdzw?a;4ȉj;*DBalYEHP=D1M4z/?| ~ye.OiEڎA^?NUw@@sf.V vГ|t/v?c ˊL4M2M捏*}8zaH8VGyÕu.9~Z5A:gLzVF]iTEG6v-Jd-oc-iCP-ˉka[ οFba3$oٸZna{s%T xsu$' G9Xu=3o7m[лc/ޓ^1C y%\{%\Bdfiůl'og ٝE"1歐hӮK[FY dUw^d̙͍ ,+xְ#GSY4w=! ^DZY4w&pP5m[*+v$ $籬] EB0 |>4]vdYEVUYUe5ܽ&'GO us.Dѿ4wz662#ףc%'ɳ$EUhy}0W78Cz33xӉZܗH%bq^3-ӹ86Q;5EU+1=)eRH-'6p QЮ# OkoT]}GWΥSwTխQ㎏m18M8L~i;rJ;e&X$Lrf&dΔ|+]XByA̝>_= Ēo~;qpejk vgj'jQpSDjW4NTij[\M=oGRT5y^٤l[l o}Nk+HLM䵻:ݗߑ2PTݫ*^ׯ#j(C $K8BB]i %( KNR;LCJ`5$5I>hrr3вxq1OQkl̐AzmßpڝorlDw!|r9H*OGr~ 25ݦm<|տ%Q$Ypȇx뭏(ғzLd݊_ z-/@VT?h|hY<{,=h$nZWòLUCV5laԭ_/!EU]m|OJFXp!ָd&"`|A- wkRyG/q)GP2#}:fW?v:ăHNM0\0DZ<)7g3!ϫ ۯ?t GXYc3S&AdѺu庍7%(23U[ǫ{ Là :DB6m˻߱Sء CZN>]zbYP֭79DUЖ(W5j J;È#$sPn˶kCѡ@$EC7P2Zg'߿N _kXMiy9cll8v fӣ,WKXvD( PNy12\!C捯@h{3r۞+/sqk ɂ$ؼ5=]3edqŗlB!``C@͔9 G% q|̘~͗Ȋ -[Tȑ]c[h^/Ii,[0?qf0{Mi{ɤgsG@y+z™tzcq%Oq۳n*f̠m>|/S^8A_t΢U|A=[9ZOn^6&$!,UkH`9Y޶8]Жo}M5,(DU5@}FL=RdEne}6kU^FHLM4 $EAVUNV=s8 )hX4$+|ȊBCM} ϐnz_i>h _v;S$ ôNEI/bA=hߴIN$79(]&E+'uZ ͫpAneDk^W-e>rQE8A+]/?N 5Z!9-أ7uLq,U WaHжq`%=Q_O_w }ޏ|?W><^XWU^1WMax)Z*=ʮd$x@QUX\+%׶݋+P%5ݏczd $dŴտeƼ Oto<4 4֮'ę7¾GĴSᤫne7YrhK}P?Àd'(h߉\>y1:ߓO>5ULc&M$e>agG8k؍ IˆF)ړ N=/_lj֬`i.^ ڴih,|k-Q1C+È>GϵGR9ߺ/?/8-nz yOw^fp金*^gqi!ɮ}h;YXh!Y̴8)KB!VԄ)h 3fܕm/ $T)G8Hq@x*]6h$gbٶ7]$j(v4X1U|. TOZBо4u :B $~>>9 cce}#Ǯ斳,d@ttNfœFdyc HIrofHk8GBp ?OSc/Œ$a6eҥWQoGiï` M q5yzq7 9\/)YT4|)o='I{C"a$;cT ̇+4U´ K;SZH&S!ȳ/eJu.yi G--]7rX^1.wJء(Wtng߀XYǾǞDc]# IiXMnRl|t脬Q Xp.KrDS)ޱOTV-YH$3Ƕ7#m^%n\spy5?mZg-c?$ ;(&tޝ7?lG6%ZfP(BV# 9@6qbnW648nd(qUT g[A \w\{}&Ǻ-x}>~KBM :`(sD?s*v]Psyp LjG~Ͽ3k/+U<I׎ߺ٧I\qj \z%%r疧&oO[.TBMԮױ`z"^B)]#R~ IE=H ض8neafܓzV,dUq4b-<{m;#Q4Y?}NJs5 [IV[5IXUNz2kBF,JbJ6^ruwaYnHxioS R׸Bh^hSm /&%n "9Ց+֒ϧ݂ qF y8턃?q+WgbFb |"&Ngo !hx dю͟8B咕$fB,'mc?ۮňo8osq$(FeRZ)Vѿ_"laSZBӧ21 (D9촓HJN;L=g?\1;db| .ENvmnBQtFT@.fGrgPTV9W][>My,Yn}x@]1 7$/eI(w>J顤'k8Qkyֽ>n2X`za9푅qP_?OLcB:9p(a !Ga%YA%`۞pٺs4k7)i)0)"Rgw"a><RSF"X6(?)ŽDLbr*HNj/!˄.מ&9#<ܶe<5BNn/q-9xvp:"^F,Ҳ}T݇m٭6E̞0'jCN8 _R2I)d)qlJ  \>o=z%<~e8 q}.5Me ?)X̞c;I-d)65e}ئI,& ӆi\5/OHyjS>bX 6i."#B8wh )q}(9L 'a5Sn@ů1Kx }uؖ ~~G;cf:GVv:?L]7O^v ?pιAV\OqA6np(ݏɀګpu=3\"g _IϮt-K+2îaG#; J(vr,W[\G4q/`Sc߾;nࡱӰa5[{h8#i^8 i,ZK )t ;IO٭W6MCJČˆc:dQfСc)V Bq5W~j:?r-Yi*Dl OOᱷ#g|S5MSx~"aG9dX{2Ӗqp]/>F[4M )u:-ӎ7>CzH47W.Q}7,sq|YXfPxE^_aMd5ꮦŽO$Iu.W݉o/!uKDӥ.?Y T)r'11p)1/$!/}g>X8WaD#"pD ŇVUqK,.hE]qr寓˜r=x|~r]㜜Ag^B4Ĉ+j9NKi*2A3%9x1vUR RRLX"2T6GN $@‹❏gr}/#2)I %U5ɺzSF ? " AdEqI5a?Ow=OѯSֳŻA^OayWfMtܿ'XK>+&`]ta#ں8ٍ!Zr-  q `9ܶ ^%2=sfAjsi4n{ۓGv^ܙ7^yfg晕D0,_*9,=~4`0 2}@B].dc# $Y6H2Umn%p,!$dEu5%2AR[V((/ˆ8E"(2ئzZY۶Zu$T\mF[gn,4^lKCq_-[M U1LD/7_}:Uoq}ILqGW?{؃hKvxXҨ[_#h2KBqGRz}dمÆիH6Ɍ7p(a`|؝Opp'Pӄ}:0~۴!5N?,ҸB! on7O_'-}i)\rL>5b2 k<=:P_yuIb_V˚B:şw؃K&E\%P$n}r> [GJ 1t`'#0_Ї^x|BHldkdr6{Zww5OYKе, 474wZ Gљ>K:D$̊yқI_/NG0qi${:2>z)Rs غr1ˍ0-eR)=t.:j4*Et;32òR~PQY&)-+E󖱾\qh4i6 {} -$21k)v=ޱBCh^.H֣(/kaٹۇ쒣db? ?8OA-gY/䑧su#>0lM8<[@v+|yk*:2"/ɪgs(̒ gt_í,:ڂakф>⠹֚a2:rm9%;VW_Z$3'vUTN;R_.f3+((ϚOEUPNg),~EtȊJ{qKO#W +{w S;IHuvnZ?]U&&_Off*/$䯮cO#;7ߏ>4 H1LSc߻?UW"}ndp/~OZ^U]2q?}>~Sy7VQ1{㮟^[dAy5.:{6ٹ鄂!r ?5iZEh&5;!Q`ٻBbR}S$RDGTVUCșHRJ:nS#>e[ T79Xi-& L``–1Q_~8`$?Gx8xģK祏e Ex=w.qX]i>ժ/IyBZ X*ƹٳ8y$y`9qeY 8^h %@C-䩧rsp=y3wQ!pdj1:-ِհa ␑0,D$LaX8݌*ycJmCAF(ekZ:u K6/\+ʊ_cdkoWatrօdv}SμQsN$| x!;+h!13S'>%UIF~ϼؤ8ZkX:D2r֏I7Lgזl_P7> 2t2s'\z`>K >9_+.o|/هIV)4SNДdNK2-&;%SK"&MK_rpΩ3 `, E=9ϏSڏޣ'Š^c݂ŠI~xv֏ywp{`'SB|B–:pz<:)Dfw� 4j _yhI3LI*|8aNYYɲ]]z )K~(ԛX_sSJz 98 [X~8ܬY]ǟ_mF_|:߭iUU`J savG3IJ@*F[[3hdBkSVՐa L>(sp:佁JeM2>{xv[h!?[7(*u)P.ܞ}IV 8<^;;1MČ\B o|jW7yg2kPNbP.tt`&no,  t㉍0tB~SWL\w;D$I"%3.L:ڈMI@q0 #"q"e)?>{)cib5"י25MWRoƑ,#7{q㛟[c`a'LP;%YhӘZ38E F̞eVUxd_RTn̖R2jh+{C7 _G(]#BEBw&LMpNфH~5[,hMJg U~MvtZQEiI,;۰p%xSf~BGu'H:G'/{v7: u UWM`|S$fS2l.O NZn!hZol"%ơ88j>)^ýr|_i!93q'%#*k?yʆO`J߱SAR0 a%xpyʐ(6ČZL:b^vT^1xډP ), EQPU,]$X*hZ||]t2Z/  :Y;'&1tL:>i<J2蓙F@rRqqx<^sNG$\70]ʱbm5M~Wڜth?|-XaM)G`^LF@Vnzy'*_ÍЍӿU$_-Wq B/n#Pib(= (IȊDCβMM(DrWe mkل&IZ\N t8 2-zp$0zY!hnxX%&)#?EFA ^{vWD 75M|jL;*ZkH ׋Y^o[ ۄnYh݅k$ga! 4^sDX iYzhg=5e0NLiߍi/H= ׇ}ϾW]rqh(aY/lw7ގ-x7˕^a# w젡hFw0"SQ黌u6d O߶c rL.i{pCwK71nAdT^Xugdiu{2Z0POrso$)!"Iv DZzJ>xn(EC&RP!+ٽmvʳ8'fb4egAakr*_ƞq'LC|!U똀8Uغn-24.k=oƭ- >i&/SجS8'ǍK-¶`hgɏ.$IľU;Uf)S¥@LKGR 0MLa+03@nj$HE PK!%="&)@">-N^y>nMJE"%ETEHh`ؔ $/YpTX&8>=v?m-ȤOr"=Ga}4kF 8`NF^twu_~E'NK. 6[#Fb*[>7Bף%Em fϘoۼ{'~t_=Пr8$IQIw/*+[08t4AQXذlBoj(.'n~V~JnC :+blw˟Oi[ev2>FO)82cv~^kiSZ|PUIGdss;75s\O>(5 chk K0yXqmtLx}յ>zٔ$2 ݛRԻW9DIDAT/S5pGofTuw/Oul`jZKX$B%kB )vEc$c%)/ϑ$C2qyc޶~Lfɧ!NO?4!73Bۓ^YCSC=s.)e}jJ[qqɊVZEJb,9=Y!gS.-cyAS tzƣ#w.%IBt2(âg\ۦmG떭yK,˄B<͝W_u~?z,"dW Srq%#@7 كݝ n'tMkR#wƝsE8UM Gk R 7J ~m*i#MW@>]NL &KM(j?,oWQӣ-3kt2Yl֢s~5mŁ5}W:ןꓧpFgxBh5VXɐexd;r}ntCqQ/z̴YsYW:h8F(2^/uDwHECVn&z{iA@>L,%dNv3uHd){hײ# .b,fg!,EZZ& $778GY 8 [* eŁfU-Y2M{YX U]P - wFg¿}dMHŒm>0WjwDu:1-KmGa3MGVmvbX?z5͙kjEFUUE!1!o>}P|5;|<ܛrLq߁6UGg-&O6/x Eҵض}zeo !8lضԴ,JK1 gz2ηʖe P=ôWʒ, Z4z_ ]ٞC:& ճ`P'&![+&q =J$Z`"$Xۊ&9iīc?sl}! <*$ pM IbQ]|[ʪMʹʽH!xX4$Cqĸ)zl;[!9#`j ىIbB=!߽H[VT@Eg=5|؝0ytOzݻwX{3OK'ڛuOU⃧gBNns`d߰qz~%Ѓ}02lEIYoN'7ofv\v8u,>9_|!3ddaՖ Rӝ&ufr[SeBA ŵwC:_ݿM簾i dTx]\!wIjZ v ѱ|0Ȓ[ܴ0}[82Jq8BYِ1ZNe,IͤYMgنvPSXV_IVNvd7+kaa ܸq(7BV@qv$ qi'2ahWHe4ç|9< o6&e3{}_u]Xy͈T˲Rb&SDn͎+pxb0-; [~s2XE|Lna!3gM,P<7,sϰ 2FȊL /|__qX@Xc6Ǘ@s-,-ㆻctwc2@U:ۻ8W"#eR'2Lt"6MZ|&N/ .`LmGl6O51|L)uF`L}w)(."pxB!46VWMݖ5t!92gb:k*;P8ܺu+?ysgq޹",[P?_߁eҤI 89r 9L| s镛Ң\N'u4u4h $&&FTZޛ#|Rz e,69pLB9 CC7.0!d2?VR_[GJK:dY& r;-w>?!! /z²] OViL$Y9, mcdΙW6>077S^#jaIQU'Ok57;y'?VDaˌ4Kc7p:8N?$O:$뮻ꪫ0`@K*!}&ƎFFN~}D {^VoW|$JȉQ۷5 !p8n]ǪGwc:%:T4΅Ƚ#am!ni"mzQCkN̻~Rе=J=~F<#Vf9r4-r8f2P2`k^'6eɀƐ>nToQ҉KN;ħ6s0u,;Iq;Y#y]"*(ep8\BA ƸB&ݕd2 @1߉?YeHRiX%AnaXᥳ&lIEhQe -þ;zDGxmˠJVlZEQr,ˏ %&, WlK_OЫ8SXPd !$}"> *++QKW%'#ܬ4LÈ6YQ:hhQZZ9=狗R%lg,];$A^((Ӱo(FӯI)d)!,@W]"!;\\h$( BVHkNN;0PTeh IFVð݈(ib@aKX{${1 dY2 H"Yqb^A^1%%YBAYA,{]Ab<ͤ_Zr o- "OLևs\E?qyPa._iοrm2hm!$*.e ɇƂwp0n,FO&?LvQv͕X V/N=7;C=4-DZN+cFI P2.?ުaKH6CdŬH%S<!@V?w?]84Q|VaB )p;,v_+^v([MP*/oYEEEɲa],bhjy.-;vaࢰ0 ׎w}!CqsNd̄w↟,&.1lJFM#8fX8].8)Gݸ1a޸Pw'5Ww\qI,{ILCcܳI/!Ŧ_b #&gwmr3} yec*KƕE)ȒDGc _z(йgw(VR>>xҁdeuѻAkid՛oka,8[B/7?!l^ᱠY]`u 9EQCq_ɻn&\2)C+sC'[vu4p.?ښC7r;z C/`òŤ.>dL>fK|`cjX,w8BplAtM æ&K\x}cYJe:46#KR*D2?29 wSm;EyA+8IPn@umN(x8  ~('@ {\υ$+A?wndI j:^~_\ K0M35̨awO:ÌH`aHN@U-U$fO;{;>>n)ӦGfni55iko㭇qoFq11vI y:XC8z G,IFrf> 9~>!>q/]qxIQ:\>}>Hb؉w?)biA|ĽS&}71xVf^vmլ}%L:X$gм{+4οC[n>xNLKN|%0L ~!II\~Y佩QK0æk 2Fay9W. 9U_'MBnY6+A3BN.x(?@M͉S_Mű_1O178fϙroL$I4;6dTo(Qz Ygf\.'|K0?%26?*c[厫1eXRXKǨ9LsζKPi4-Z0MM۩ݺd%JFms8+ ٹƪ $E o;,fX( 5ް$Gv{ێ_汶e XO p|ma#[m'dptcNʓ'OfԩH0^EE3eWrZ˞k )?p_2 -"I -M,oٽe-H}vV-MK>d(ZdYvj4-DljØ3 >--k@LR*?Qg\Fbv>l[d͙9gZPΦBv@mpVe TO A_r`܌ tTGȪ =?ǗҔ!,7|>`q/6!n0WYOsS+11M:dE$1=%?IR [XΘX~>t 3qǣ*?}ڝ|ch~ǪdՁ ,Չ`8F$%p'$W05㯻`wgn/a`V IQ&Wغ]N L33&ߥvJf_OVӰ7ߖi{  T_)S': 0 !p8(l^4SGAI8["RY\{&{ֳzM&Q0eQLaa٢$0M+>Eu^1H1qt5Ѹ®$)('fo F;f*7!d D74 C05:[$p{lCSV$Łd$UeOf|mM(./P\^|M4VU ;vLYDRd8|-4TnYAV̰vl V 3ocp :JеڈI'W_MCCgΜ9B!>3yufDUF|Dz:t;Þv:v7 j: YѾ iy ;6_f**W/n,ah~i?p EVR I.z;qi٨n7x,aua $ =@5LaVx-pTnfo7ٸOˡu_iVm14chض2ܱ 363b:oiv(Dz fن!&  dV,QG 8r ݑx2luHJvp9c񇼴q '3WNg䤡,x}n84z0ta<^.Z#+2Eo1N'))n_;O˳MqnLnG6:{߱Z(Dɬ}߄py+&#?5M `7p{lll8*>{!˴ڊnu>D:vS8|"gʚ7_#t/#69 ˲c#LBqߺ%(gOޓNX^)<5;kHk kiıcrsx8q" ,`͚5L2ZXj3M珦I.+V .Ӣ:,\OwY*f۔|ւ2J2߳+HLI-샐d :;1f$$fb?a͛ϰqxx҈K˦|\ ]dq:= C({ b׳cGa1k4a:r*Izq?Fv مtaӇ" _Cv?6:;,&)}S2qyp9 =d,Wif8@HHr7O~PȥFYvĢzOJrS{' u'&V/]E?ļsȼ3N삭vsΩ'2Sp;]NWg]]]t8t.x瓑_UZ[;2gM06vpmR/D V-P  Hh JXrCcȲ]P?-;p,CWa!I |?p:BľU8TM HV$7,'HܮO,yTͫ1\+[Ys:Jͻfݻ/0ԋپ#8YcNلq&o'l_1.vld O_7S>Dvk!$5~Fq%]SrEQ:~6;~HJA9Ӄ82zB&< _MB0a&Lpڻ?"æMh)v}Ko .!g`W i]ioogVHHH@Qˋ7}} w{+2`\[iAJ0PZ4 =DvȒB(!(=uwO04s|/57GLSg?2tt]ߌS]>s.k:}_'f?xp%u I2fIٸ +n.K%glԴ蹭-ͬ](|kn 4<˛88 _rJ`Y{Ӵ$Z(HVd$|",bȼ{ض}w3G7 cδ(n̈́QW>c`8UAK0me#|6FL <;ERvn# g&++tځnO,f%6>o!$f_\H=Znjߛ$a ƣi!@ т,4M{H0A=kFxK;:%m6ѐ|>dA( B5HDe.$YMDIXǃcR(FnA6R\*+>KbXdJ*l۴^O ]lݴ>{~~5|iHDww77t#'Ν rss,ʔ)S),(_eXB)sα˹`U3AQ.:FyQq gr/<W6ׁwT drC mloOON.nBY}CA_6t݇H2*s}mx=}PRLn\NAA a:ݴȤEbV%XVcO-n NRn1yC,{> }] t!95Qe tAXBG.t]GX&ͻޫfހ“Blt4JL0~bh`4ڎ79ҁĦ?ZwB z(xhc"NJ[EIyrW$3-4L`wC3 ",S]]g}aҤI~QA\;77[n%Kxg7nk׮SO=5g&ƎSWcppm~D(of#&#ABqL= dd%,"=IH$ƬHZ@~=Ƥ.73ʖ#Lz /ؗYQ^@,S>inǰ ǤP#%xH5V3|nZi2DeᒅL3u9w?)}]]]7SO=tx])**o7+7%\@B`vꩧpٵ7Ҹ4tG [ׯ$5#١s4?YbZ>$$'þLh9eT(Yf3f!P}ʲ2ɋϷ fMqjtleH&p(+B*@uZ.oN4tRW\1Θ86H{NƝw+^|F:vĒ;p,W;^CjQ*~Ȭ4w  Ϸkߊ7﹒O\9v2IEyʖEr^IO@:4WUɣFhȬMi~祌:ڰKpcR/ |;b8TDu).!51P pPuͭ> omƉ'0{쯌.//9s搐@ @4``vֱ፧0p&2ʻLl\<,Gm!ro%XXFޠLW#Y(+*`'@q8(k]q}Gye=ˏ~pL e^mgH64/h, e*?=%`Ʒ@²(̿)gcf4?/##NJEVʆa( ջwsgp饗F;vTq{&%%㥹 4HY߭s2N+MGۡVUH(lAIBX&ޘXNݕk1}J%nDiMH2RPWQ.0,7J[V0C~r'CPN̿2whoaNV@귬!9!nfRn}n?ҋw3t, @9g_+&7[#)% `7kdEeԂVN0`ҋlĐ#)34P4r*ٽ`jܭUd# `V-78ԔiȜRYYI]] g=T+`uEmBVN.|>nhptD=O4-r,ˬ]7˟}a^2F,`dB]Q;굋X?0hdc9قe$"W!8 v,]#&9a]혺'>)Lyd9R1+%IB,瓿&RSIAA*fЀAXջ8taeE!رq#z*{&X#L@+VyEϿ '0Mtt7T=ןF[zMB ёm-8  Ր9sI>EMFyF /{HNl%"hr֜|2$ af1 P$ 4Ma`ؗIJ K+`΋ 2aI&X,Hvva!b;9q bdUEe[3_$2gcB$2l5;n2H) %lۊO^ep!݁t e "\u^ӻYEA6!eLd- I^L1,~ R[+xW>bZÎ5D+HOq.B!NfnW JIIesԁ_vNDB%\Œ30N?oucّ',VXA3S1 Ӷtj7m =@8e㛘v%I:Ԕ5"NҒ :I"8nZk+YjCv8ٵv!MUvTGf@ԲsҲhز;hضuwkm l[вؔt@WEpj`̐Gh>7an0}TM]m=ٹvըo B0B{/(^"n>/Jب(2Xf͚|]D?gJKKy8쳩dK~]pBVu9k@B8eId6Ē8T C\ fgBAо&lKŽm]4#- ?߱+؄p{4TUDi~]aWu5[*xb<$ p:n/e|͞q{{;D_La ap$ًOI;<$ iJZr6<}Q:8FNj]|س_3`i*g~{DȩxS0tUaIFi|4n]Ǥ0I2HB`ZРl߀\0,Mr2d.mBaq7%, ozڍyq_ `h٧CJƍyר#99 €kNYݻ7v ,_EKo$95_gY 3YScBwSQ1lit6/4$FjVԡ.*OC3aK2B ,rr5Y8'?4~ySןIFNnqymኡqL-do\΀Τ>Cvҏ$׶= lMt4Ԑ^ǃ Qv!$ *U[!WLAaNBz6ٽ0u ˍع3.مᚹ6" WL<6dYoB 궬²LR QN01j$IYc\y.3tch!*U$ƽבZXFlR*c/Ӌ굋(3=K`{/0񂛨^/?AZQ:<4 *>{qg_v#LaYxbYw~ϰr*N~}tp8mlaL>s(;9r$>˗/痿%se^U׭(A?e9'\5۴g\Nv!bm\X^+RnkaQ]n&]pYLWl].U?!>=~뗒_J٘Zж~}\ʀ=AyeXa`˧o݇s|HHX$.L? Ug̘1 0ӧg^{Z/IR@ELL,*G~96Qx]m!XYTى7]#w YƖ B dd4|"|8ɠa{FXFc,|APIUȶ/SRU`+=x<4Wmf'aGRHWg&,οMgZg[vQC2_[#$vudCK(.’UQnFyH׍WEEEL81eeeR"~* mmUY,Z@G36&!0B~-|S vl%Γ1{jG)*qhs/eM"&?ne LrR,߈`ʴC-J `ђeHK}a wҞy̲,f_}K=W~EQhingg;ߡNXvWcJ&vɊ*z7,@Z= FѰ1,rOktT^eh` lu$ #DɊBj~.FemMLJ~ .㮺13X3Hu-⍏zI)!;Y,]2 P]n fY1K?"c:)9v>uؙ>2Fq)%X?6I.7⤱#0_ ( XA*&?\4PeO¢vIoO% (~;Qb*("˨ݯ2bϿJ}M+vTȹJ#2WB4L✔M3XB`TvlٌidԘxL O_tNu3wDpjp D:fWW{Xe~)'}=s;~C6g6]@Farlۼ¼~G \*UeQPah {I/+"~: C@'F4L}'HRfz4Fr!={qj&%sgM8Lܱ z"MTQtwdkw ^%Mj1Gד-%i? %ֺ]d!M E`/yhN$dd3⎉pybI) !-^}0BS8ۈMJAX&_sI8nN-!$lLҳqS2z5ĥf0 :I. CA$Bs)9ǟNJn/INrglz 2Ͼ#wp!(Gאe -Hɐ}Ւ! 5kג@I\,C*Ce]63a#].IhGZ[[9餓Xh!|U]'^NѓPNt-c#a@>{!%Y"4(ݛW|U5@* =Zٴn-ӎH$ii9\y˭=Է Ѻ= 4XGrΞ#G$..]v_wyM7cջYz5IY\p5anͶiiɗҾtw(H@et궭f`/h~J`iR: n÷hejħgG8|@Vdr ԂXJбiA INZa+!{  u 2LbSЃn7YeEVi?LCCvƠ٧#, ߍiH/*#01 /Ԃ2PI(郩zp^ V =[}#D!0 7Ye#XYɵY2Ol5KV0x"AzFٹ9X"JbEحituk{%o.g^71NY搒L|B<^Yٳyfr7XWۏ`pߑd@e2C,Mǀ@'7Ե@NJA;!x!t۟mm6!a ;WoU$YK@w S80f0ݰӻ=h#Kﰟ24 z$f2›pt6=;_e"к;>,cB'r&,K[}waPd6߇ofH \a"|΀N9ÿ 5+N9hpw-D".m۶kg<եY@붑spϲ,C_qSnx¾ }v >۱YPS4e@qxI~2Xfܼ&}~TŅi}3-2rN("px~7d 7}:nuulX%[6n!9N G{]3CB@hXJ/Lն~7|N4Gya!T/>yO %tgkGk-zp찯 Xẳ==ߙxi*2zs:NoI/!&voy?چ6f>I0'.4;X&NC]|$ ] AyyDeW?G(ZH'+'9;MU Re6oQCZ/9 0M'2"C:ڳ'd^,l]q#(ۢ"|kw+CQF;A.x0 MK?qj|U$旒[DZNh?z0x|ml^)m;xH՗~xcaAׇW3_>=tҗRB.d޲4 ؅qZکohz{~sW_{_iמm|+K^V"73tL=RP6m QVb)bۖ-߱e6n-_ i=rrV>̞SU4:jٸxnJa)? EUp8|س-MKC=457r 1RMeԉg PnNge-f.cQ:vwc5W2lT N%VN3 _p9+6! 4t,!'+_}E7(+]!OyÏzcIJI:6nXGSS+w;~xpp,͛7Skϋ/tѿW.MAtBBdN0aұlp&~r‚Cx}BUU,C=8Q M{INIFQᔩVIRп47BC3Ԝl!EAYړ:v7/=6+~=FK0bsڎoݧ s)_8opBQN{C=ZЏ"!5o|"8ߔ5Kᠵ8Oa^&n^E\ '2yqw 9!ӴhQMew)C\B-wv iwkDQ߁3TPh %H įH]+X O\`jJ{_׿1ٵV>z 6]5ǔIyoP]kEL\e",y՗ɏOb`b5;1ht.:-~ (TL$di>¶~$Ih!2|}EI$wvl#3;M;61(Py=}878ZbUE'F37,ܱq,5p-aY %lӡi簫jVg9GG6Ja+=->d_ *$JJǕK3Iηñ(,PioM80@ >?3hHp@ZH bҘǼo!&.L32HMM'.. ä:*l߱  Yj.'\A~Y=er{qy`w8dJ`3g,)71Qo&9whp8!Phih0tFvvQګaL* !IHodYT}xB0 ;Pm/ޥ\{=:{Ii|彙8y ՗gw%C_Q[ILNG,S첲Oe2SLզ?g0M0-a/kg ݦ M+@n;vͰyѥ$L@UlJ}^Յoh4R<7WqC+HJg$hB 1.IQwh_j0K8U4U'Ս Ti54^,/nըm ]!2t4 }2ٔOMG/hhJ]_r7E1N}KeM'Ea(Bvdk_mWɓ8"\wSO=e]FzzztEܞbcc;ڇYNh:ؤX@"&1$@QTnObzNtA<\Oh|I،ykT4$ፋ%i/fZu(Dnv* I |V*ꃡ@R0&- Z]ddg9h,K!`eE[B wFa}ϺBH2ܪIG KHB"`::L7M]KcY#N_ !ؾ;l 2sr0cTQqY$#Y!3Vc)&_@؋mSa y]]Q滶kvG\\ _Wez޼o_^{9sO:9ߜs9"U$IG̙3( e_hYQxӧSMwO<ÿ+7;h4eǡ&CTJks#$,ؠ o>IPYLLTEA>2NB`lI{-BJuuKJfV4 i&ɖ@XCNظX/}wA(!!Ex.TDe/IHpȥ Ӓ  vKpi i]Et$LmrOn& nL`ź'3&XBFqNjqYgwdE"TmZ! kYɟo 1eXx]\ŖEq=,:* h`{w лwo~߲h"N?tN'\pw}7//III$55{ EQx9r$o%\BVV]tswG̖%3[hB*uī)aDH y{<HJs_VUa}ERb }T[N榀Á%( < Rmwj.o3Y!Ko924^ /{ڄ Ų, -ttCڻ}*EQlѻC taciE[]9 et5X_޾X۲,ȅ^Ȟ={x)**bȐ! :)Sor璚{xXz5gٲe< 83n8ƌC9{6na{G+6$FŒDT&8}뻂"E )#4mtjƉNn^VO$eqG=ILV4-@qAX|5G2ф%ITg^v409~m㔔jsb\nOSq1ʶ ۤ42S׉ kŀBxG];p !+I~t|mtIͲ]0SRd#'99 UU4_D8%==Ec-ZDQQGf̜9W^y-[tR"));/y{1h ̼yOq0! UuXqqXb>$4Wm!?' [>աR[H"#3L>zbTLC}S0AÞv*;,K{GS=H^ e˴pez $И0æիF$kP[e䣞((&k rC:dWyr:qĺ]Fdž߰/۷|L ҥKYr%[laƎKss3HDLL ׯqQSSCyy9cƌى먪J0#2NkND3e$' ucb LlrK2Z(DQ~z !UjW=R\1q1`?J n)++ H;j 9Ĵ4,k_ Es.: )I`aᠺ?^SL#Z {$} cj-Ђz R[^E4s,.ըҴP6$QO٩AҲhբI}O#K_yOW#%Y sbb|!* ##S' 2)))q|>>fя~[oq' y衇eqqq1w\cYUHznNw$'6;; ¾޽{?9E]cn迏?GŨQp!]| ~|&|yW^NgKdKѴ ނШ_{ NAb|>U I $̍/.'m;R!73,˘ΆF2 FlKqfhMmMor _o۴iB& 7Yْ,y8#Y%N>hthk#P-۰cw7\vnL] /}}]s;DjjȌщb\?u0:_(ל"8 ̡lq 9JO'# !x5f'X\62HAv}M5Ueld Dzi :}mV <3dGc_b-*űg^ j$chUe {! mXG- ߋ}bJe0nD9퓌+u>i`üE zgCc`6&sk%1H],[߮Q)Gk ޜ}\q\Z(,!e2L| esހP5,<~)TFw"%UE7QP\r jJ2y'ɆsϾӯz/c<2x `?K.z+҉K#}u'g#hg" ~~򸖵v>9qspp}x+%RpTp͝j4I$ulڸ֭k)QJ"FȟUL%*}rXClo%TfL(_ EA;Z)X|z0m=I4ȊIKI;@A^+<"4ad'9:$O_CE"4x=JLja6{wȴF*C(oVfׂw#2;/'~k^(XeGm݉嗽 1θDV~I>[jBX5"vqEQ[o>ڊ$ /󶷽[o3!am:SOկ~˲- ˶ַɚk]qtzo 4 L CGu ]), =v_>stl$tT*+WB=BhL(.8IJx4|^q} Z;zL4ģ o IeeM_pf"CʒyqE6L:{QP3@LIDjj1RB`P0^$ʸ䦑f,]W>(B2߶eY ; TL7EL \r-9yh[[TMKQPYKgcS5=*i0o'˖,q5˞ tٖ55Uo>:?яضm?d ̦a( `۶,yY:;;'Ee8i$ul4LTMK:әnJNIx=^Hxz a%)q9(K)Q}vvh^EwťG>PPLjLR)qM(:19W`ք_8p3*]yi3uHix4"IA1W^@䵙Η*@AN_C8vcJL3qZi!upʼ^1zR؈(B]"1t"7p;) ؠc5\6񑱗^SN2FEF=˲-#2qkmxnrrr??7 ˝w =47XC'VZMs⽬K  "w{M7cy{'?'O~ >1{zXn4sT[F^8r1d*JQ~eO%-ǿ'nyqd1SU,Cs0F}IDLPxRw1؇McǮvBCO%/f,!%'#=̨Za^O㒭FwNwa~.e`rR%t"EPZmػN.}үYI^~҆Ŭeّ -[`Y΋ߨ' ZwUWr6ʩ#۱p'KQT}E{PU9Jj!ҙUaic002X4/x<ε^]>000P^T*F0MttD"o'>q>OO|M7;{yLee%w臨b~_Xd MMM{9XE,:F" 2ƉĢ1R$,IQM$Tױn ]3lٱ<竪X]Pt2jS $>doS]Q슆dnMǾnxTNO(3NQA^&=45aF'/*ȡ0ۚ D4I8>1C9c8$&+epI* xa(`Y1'G`65=,:T Zobfa sHM0KL8K:%AUdmbEWSP@lt UyϏ2ߏiu_-0$ԺgaprOr`&T ˶1Md"Pf^/xB.Rk]$ y:Gm۶M8;cT DZ5kxUJ_?z:宊qP&ڎDJϭ'g F*Aį 'X!%/o!$;vwpfr-%J7Έ*#m-dg),4wbYH]uCJnlp0-Ŵ_EJ@U"O#%edCX'-z c?k"( 뒆yz{b tu^(vaъef[tBQC-;' f^w0QGl=KܞU5L BB0[{p^!ο=FU#PT[X4F:"HiX i?`Bjg>) =TW{nrrs@|l06e٨F2$ Q__R q)̳"󎫯&Lq뭷0 dޞ^ƢQtiAxUصv -=;BUus#_}!d6U 2{zP#dEXF JPBc} `tefK\ѐ= [^NŶ(Ёv*~d=- ikvWU[2 =n_nTxUĤIGLݤ OA[:-IQ;YvڲinTAJ硯wt r_zszLW8#@68rI!%3yL +u8sϺ}gil cfD0mTE5k#"?H$xǹkI&Dc182Ln۲PUX,(==nt#ȍ7a"Y@}~֯_0Ѩu6#8(I.YMcc H$XPWC{({v|?>2O`*Q~FT,f|| dJӱo75@Vq׋9vM(fXqbb%ރ _euE 'v4Bd2?]\_7͎AETD~}MepO0kil睙韕*8QsǶƿ[qvnLҺޟhC)\EQI>n&#!ئBE,tNClӠ|f=OyEw͵0:661RL$Kׇ>D:귿z. fusbBK&S| FGF@#.YPUU(<p<( *0 TE% zm)Q5zF,./Dzqk/ɤӏLPv[,frg4Rp-5ؾyTU]W,U! fcCA\# k)act{ƾKhz5Q2œ9vw%8{8TWQRRBaQ>2#166:##$3!>!x44*} &m[AбmT"(x òlqW, "Ȥ^ thB@:Ʊmt]4܉ix[@dt~U56qeڇ{@Jף?1kfUjŧұw%Dbc eDQ=(óM۹G^?gC2FQeԅ`ۯU߲fM &ϖi06:=} `8PV99(tA,DQUHƱmTM#i8M,e,BLf6aӉa6Cn~!ΙTxiHDIئI4:J &+'Bu}0|ھ/U(؎ÍhԭO[e&ϬN|, UUEdi3W<}bPFgWiaь2|xB:JlO42hBP]UJW #QEq+B7qu?FW p.ydS}u O(~eȴtۭ\kZ|ΝxZ_eM)я #%OMKWPUE|,v(~ !-ŷ73W,Lu~57c$ .MQ?9R mtw6-{1.[Ni (`8Hv.^_Ѕ ӉmVG ʯ2eۄ9TFmƆeݻ8hhm_w7Qރ89(U,;mDHf*3. H%$QU+%ٸuZ0咛n<D,cA+BuwaXeeADpg٨؎%E2tS^ :mrqP}y9Zۻim>=ӛҗIqa.-CSC5TZHffxqJd: BH&oq0LҊRF=Ei *ms-v؍q>(Ctl۟[Ovi iNN:kf󭿧 pPfZGQl݋yEyBSiƆS h^%AaiҴE~y]|?G4Mv빆I<&6bpȤ-;ط[+,*.`ig̣3/vgH[8 uHGÒxnތRbYs;6vu܁Á[S8_7 «>B\fVS=z~U(XMv ~c$GSep[]ee1PUEQUN2BX6«ÿNcoBYGN+8CAq啴lZO ;och0AmC[ j۲#d4Cf<'66p / EQ ʲʍ?Y3*w,QUsh{< 6]ThȐE! 's>*e4k1YM0&J)QUx"Mlb8j!˦pӲ__; g_ua,P^U';odH,dS8I1e,k@^BV |Ôg1N=Qظ{Hi#y5eWRK--Ƕ݁O pl`$+)3ŁFyP_r)9%yxbx)XC]lw02HN=4[@ݤ653I z!.Ua_[7BY>lۛ{{:j9LTB4L )s< މ#o =U2dJʁ~@al8kB&eZe.kf(xkMgA(P_a˺W$"m+u z @?`FlqJ1~R^ $>7>0i/hM`Ml]0[u'N꫟;W1V Wa&SS: )'Mk2,9Rՠy٬ۖq%|qϥe&҆j{HZad0s+#^c$}a'lU?L~$l?wC2( R7?\UMBXUPՃBQS (B˦-5g;64i"#cشچZYzwMa)H5T"J(Mw(K&\Bۯэ'K(+4]U1سm+!|=#x>x1*j&T)twtP^x\i8CO![ڎQ\K$+5 &gjTi#M5^A0$Mo$P);a% $=Ѕ(MAp׻;DɯMNnF8QA1MeLh6 iмxh@tptM*~juɌp i݂#ٻu욢oF(`ِNȍϤY(D.eDs.iLŭ'u0 ;mM;M;WWbd5Cs?U兙ә +2t5Dǡ* HOqz"4)J**3Sik2(ueYDvU>1W Xx>Vc>{7fұX@ W7$|}kE q&H!C87w#>?FFYiGuGqYEں ǁ9Kb&v~\BSZB4uAnִQF2*k0)TB}yN -`Yߗ R?M^#>nX0wv}8$·m_ϟ?M0!7'Bym-;6g…$ƢuQ5O۞] a֜yƢodeމǂ mY$i'P4{O8-{hJ4`$nRY3{oj#rlݱ%- }#I<0, eգ02/BAa19=ӁlPBma,fAҦDS}.IV ī)޾0a|Dl`|" qOi.W>J#7v|*}ܼξsHW6Opplw Gգ6%$ώV~u#QK2{"FGGI4/\ֵk@ 8ж=mh^uO=NQi)@mƱ=K"0 KO)V:Zi:I)0>J74<C~Q1]Y}U?V~O` ^HV )I0+!_8w@ρ.* ʼ>82*J DZ'e>rKx9h2r5 â,%%zMLog I;nPezf:xC|v/G5ɬ+z[>7zTZ"99H)hu`۱xO'o0C2j#U +`[xB558y,}n5iF_ x9x1 tDi`4`h$HtXg`_8HtUh= 5L3*ExxM: j‘~B^ˁziU,Y/PwݽSv{-`\Swdxcx/x5H^bX*k+0=f!%m M%Qཬ{j HpOC*q꾓R("fuu "-ڙ$XEie5>}v1r`l8E]S3C {zgfc bשDE|A\e`x+++D^NU>+F  "SnkCY^޲b[slCؽyF"TȦPrrkA^NS7&p4l$` /41 iM#鹧YrB^ge˚gRTVuk9өf疍b%}JQXjAQŕq .2#\0q,B(Xe+gז@0Ⱦ];c^L촁 ~ ʫ11}dltRg_o~5,;4>_To EEySf)Dhwq˽O;ȥg so8wqJ'MUR|R۱oWnENnlPa(M7΂Z5VRƋB0,v;h7{|aPCWwBQZi V k8+΍mr=#;']P{]ܗ`/)PW=JM2e=fR zh=;Eu.fx48̚=s{nOp"@Fx5%4LgT}_|Sw\|Fl``$Faiڛ  2A݌rT$PVZinjn%;vb[6sU,=,Z6etbQ4OIH޳m$:lنPlI2[eW;i͟{]7蟲1FJՏ?H$'c s5 KOa>@7hqУ(BWNFSnvA ɴŞO1 8DJP* :FB̚38q{-bΊS:耗nMۈzT촍%r{| B0$^@ZJL D( s/eRYuͬ} + ܴkf<?ȌYlX('/[kOiWBY\x K}/o{ӹؕR d2-@JTMб͈< LX'G M3f-H6XH$|$'d<"pV55 >c\~ 7¼lmك?/~Yy8kOMxjvyh+AUh#P?-2Ӊt2,laf, cn]<Տ1d~]!C],\0d>Ӈ1q'[5툡+)+/4 WPDWз FNWw+lK>/BQ~6Ap0n57eAnl7ctGJP_HSٺcIQ2{V3u2(F}Fc.YBz_M sF-[D]S3{s2T=][г* xd?zh6O2n[g K-I[`6+xl b'BOn}FӼ4-Xm[h^|J+ؼ9θ|[Clgsоg3gg梷T:(>/*z8\2X ;'v3 {[5'BDcI7ס'8$,Ǧ'+hݶ zpo*qκ}˖s\!7,MU@Q 2/esio޼xu(HTE9 M-%q}*A:eR;k;ҶguM4[ȳ=2M8Mٹe3 )yhKNJ+0WN)xeHyN[~\ǩXb(c[6K2ֻg.Uade.& [wg)0o\:8} /+?RDQi7\pFS pq3 ^h?z?,GYq>e ,?+yoŊS3gvs\JJ7W.*TMetdh!˚=x]e4.\ȽyޟLCg\d=Wb:2pl`C';|RyTV4U% dXE9$J>5qxR)wy{?H…86h2RSH2c;S/"C_ ^gԓwo cD 㠩 ZG޽wEPMPNSƎMKLGyΙ|}gdhTUs\?ˮ훹_6,?ɤ"t,!/˛BQQ^e²Vr(öN2G(ထN4`(>Rx}/a@ Q9G>JJ~Î@)J=qχt~?lݰ}%Wj<>b.sYRSUF*A^JN[FȊ^IѧWr[ ޯUl߰*kgc:z`)vy,\ G8; lzFQۢi ƅ?T*XO/QZp'0ّ0G#Jo;x* jR9 ȫ?q7gIu!Z(HrxlqK׵P^[Gv^Ԅvt"8d'ⅼH֔YmOs V*d2MChzyܵ!Ey ̨bQU'g˚g1t+Na?uq'hef}aҩ$5 sٛ-wZ6op]#~+C\kԃa:s`lk%t29^Uz}Vd'ô0YRV2-7fk'[ڈ7׿ !cے_gN TBԭ(g<{딉 V%3ظ}W?,!AQ}]) zu'z@(U(ɏh*nɵ((c =3LqJ4I)ɱ40$'eX̮!a]=gVs[d|VVR?{꣠@0HAq*ܙ믾UKO;~#lfӏo}f/ _XL$;zRf{ߢskYD<]h/R+xd,Yp~_ Hm>nJ;;lA4ݟ,Q<*} FB75b',zشf  N ű VA+ceUy̬_)ѿNM!PZ^[<*@׋i:5ͦɸN NxTC >`q&'롿+6 08Qzh&vYa0nw#TN 5Cf`ۮϬ.r.܅(Hb`4Iie 5JY( SZ^`.nȅgaXyE =C}c=ҁA6_G<:3{@'XE"gthKN$8crza| ndTάcdhUU3l]02lh -g3Ow{o'[ׯjF=ɶyчx}Jzlzv5z:P@qa_X̵Kϧ?^k)bCN^A?S˴(, Bvt5Ռq,%Sٱk=0\d]roXqłBBz,x>mcz6e翇˗y !B |#~^TOFzڢy4ΛO8e9I~q1y1Vwg\ ȉ Nuw3pLH؍*Sx l|n+ a uU$Si.>9c1vGU #CUUGFX&xg.ffSRVMl\otȫu }=\V Ҹ,3UNRKGò)2WC Duά*9շ)&( h/`'R)}<ڲ0<g^|W>zEQec1\ܺ)%i96b&KKS5'0B/RB:4t s,4,-[ʬQq*M̢%2M,z:w7z:^t8CV$@w| ސ{LVSU4)D섄(^cvX+a b'[G64A KAg/㌬y-<ZH 9\o3myˋ9m>۶]jJٻkNjvcSx*}8SD,RͷMEq>cqvχ7u{+U|痷t,΢߯5o{? g\@V$OsU$K9g4[dTTzk`GNU;{TUcCy3붓<|0/];@bw\}\x)qpn?Q á’2:,H$YW_8׬<5o465HGTy55a iZ˦47BW,I0@=<32DNlgT4-,:Hty%i̙9S<^$,r #::Fqy۶]RPĆg~c뭩DUSE/%H&D[|9exz뷵ak+/F&y{<_}1~,(<4OEQ&IC*iM`jӏOs cǮ'K,}jV* mV$2@ϴ5s"/gp!b!O޸O(O#H"͆Wl& kkh(v 1-_ }C:cQ9`RR s/{1rr0tE+Oci3Xuޅ`d`XT΍`[?@,3m?Ra-Y99PDP5H&LLMWql;BpB2i#0:2Ο~` Θ֝u3ն*EəCYEa4Iܤz9wn( v"Φw-)*ьZZrr¨jǖ.&xyc;,X v[j2US)zSV]jLQ@SxGU=HiT| cchJ(' =Xd6DcYݿ>/+f9cNybH#e~X{}sV-$7~BW{4x]ep%<^+o -\=Nsc B8㦌1ˎeXӴ133Dl9BDJƆ-| Hm; %F <^׿5\ ݇cYģ&>dRhK4HR>jοk> JjRDc1yss ׽o!M,5KsՒtI~JUq{ńÂѡP JxPcX&Y,$tw}D6X}n6RJ£=~A2y+Ct{ Ƹp* e'PyVt9[Md9OHI: !$5s[uj.$Av~w_ufԔ_?X={0<Mj+ax KwӲ vٳ_MDSUKNd.OF#4~l`H4U vnي= v ǫI?űɡj'Z.z^n7u`g_Co\$}{(`FuJÆ=s;yWcW' %)<~90vƢ<*GhHP 7.'+֛NYXC: A}-4cW }u7O@Bqy#.ҹ m| Kؾq1~N$gR V!H0#es, OV(,Y1!u eERرq /7rEo _̵\tRV,n= G8}<<kItwoo#Lqʒf\?WS]Q#Orq׭ή~P9gHxݥa\5fVCEtwŨQ)5jflvp2Lٖ]wѯ| =mRTVc;x2rH<$Dz3E~?Y,l[E`6m#σ1-M\LkePxdUB_" 咰͛Iصq5AUzTj#av{+M*] Ndo`'i-P΀-%V"*h>Cô˗̺L隑h~?"c D9<.5~dT'9x쾻.tz:H7i8*b$R e0̴AMQG׭I**  INm-5л/o8ETpUQ^e9 A"Y|o£iX?Ҧ )D'{pJ4UHIoPM aT7A ))1Ub농,[eyvyqX oz 99Ml4_ 8ozknv &QmO~{AѰ˔{OK/?g=/rG^Ɓ(wMWa^֓ E56c'o-\4UQfIZy⑿rUSeģ#ܳa\wG=QVcx$nC5RS( C-,>4ytmmN_KXWq$gdQ^D/`H xZFɫZBqq{E請qr_ 'x=ĢX;KW ){~eWbORP!0sWI,;JR)`6 WbthӴ_Jŭs؏鄃Ua, l6=,X뚪`O32! C=<~\V,Ӵ'd3+o`Y w-v8>L0~%*X#q\8xeE(d`еD3S,/OOťh/٢~0,\aU&zPx+aN+8K`ldm7Liٴ{y{O~ƜE T-YqֹضMWG;-68o6D"^~o.Cx3.`+eoƿ:Hس}9!JKʐ$-xv0-hH\|a/֘"k[ƨh\D0=?30Ip\=ܲ -AU1xp?ޅ `xe;3jB!])\aR K2G H_>SCF;( C leb6m U~ǔUՑY/W9O~_}}1JϧY|csGu>mD|gصu3 8cN[Q5[Fl߫rA.a U`'lpEs]lmEnB:ϘPͶUaѧ'f&n/w>xTm۶TX(3d&j+1^=1lK H|5iBY٤&;6ruKغ{7я&*ccädž(/YjBt$L  e0R)UUBJIyq>Xx4m_- h b%$cyuɤOr daMʥ 8כbvm-;8ҋ_|4ʮm襤4v%e嘦ɣwŋX\W"i IhJ8MiY離r_)TfFyI%$d`[\?x+o2~o>3r᏶՗O_QϷI?~1udCw0gy|ˌǭmQv'ޫ(1LeyRUٟ'CUL 9䥔x|^v_Ö?K"ffs{7^{J ǭ1EdnK/B{A|< ݧT[3ee8~^!X9&hih=]=#=4:@J4/wwRVSCVHzrtK$CèNܼllyyjoVҺN83r؎ob+?A\3,+D?N.kxu__nd@?|2Kzs CѓN$~r M ?aӨm 0,ǣndh`P8!<˖HUJYAyU5jY\ů27>!jPU/^y59iIv~!].*jcQ~2,q)w+>EU@O95?RIAq ?w=F$6!)*/~ؘ4zO=d"y_bLa=vyfn9| rIa^¾[) E)/.y2l,b@p\8QeET\ÎML$|2n Dz)/- x׿NN}5Q+RLmfV:4Zx=ئyB1Tte {'M 2_i9xZ6n2׋LFRO3O371;FQa/߇1QEiKai$ = Ƹ馻y&{(*c_{55ex4=;g9u;k)C|gcd,q)%Km^|rT 9tvvnlföVV-g,vȘޘ]}#W4M"w$BAeM‡.{9G/Zeier׾|W7Jۚ-Q]&!}IM6aa|Ԧ!l[ *,Yתb&tvt)^ 9ɳc|g%<}Ï~A[w/l?<9`P2ϣ6#/OB8K_;Xd6:֍ RZQu wԔMNHTO\ ʊe7poo6pw}eS[]ή}I b<\WcFM9y̬)'8_|<13? +dF?3['R|KY|`KK^ۑ(i;0@qypNXWEm[-Q29hC7ytD-b? o'j+ɴ(1>l5xEl"a6u]9wrض/X";?>oG,;'={qJ˴ygq$jP5}[Qߧz Q ̭03 GDz; jfVc'!L!mσbۘC%a#~[k*|&Eus()/iH˙U~59W^0a>"mx|y98ͯS?ԦM; pVXtdܮ˂`?K M:7 vC gZDii!hZc ;h,IIA.2 qOL먊BvVMU/5[?҅pYK++DSUìY| b}z#o4j*y%wF< vhI32.| ãtbl}+'^AUyKWqARI8enwGo K1KJ_d_ )*!Y줭c;矏/ZCiqHhg {Q^&a+Ob2X=6JEiXasfu_Ե\qi}o ]}|rckqdx,N^^U3mBA?LR1EݗMXC40m7Sh!nmFtA8g4:d9hCLғzr?}PF ä3]{;X0qr-(-[QQ]vwI^/eχm( r !y7*dּ2n} {Ԗ2"^՝?X4zG 2+JAQ)r\ =Uq effݏ =K,>te- sq^Y[T7Cܕ2^b܅h"voo/9#ArlS"A*CTICNCv/4,_F#9<PWXmxG HP5k.}t\$0.+k~g*J1<e~Y&xS'UUGSZsRJ "1H(m ňd6]iN_w<Ɲw=NEyOƙ"qM4Č'CJIv$m<&*EI"s;(~s9J8kcZBGu0zFPsrmkʍ77^A=PPglb*HC(FMu 'p"oesϰꂋ9`Yk|G\|).-ǘ߱mr_o}*~bV=To=U-eG^}s702tx@®-kW%f/ӟlKs<`K:Ge 7͙=w.IdĚ97Ge4Ve{@}KBeq9۶>-QT AEDq^-'j5q~X}X+D4c C~q۱8)L;`_Y>֤Ҷύpg,μ=j04 l6=FAM !H3 #[L\/;AvԩU{_Ҋd,+^xEow|?~…@GK+V-z%?h^/>$[03O5ۗ==\~iu e1cbhXh6]Gr+̖wq+1 (NXmQ5!eE.RHQhd:! T"UOnHNF,dZ먆yz&FYq\/ |_Yylo}X"M̟_úүXh㏪%B`V柔*&܃{FGaF|z3:R# еdOWlc$lBbcF x=CMߞnFYid""0L3+`WaMu\$cg eDU:ɜF wEy-%*bHiIʦ5xx7NdtMh CmG^<!M5|TԽܰk]U !-rL)bFyNljHe":Q %pэ)kǝTnг@0IJ \Ouͽx5u%fbAcv"!9#qe$;:Ї2{֐LIY"P﹘RbܫS~H&H6JaBHT}]oc`Դ^ :媺+E9pkhԛ{SyߕP6gp܅ʲg:%%TD }ѱl؞<34,s# '-51kٺa_2 ye9,^q,GXe|d4J t:r8E rޔBv7G^x̣+dDsumQS_D̤ʮ kټ"bPF2Ȩ)`ы% E!e3~OU_㒠60t ӶgJVOXH`'X㘱3DR.%3-KbHzHOG)GMvƇ\v 9Ҕ}W ?`= FF'( s\ATBiM Dt"f8&@'64VFkM]Cgo|_2gQ#3統`a_v>L{/R&F=DYaHMM;򽏽xiK/\N_0a165)]t!Oa=;r٩rG,x̠ʹ@3=U?Ɔa1|p`Rf1wȸx-`[?,'t;gמ.>bB?BjqrEēeג/x ?}>M 2U:,]hli>wwR3N% g?ƣI:FoYQszJX`e?DHJBXd?s!bf}/ůy5]x>+nJyreR 1 /+Xʅ@c0uzڻx^Av}!E h@Ƭ{x59h go\DD+r0 29$hj|𘊞v,oX?f⥭hW܈1Ѷ{eMXO /OT!Юu5²n#Q̡瘆 0.{i  80k7MI #t}C4oS*+i"dT5ܜi`_*7/ϱgﮝ_|4łإ$22MtnC P/U9#QJYxAg.{J\(edZ4%{\37ZcdK?w_hpum\ې$چK)c7ar*^[>O#VkmY?=vtxl>WP]s= ?73CxJ+km ߹;rz*# ݽ_mCV4P.m 0C= EGtclKtu:9;&B|7ddE+z`K@r Iҹk-op%[,fo'o; K(' 0->.r~I֜#cDQ ޱ%R#AƢTH[hMWWlYKG!ޣ2H;Ɍٳgw>/o4W i+qI2Ã?##8kJӰx) KӰb +V?cKQ7g21ΔTȓ*{:DHzhmagg/W$_=_~w3NM5|ㇿgYpѓN䨮keӄaU\)&]WOcy^)$QZ+xpFD4x,hX{ضxœᛟw}|a9)‚_qid2{0O.ɪ*J% AbQF<ȢՏ' Ck;Y[v%QFV[z_y;Mt!a9nӪLw~,[Ʃs@) !K>yw4>Kf4Qŝ#2>IB>{hհ>ο&p|-)"JY-|o/`dD)ẺskƆh0m2 ٷdqc@<'97R1Oܱ'KZxk?=o5)$Dw1ڻ] bg3%o22=$-RJr_Q]WOxt#=t4Ղ!S"@{>cyZ;WcNd}o2PeU I#/kc򗛸gƷ>AǬ¼)5&ɧ~-o}E?DEk {g~{pw-4™2:5Z}.-bn "lv 8":={$Ţ%xEM!J>Չ$gl^"~}vt86s\⮟}|Ĝ]bx<+43j3JXO@!fqk.b~IԤy^KO ӳ9x/x+O7ލNe@mZ;6f>}N)K)zl=URdsQ'zQ| * G 3f2㘥%Oop]x*˗ͧootRL`.M[s=b)aJ2H;A*GnN 9RfyIFϡ~^)BA@M}'Ўmr3~E("G%i ^2C_?3X0$4N\]Xb׶j m1<8Dqp+/RDUEEt.KhaVK7|Az ZXC`Ǩj& 8d*"+6t+cbjL=Y^)MB0K/V~tr|:GHNU!w?-Yv(U!\S4(xp!6r:")˵ƪ ,ǡF=y˾ԹLQs+Ѿ&O1Ѿ eH&h*COnT,ZkCwg fkoa٤)W񺗞@&~wlt񁷽zO.0 FGlj%H$b\h"/{b|77N{KsàoNJDVx"{/!@N>f>$sNfb%,HT꘥iY o?˙QM2IPՅ|0cB~ XO۳:s?5%#!Μw>4cٴcj?T[ԣG|C;=\ UNݣF [6}ScN_Q4JQ4Q:*[`dFthE BKw[ Cx\mzaLSɘbO:W B=<6%8@V2QdjUk%# 5l!?B@#tM3/4RDò0 m!A&BD yeiD!V^h4L @H%Cp T+6up~GyW~S2YywݻEfKFso/|.d mM|W'Z)ɷ9xw]CT74GᶭÒ7BkkP >p'!.+G!n)d٪Uzv1w~3uB >g{/ǞtRxV,&JA Cb m_h ]02uu5i* /(}AH$(1[:H(h %5D9+M!$J~TfYsk,Fip|9.m%&y&q8 H2(2H;%LCcX6&XƎY >&.d˒ئ$UtL@&!ZP2F,$5a=4(0B35I3+UVJ2mhTDFz,[8h%\ӎ[J]0D!ˏWW]^zOm"SX(c& RH&xO;ᰦ[!ߋfth!)&zڀ1Q1vy=A :;Dw-PPMh#*YuygUgV}tdLS I)I`Ha,4D"@.Sedˢi .@GGMMـ0 \|#,hX<&šXxx!wpK.c!\ښ4a!C6Gd:[x90B< ͑R~J1DJIY|;fqR9ô8L JX6M.~ Ȍ?Fo)}!V,O*Etdc̙||.?+KO 7d]c [&n`R LJE7)2 Aaľs5NZϡ. p Bb91ߝr#tbX@JhyGdL8KBa)pEQS-ȸq'Dx' t\չx*ܿ[ݶ<1?Ɵr/nUbܷɻIZyһhg)2pKVtBc B|!dժ4_uy˛HSs XU,Xn z+Yt1w3B!1@cHYEӣWH=ZoHfpLR[`</V16 bH+Om@K% J vtmKa A:^$fb[q[a°T".PiITEGU<&N`bW"Co" >=qu)T(T2H9eV@oJiHi{>8e^*|ۿ{?c9|兼ҳz~qK.TO5o'_,q9'p'V<Äf&G>y8" {MPB9`NY9ZB#a\~\sO s)NzuS9xsQ5V ! |Ts'z^@"fM21JY@ JEw(6^`yB`Dk X}?4ˊ!:")tTWB%-`SuGZlH0p6 ap -Bʹ`V :XEB%) nC1&ԂRhc EU^`0\LaStTk@]*z䷟k媇.$14^`%M *2`1F)# j9(%Y?417JCj)*~qǮ׆Y(22G&P(@X?q^ΤT3,B7Iإ3[F@iAΜv mL?q` 1gُjaSMf8SGF82 +QϑJH qQ?b5Yl tYy**KB#53HZS>iOCOU<65q[QHCbձj'$(SQ+e(*-)Bk0AɥX-sNRFƪ,A  ӎa1ai'(r47XFQZ3oN{x?8SH$9usO~~imW_ĶΏgG[SRLFR5PsK'?WDī*_ j^7gE@_GꝮ'Q`-7Kcӿx/ LX)2ͶDQ^1[(rY|<Š"=TDްG,k2yh͝l ׯ_Șl|%B <VpVȲB 0 {`J?V WQ+ţV%:Tb0VL_f8_M㸡E1)6Vx#|U`VS'g1!rY>7p#340fz_kOxA@%1 Jf%֛~}GqAC0"/XKEx3}*sئZI tM4R*FyS!!B8mŽ<@fUdVMY ~iڌ\domC4s8: ֡KiJ&-EښÃxaZZPBODyt׾,֭A.GG/U4/{љJPH{[#1~r&R3HUc d<C~XC-m?qn1XP['&eNN Ϝpٺ7=[<6ᘗuXH(Z)B%pKn1z\RuW*znV~ԴO>sӪ3 =Xͽp Z,gm+a@$Z;ʤxb"@LӉ(b 7w>[ZThZJ!U1zTb`kwhbWΝJ,㉛26R,Ҽ,ᪿ)Ж!bS+!043QL(+ e"r|%e]_Kq)5ܹ-}QSv] tcQIc(-'C^hSƖʻr u $& 8CF\S$a0 E$^`QmM`‹)I!pxAl'픰C$m*Aʖ|c$;8 X!nB)Z%'5SYX=Y_ۙ1:ʫKŢt]Ѡ%,!5NChb]d<ȐT=ڿT2FPU¹o'TFm_-mo'm Kʼn7|팍g9~Q]=jJR-zGhj[a{~+Ôxiocl lx`_;m`Q9c y`;O.[Jl_)f&PO{WBP_IlH:B=dF`| Qa6ry n42JN$&GpsiĤ2FprT)#*Y^}J$4IY dH jYIwKKx2B @sѺ-AkBcG*_p= #oeE9*{w?9_(Uݚ'0LŃih@@[cnq sSvZv&dZk27@i B`x@Ix)ASۤ"UNX(RFm]2-;aPxJP$mSdF"C P PCMp'Є~V6*?[ BfԦ%)uT3D?eJTi2|oQeW;Ac|~J`(L1fBj,CpT9E8Jf Ҟ'Ԓ6V-]%kԤb$mE i%U2+Eܴ5S_N=~fr8e|㛿G+uO[Ň>N?qL15> hrP!0Ea(9RWcʐa/\79 6F9 ( )ӈ /=r."lQ/rt%,GE[J! a8:x(9N.2T )YEM%jF6&b&E:*'pH-AX嵣B38_\g1 ҍu 5f6 Οk624 ϩ:b_Se\MSk+sy zhh38O8pO 3R E!22 CBߥ0eoaF x 8Ӷ,kRA~U{JAR JE%(Лkcs8y/^-} ʭVȠ2#'[LJ;0G<Q[>́`IgXa>Ѹb::ڀ(G4Yk9oF*eWOL LnܹLsW-{SOȺq,3@kA'!wx)rڹy=a\&Æ- >@7E>49z+-`X̮O-d$pѿ1iƌGD/[{qaA.8U90{7@KURfzXvᑰT9EL3#=cXFH ےt*k4T'H'LiZJ+2!ˤ 5;oo`yx8ɏQ[زmM/j.:_3kF[vc]\G6Cüs_Mx񔝘[PgN3?)T^B^`9T$LD1TJ)8}z{{<:X];ŲUY?{aRUUҥKٽ{7S;3gmmm[R?:cشiSt圛)A$2^`Kʠj.V1\L3Ta#iILpr.aG]RӝHxuѠB]QAR  P<&*BrJQ1w8 epp@\1ES26XC"]P`DH>$,rL? /~1bkӜxLuVRԤ>Az϶mx7ɰcۑkGTO>QvI"/ PmW)mO:-[+eV\R{4Ԥ$JXN`10HbD q:Rc3@D AYS jYP1`!M,w%*DW$TrA}6%;]>?w|k}DT9+2 l<]aS=O.{J+?]?񊯻\0Ej T"0$=Z9c!*y(Nq ]NG<E|АҘpetlgN j$B;g0w꣛9唓Yj%_m& hl5-d /`8 n(( 9f/χBh>ZB[mz4-OO<%8. 󘄧+#,|GEr $l7jCE' G%RAhIgqK" IhltxKN<TާTpY0yJsA`t'Lg|$QʺB"}gqsYJ8^B"Qoȧ)B6^!2} 6{&<\)cDaDu,dvT圗4Nu0)~4;w.ccc8üyط 4aN9Ð{MMMtttP(ػw/3k,07oR ۶1 B09y۷ubʕ(ؽ{7pX(S)y} ؤb)4a @5Vsc1ɃGZ fg;D3]Eɏ:U@_}UQDLHwm,yy7<p!]O&(,p3݄0C/jƆ@X`A,Mm@PFA&Q9hm Nhb4NZP}C]Z[pC*Y'4AHd&Ҕ1eoc^*H9͐2@>k/eG.B-)V@yzsxF ePңc&PIۣ5=ւB+['5t̅^Ygŵ^zxL z K_|W'z5{C VKߦ*.X3o|Tf) gL\FsK>P")>0|&U%ClH}"C[ :FU5Jm J%^˺޹cBssvNZY粰DJ*[a('r_SkNOw0Ս MQiR~FH" "jB7'2>9Ω;Y؍mQN |mQ/p茦 Ӑ*^rUU[ٳg3k֬|/Z RWWu]袋m!z{{={6wa6 .@A6@ҥKBPSS_ώ;8묳EH|8f2.vCsIa Np֣.fѬ;|(-vv#1v47MP&>N{1#o{V1<!Xq'&6Tˇuł{?hY(yI&? XusL> _+.2y)Eg~aohZk?9ug쥒[7+v|RXXKMQ'Rt}m|Js$Y>Br;)5 FrL^φu+HEs-d <&}J:x/9~і@F4SNIGZ"ʜgc2zftt m Yfb,T| 0MH!aH >pŖ} v`GbF}/w}ȠQ7(ۮ@#TOT"Ħ&_MEn}$Z'KS"KvQΟsgomeHh˷%h8c"s,/QҘXB(4S$des@!"+hcOǴ•XcmPSHL#;RٜOwwzv36GyYrdiZVA8'@4[W# Mkzw2fX B/4qݩù 4aHmm-A`۶m{Uz{,k֬={p}>~:===\wu/SNapp0 )Jp -[׼Kb6G bңiep Gq=yQ>TyѢu,i%_ɦ}6gkK)q]ܲ 瀭pD\q Ax#G۸k9Hd+>uO2%O L HG?h!Z^gsSww/?y*|."t{w(nyX\{wM ۩ذ'E~, Cy[ey> MA7ЦelU٣\,QT*~mȺu6IK$;k.Zm3)tZx%5IխisLe/Ǵ`~(T;<+Y6^hA9ZtI'!ddd;3Lfǩ'_>;2H>[MևCzF5 ݮhW=Bwѫo:g.oǿ ohv(A{OTj˿(GU`w1[zɳvXPKTUUg<>G,+BB`&Inܵs5ny&Mpq04(&PP=[L^r~M{CbdSMƊfkWh;>s?ƷQZs**3.pc<3^Д?J1[rm7mR1KuKo ^y!C?Z',p!LFY#:9d{B,&{IzŌWfmyr\o9WrZn۳X@ӾfmF Mѷq,[|Pɧ~aMӀB~\ )qA&# kݖ!Bksd{dBt&B.| 2O:)L)n,azm܂CW8m$5x)~\L3z0$011A'Q 0mx&pX6Pa"XiM&>;1#[o3ш6kh5Jh38u9Q9|AN)IaD*p'Ɏ Pf"C[;MJ U< "Ym(xƔ Kp*0'j45(O˲غu+aH6;IJ,Jk֬}Yf 6l˲p]n.p]:>z!0dڵ `&\׬|g͝lټ&osgFQTG&nRIδoѢ:TtBll4=ÊW3 C=S*\OW-]ѫ(hw+tK s=^~ɋNk XKg\"|٫i.S5Yv 4?6[B'4 nU}E1/]12 5t֐O~ׅ8P xo!z4?WUs$ό&cFB{k C0X$(0<+BIKn{{4TZo#m1ak^g& MT%$L S. aBbbD r! jI X7HL zmUFOQ-D<ITET2uO֢3{"FQj(}/]=ߺ( ˍxTF gV,sx^|A24gضMܱI' Cu9؆&f ôGWW&\`P2$8n1Yɡ5Fks ӌŦp &Z3LALJ/ ۻF\R u9_%H8 Fx hR Y,mEk+gaHz򵔒 r ]9ac iFSؖ ZѳO>V. E?`CڋGD Ҋ@`&5~;.yWJKH"1 L5^LjljJ8fcb< u`P[#4m;>4 F3H<JV067JPӽ_G ݎl~nmG~q3Ʊ MJ_p⴦C"/gl^-!ۺ/9_/qڐ ߋ;kV38CE @ؙiLX%{hKqtj8m7ǵ"iXc9\ Mt1Ɲp6o~L ! 4ggɔ,]mDZp"s{bWtVHkJ1WITR V-pn q z2W;~CDA2 H=NX)|ƧG#Q4ϑ)!+1%⓿p߫ M 1B [)xd"> Ð{!ir)0::ƍ\ aD@PJiH$XT%lf7qf PD+&CQe׼.5DX^CtJЀ ?(?LԔdHsd4p嵀zҋ{*DZ N~an}nq:劢(5ٍѹ4n>zϱ B0 1Լ] [ܱ1•*yS.bٺS!gZO-&-as3c+/;ƋIknvOYx9YX ZkilytO43>VEH>|!<S&LtkDϻ;w+6w75箈1/йCM &k[)رYqxuk碚J9E"dG4ېM\(,n<9;Ju:(ьR gj*uA3s-=Yh,EbcEK2aМ9sPJqN; ,oOjZBDt*'/0:&/_DC"$*}{:aBܢ (W0>x7=[6%D]l[J)B?rp"]A?=JHBJW(0Cfx^#}Pa _̓KX;*U'"`qh@Eƍs{bY+UqBQ3VtZZb)A ִPDHQ?sj?(&M,i` IDp(6 bH Fk72T*:"DȐPM*ԘL.0ִ g~C=EDFtSH`]6H`JQWض*R2t>ڼ"?!;Ʉu' OpBLLp׮Y!({јJOFt J  ajJww-% -9^ s)krB.DݠmFy8T a4v @( H3ba_U|&W)rFAc 4ڍr#!Ngk+[{Y~p2l H#P1A ~wv͝{z@injU|M8]p0`|PG.ZsVL%epmJDpQM_otᶶV/lb_P0ApÊB*$6FU $S6 $Cl8su-1]cQYfEFR A!3f GUUdִS*dFtiUl$Ԛ0,GYvM2dG޷]۩njyUM$kdD_brh4| w"3 {"qӣLܷL(x;8e7G~=R1mi7Q=~TF h7]P D=c60DH۱;* )GW !TΓ<s=H;Jh*rҞuEI+tw1њ9} 7uێY8c'U#@9hB%r\v7!5c9?zc9X˯> {+>N+OZa0ym1WmuY!xIfbs[ܲQQ}CkMT7џ{of,IMJ >ko O""$(f.#yK|6jp-hH_4:!yK$bzސ58ͤiJU_.! Gc&rFM̆/^!sWJtj~z>k~'{-b||f:;;a… u188\u]GT%/y z+##m{}#鎋aZFSʌDDu-5m4^HUCB7IRx2(e^&(f2h"n1ww.c j/_rgL֏Q#.-RZb+;9mID]2 C([9sJ'M:lLC _9u/UcD6|xۤ6V䎭v˲w- \m]\sk;` k/.gX3^i\pc|+fI>mw ظ'dl1 >y˻^h\b~"4.-&'/6Q))%dglUk遀?_.֟}1}Sާu 5!rWa5~uw]}֯_֭۹F3 1nfN;4VXu]GXdܹd2/M/eh4^1O1;voT5$)ZeɓPQM0`dn7gbh?~ +`)|Yo֟KXy_ᓿCC-[n!50/GP͆\=nԊofp5]˘śVX/"䕖\!b$SpB>Bҙ+.8q CIVs ;ލ!o{Bi}\/dPSU`Wwh{)yh5%8fx&fJ]h}~K' ywIVn\xA?LDǚ/VP̜)qC(}_Ȃ6G0kYۻL&v,h_|U+# ٩P4 I4暌Ϟ={*{Kj" ˰h #F۾ +q-Rȕ$:jI峌tw2gAePW yܱo13(?Ɖ]OY{*Ij6C\)obO)w+PX+;fb;Y҉cy(1PYؤ\f(_pb;Zh/&y=G:QW#|C0Ao-}̭e}F[ .ʣ ~oC c{__>{?  hHi;KO4$%HA84ݥ,  7}euy^KC6cdcUYӵ2aB$ ʍ0B&QfH]0t~s@R*TJ•ܱAmkHTGM Phe04h3qJN]v WmB 'M OgOOlsYv͙$qGrf/0h*"f-/o1;;6jN]\G*.iSbXF9U\s8Yjű[3oxAͻ T4F"j֟Lz0&߿ ?qYOǸTLZ1Y>.qQז.Ū/]YW7ܻ5E&KۆtR L-c͒O ugZd ݚ1 .94Z8f0 $֚ p嗳xb`޽466rw3LSQ;WӻuÝiAEԴc9r#xG+a<6ҳ!JL òy7M!e3>U>s;!PtDVM'Sǝ3#%~,J R!DdU<049kfNU& <~ʵs$7AX[F6DJR*)tMj13 *-Hͯ R,ϡv Fs._}S@M 4 N54ԜŗP⛿W >2ş ?fJϕ,al)K$5iRd|Pq&o|oq8_?N9:e'iMgXPJjQ!a@ n^0:s N_"ymHg NZ-9f{C!+ 520<̘-A҂]}` %}W|/>_io>Sj{da{Ͼ.MY$֜`}bdEDy{1ܽwU Vf~ u, LGYHLϟWF'35B7Bfbbѧo?\z)higdlݐs8"Ifx,e1h@y+#l|=gLӒE$G34ꀔ ui{57!' /\2N2xKƀ O7lqͿ硇bϾՒ}574 Ƕno0tѼ4}Ek+Dw^drBn 1xW|Ml-.Ɣ ?]vQ*蠿0 &ϓYiIѷhbbM0RL ,g8nhxNAR!PzT,˗N0Td<&pdJIruIXMw;RewŰ䒧﫹_i40v?e ׊72U$+xEHdI) 86(L@>TPA,yB:BF'K݅dDSxᬳb|l۶ ˲WYT06_)HӤK9ˉw+)k1(8]P0g@!snC)dj.Z)* B%+%ȔBB}zz'ku0"[3I.}:LBYu9u9?$4Jrɐǭ=+w^,Z'QQNX 4R?m9\S_O0C"!}ePx;XA)MJ ~ɫO3;Y*Ӛ=54_xCXCa{ A0,jw|6}) kC~}GCMPVG|JpDp!/W\64k{ JtDIGPWI>5qǗԧs%vܷ^d~Dy> ߊ,~`H,h|'W_3ww\2)מj\q~q!o ;_,^e? sR\&7\e2BXJ2ibr<e$mQϲy;ǶvҐ%ӣx}6DahƋ16gswRWPPЀLຐ˨򽑼A6Ɏ`&Zi DŬ%Q< R^ɫ,;sኹ^U>vUa,F/i~<2@|T<`-")+.ͽ{33flm@ $Bd9RRٺuBW C|\V+LV!#=t<(:tC3*PHqr2Ctm݄Ai*.ߣ& Дc]g\>ڒYH_-4bL)ńd WC;2g5NB|a\'jX.K; 1Y+$aJǣC<6ÛK&_ޛUg󘛛yNH!adPAj[mmkmjԪPR*hA@!ܛya}h2o̦]W<{ò&EeiF3CpgRр&`ՂCf-Bh>={)njFKRBx)UX0S~:$Q/3il!Mm#ɚg= z+}<߯(wq,4R 8ZhU4 њ%㔩όҘ*`U?B-M,ly|*F !5c8 CEhlmtL ń; Gh28B#fmyeVLԆhMq ~Eʛ]%n[Pdl*S%+[pW/?Iw a[;bjHH&#K܂  'c&6}C vPu}\8k3z^;p`v]/(1^8MxAI6t)Fa{4&K,9-{+2Xl9;D2X'kse+v1oiĭ+[._*Y0SR(#C5+#Ed]Su?~uwҏd2b`,݊>+- 9P,iG&QdN}uZIʡ۲^Pւik9Ջ-{i;nk8:ܳ/$SDyϲ1LS.{ݣza00cT)h w'zf2G!x%KXVsx`rF0صϻT l/%[yw&]@Ldt$4Z[$E\6ٷe\C[AVtnOΦ˵,sp#"e-RIp$bB93|_gq:jFɵ3܊Bdd)m^8DUec4/6q CF9k.yA%?/k.X)t~yd&ԚKϰ!$\sŭ6UrJ!͏1Eϥ}z`⧿IogB,Kpbɯ6ʥWem#*nU\zd"gv6 o~CsZi\sCvԼ;5O>^0e2cP2޸daEvޙ<{&+Y (/Ah#-{y󒇨Kd%ڳ#n2%xrnB: zCn ~h1fmoS >LdXI<#»swuEކxbީ&X {5ڍUF yifntIZm22yLNP2l^H2ѹ Q9p]M-,8bZfŲ4Z 'S{[aCwVH9fB1=SfB`iᙃssǙ(/|aRt\}4sS& evA?h-yWLW_p;CG8.W-ZMMs/k<(e H -Q.W~^{[s3t  lPA1< Q,_W"0OGVdYCRQS Z)\.̇ZGGK ؀+0@HFRIs2Yde])iSTE[ =ҩ`! 2~,9- |4zI'&9[ f^ji1Nkۏ%4^|[*d$Ȅ1=Hx-* ɃseJ ڑf⥔tMfK7~ݟ56?ds>jo>$Tm$eWu,IVoy\"auڤR>Rʳm$O RtVI6 Kn#2i M"3Ҷ,jϒ4gr(-;RFGJkDƍҲ_?x&8=_HdzI713kӚvKcwZ,rY1#!qW-h9ܵ z:Vp\s_T"dL_%F[)4XOO!p3O7W+/V٬Z@߈!gHxcr1wRFPd,o߅$elꙁVN$HQJuFhfrgxB M?E/2ªVj,W j]ryTϬFVfO AOʰFlI`D|-DoPYrÌC@)s08KE;VԚ2-s洖lJ, ՠ i)ѡ cU5c|}dyǫ)(xPBk'|[.߽#ykwlޤ5UlpdV ,(.7al/5+lN)Y²Ǟ1QF^9{ājff 뻙K]H2M!P~&B2$iHRrSt8o`TG).!Yѱ9McMrt,{/ٶ!4ugԝ1Rw{t}EZY%4 q7ob~L&~IOWiTKiZR6vР%ymꥷX_̞ʵ0%0惤l[׽ḓ<,MLv8]32S%G;WL(+ȇ VOyݧQ-$qqnBc9.)ܿo1VBULjxŨf7EeFǎ1Pfr-Ow@ *}A?& F >$61i}"{kk2 ip΄|_sZ폇l;>Rva&CJw6M vFu5lTG²\ %/W1>:7њ1PeanS7+ m{j>5¶=HTxNɄӯ5Ҳ(:튲pmR`eTfB?e28yȸ* VpTJ#A#@* L.gm\2} 7;vоܻ4I[vzD* DH&Y&m9Fv~l(Ē-fH;DS !ZKa[:[q 'N.ɍ}{$Ds!4rS/qê]f T/3iHݎ)wڜ97I5n<ekP88(cWEgS0ZlIʚWnEa V;}ϓ4k7d[+Y+6viG8au( Y5JtwFh\6tmw]+AQ8QwO᭧=@Kv <G MyOJIadGJIvQkr86sV%C~}K(4{i״"$͟' B(F ]x҇lӜѾRB=۹!/(Jt)4*pX6i޶a6Q*Y;XIB;FTҙ)7;3ݔzBeQG&Q}K^-p?x(eMLmwH/}NcztPv g #!O~>6+Yep'8."@W yllo|VJy+^-%= Qu)h!ha ߭+XQ瓖&)5]B?@][dp;ModPZQ4@5w݅2B"< /4K HpniˎMR3##i!Qbn%mp$nKI`Tn;b :\3H ">Yt&UA No`yӒ,R%WH+#zd?LqBLQ%8ZX99BS_C܀%mǭh>¬~SJ=Okw/XE 0f)cٻ+?m΀6gu֩aHn~Y8 !K ظIͱK8DЎk9d]4#IPD!yj.I;˯ISz}s($S9{/h䱤Qjo\d=#-HmYN"CiۿɌFH. Z=ڿz |%Iin}ȵoOC AvQ%L:*wZ9S8 -(y5!eWZϲ}J, >dFYܺ0CZ1XcH zgwZIxQ6 }s-mԁ>Ү*Ŭ4h&fGsO֐I,mJX>` ]~8THP(rn>|.Yıl| H4?}|޻ t>Eē@YX] Pυ36gV}^| ]CC ʦPO_œ>N6IeZ!{w-'t3Hۣ.$CB+wҚs`A1s%ik8H)LmF Vtle'\y L-pCR'( 5Uh3 k724eJ@'5bz )‰WRt@"Q`P;3{iHOOF fvc/ kI BTQen# PSjMcVvNcPJEbBW* } q ][e0Ĺ361w\gɕ Bkx{Wm'MB])cWDCu<'?DtZ[ d3jfjGңW-CPq.e,*?'پ[ fl3YI%8.h'!R G PADlf6cAC?M<5J{M)L/'*tEݳ0Cʐl#MymSi<=!,Q,g_b@ 鉟 NtnO\xB/ *L1Q޳E,jx e 2:q²rȜiY-4א͖'#d,eR]ڰlI$M_H4E?%C ?*]ܷk)Y aX`GyXZY&6>\֎GeHpCIO=R@eH%ѾB-ҍ̆..'{gГo7ߌr6[T-MM:O)p4t>,%-sMumdEF_| sOOxnDe=4H' ,nŶ) Es\)@y0cϦ-õTfN̓_Os6tTDyldV;ꁘM!N6ʦuuMIl`ٶGoNћӼQC! :$E9.1ś?W{9c,3nRT㥊87ؒ!#Ԓ{fpelMz_wB"79zl$T*UW]EssQWz qӗs}ˍ8JRH)KKќa MZgGz,kyٳ,:gwix)'HN*a*!LMQ sĤf% k@XoW|&Cg)Iaw(-`Ը{4Zh\\bhen}!4ùf=u3n &^fU<^cDa7p5JK#5ʜpx-LGkFCM^WXJ{P4 xbK  ΐ<v߇3K{JM%$IGEnXmZh߬,+.C&&_%-f{5VŦ,oRIi46 'kCڶzYV[L/j:sA\! ;X={N'† c2㐡֢)9Qec\.3k.M84x"l6j^N[Jزe dl#x<5C؉-n`rzWܬIhs;іݧdRy[_,R:}f}'g߬ӍV:Ѥ\/M\4k=ۥf!7K9)IV#]s3؂V,l:^/7[Kh+CS*AԻhRYWcgV8js 98$?#!e%KMHXiS3g[To+*>&;LKQve&qKF3ٝMXgk/bKGF ^ ibq-]wj6l߉V<}Rs9Rֹ 2Ĭiin+ !ˑp$˧/_h)Km# 'd+gl%㾽K3@هZkʹOwaklJ^/&{"<!x$ֺf5ГkT2K[u?R1GR^ eX>~Ȑ-59Oa Cz rzԦǓˮع㣔tŭ=vGeSҙء߻7f\EؼLO}9௯q{|hg-W0<1d ICޣ.{K_lsfJR ?m u yNj|GG0Yox⽯׼K3}uw4^dSri_q]BIvq-c:'3$bwo_Ɏ)6i`~I& Ӵ$kYS3ntDps[ֱRVVZŒ%Km@;墋.bɒ%}ܹaV~}3u?|ܻ|=}eqB$̎lk J:Q4-qW/zz BS(QL7]UCMw$ѡQfsܶ,\2sPYrY<,Dxrڏ6cʴ4(gY{XvPJXpp}>jhO)i~p `6e#KWY I.|8`<`K! €w\jᚿw&ߤx.B|L!y'4 5C}H 6lԚ6ɇޠY>CP#BX2{b`FZ@^X>;-Q~ 7:.x_?s!hkL`t ' q' X5)fux%4:3Z;v<Νŭ lʦ"!D^?qyw9&;rOVA3kQҙafZ@ht$4>}:!<1$ek\w0c!x4~@fZ4J,V-H:b཯q(Zq6ۺ>\w<;żR|/\rEϰfnEs.X$Wk/LrJP\}bnd,BheCȒxL#x&m34!c5硵fq̘1q*d| GAa.]ʔ)Sزe [ne``RJsEH)L3:2v+s`+FMXв-hN\:s)+2 (y?]'F,+uTvKfm$:r8KiJ &νrvvNLCm$5˝;W0\G+f2ah#@KƧ{ $-TG>Ìvk~HA.jKGS~3% ;I6 f ~`+VU8ìY?>-"uXNKcϞ=hlǂr[O^ξQq 6r`dm=cE8o{O]YF,^ԽHeT/JuJLgvcm4ω'vֲ"a(%) + 'ɹi 98%x$U)N ӔJuMIs͎Zvb (D`^.'`A"!(4|p4JAKCa4>f^Ґ\yL jj6̾@,';WkYCR $0HNڨet,9 KG'5g|$hV(NH5Xeي$>s;:)@Dc]KsngIR['>0$$v˖-۶+<2XI9Dr. tuueG.G+M9L[nku390ڌ+q?,3flkOҔ,ewr߽ ĝ][S%X)T 0:m/)+.Q±,sQ@(-*tA#Ee iaElʨZ!QH*BS%h y)re}qƻj+Ø"ׯ±eqcr5ȱC0AؑxջO'Sm!LlW|C)6 Y:csI !TKlV>GsK!IK;rhL) x9cuJ:):<;_m9dhY:T7_7Ÿ 0 OY;H%:fjNRJZkl&NY`9A17]}23KOekolKaYqL fL5rTHV3ʎLg~c "K ؽrcTgL:B5FZ +xr?Pb_7ϖ>9MC]KKf rF^1mS E1[cĆ(R Y;}3@ DΖ\1 Vu%qCГ}&BđCʮ)<6F+CaCW2d,Cj3#r٬ ,mG-0]_eX)|?D)b ¼y1cz Ix^Iy"Orl"on,X.Ϯ.} 6س_ඐ'vhል޲J,| :A$lؿ P;^̎]lOYYDqHKwF\mӛo즢",r\%f3v!u+" "X=Zΰe?K`ޥnbuԉ/j!nfݥ-.G:b,փ]@I+`XU]!},Q*SEøE޳qK)6Vt&(Ɋ wLmLimN'$剈c/^(kPYDi6nt.CSMsne#-uC$W 뉀w`#orX2Kyk dR/?Y<[ݻu2q`L Pe-Mи>ܦ".cEHr_T=Za4fLUB%|XTy*4dRt`Z`NE2fJOhS^K5l08i焗)O˻8,*jF5{l ypKȦݚ~M[TCRq)wXh,'szNf7tݧsw6B'M(bJmoZ+bp3_z aE "0RJLaCNYS:pS0+]H'Mrr5P`4 0 5'KJhs3lʦtnФ$Vi;z2ӑfbCQρ:9E|3ZLo4H҉Ï묿\˖'C;kU7jz`Ĉ˞ާ٧ָeM/c[/ϸT h'%|@ *r$${5l:ZqL&T[6M :r:JCr;0.{'.#U~cTSO|.+Y7nXof ._n-yO/2"=)J"T!NoS ! 3FrR #zu? *<,E THc22IA2ddd4fAKV0^T+pIqHim58=RJcNZWjdm}dU@z-%j:SS)ɷUt5k@ibn潊]aMa C  cQqO<z-8×mDĘ[9B#@t_O[ A. 2]:y!(fLM{o8u-8kEk=Qh'j^Y=H P{(Mcbd+'fdTSr7kJLِqd4nGN=be3+Nu<GAۜ:9[=lzӑ|7 K|Q3sD)ߧIښ3%sIvulݫI]x,j݊׬w]. W8Upv?Nr`^i~X =mL%!C5lJ_g \f JQ=yŬTӭV2Wp@$`dv3IfA)rk9D@&#iLm0SjX+@ځlR`hv;+hkm3$UvlJjͱjmj ĭ]Ų,XnW\qEG9t]TL$N{拾 B/n )%o|illcJo|ihh@kSYlݺu<ÜwyXA~N'\h"efwbGbGb~͞MJE@ك<=ZR0%'wY]yQ'=SxV]ɓϊ{')xn ۧX:Sa.^2N"mg)ռU 9~7y.|/_XY<p޴4$ myk!^9c'zd2–}bwijO'DV4]CTzXIEm6K2ξ/RWa滩Ͱbչ$d =d&qL04dbnx_j;I+ \vm}|Cg>QN. Cywr-No:A`6]vW]uЇ*M7nW__<~̙3kfϞͣ>NGG?*nv>''lڴ+/۶OYNjIU^{YٳfM\\n8udb]Ê!iy4T=90G5 4A걀vLrLu;>S>'#xaCV,i{Bk$ FzJ#Ȥୗ$>α Lz`X24){%BwRfS'{f\aQEI%LGXEZ^Xwty&]VDT!H DV0MT#Ȧ%5u 6 4j/ xfZgPȏڼd2ŢE(477s֪(|RvZ.]JGG H)xhhh`ٲe@kE]rarXz5O>$AJ?O>$˗/}|1:i-%fi~u(H ֙ݞ81~l,uVUY-$RАe!+H' R5l jI0Y0Y2A h$# l,]DyTo{|_s]M|1gYp!Ogq###]\xᅄaG>N?t~i7O} ~]vdd2ɒ%Kp]\ql߾wH)Y~=?9ƕܴioۙ={6}}},_~wX,+WN ˲?OS/^袋WJT qlrL*bxxNz!V4 /&\@\!{7͕}"3jLF wF6mWj\F f(Cɗ?){B G4#a=PԔ\d[bձq|e{ e!KnckkgO~;y#z"͊TIB@ȶB9V9"XXb֦*ihh+*e˸뮻`z̛7w]| /dppk}sٳUV'Jq뭷7oO~l۶' oիW/իW344E.\ 7׿u?Z?aZoN;O}Sz|+_!HƲ,0d``_״n:.2կV;Z477W\_җضm_='iiiOyH$Hض]9bȅ^M7_z)R>Y0Y ߄dSrFȢiF4y)5%pCPʐ+BӨ < E39_zo(f\ˊD=i \2ۨ\1[5hD>د/*HΈsS]("!}U3*n.qz?h7i'*m_U{ܒP!6Q&aRj|RV:,„cr&nWk:b5h շ#&WxjR4ԦYcdteRh 롹VT+IE$1u:]{}R.9hhhu]nJ\qJ۶mŋ3o<0dɒ%<䓀q_-o!fΜɢExGٺu+vkA)ž}'1c .: C2bEpB0d…<~z.2fΜy_,N5)yWēYݕU#.+;=<4ED%4*P[xM"kͪ@) 7҄ʪ+ jc[JG85GL*!2baiX/;Z( ;M(6&2Q.SofȫaK/BPg#dZtD!:aZlaTV6"  BhMIZEh㓴j$ Ɩ`K ӃX4 'DZ-Ȧe٤Y4Muij3)GQuȦdsܩۤOϤV $cAP\.W>KPU[nk=G?²,FFF*|>㗿%Ü}\qx|wmochhBTvZ<#Wy^e?B _zr-\}۷n,X.֬Y\P{{{ٲe /6mݻZS(p]Sg?gw}$J<;&onロ 6;w.W]u{Xp!7tDZmO?O~x| _3g/}[n;35k֜"S08ZGrǟmBH,'I]}g=&cI(Vhё$Uh* xB뢵u]#eZi=<6!*5qI@9wJ56 % 3 ak2nF~&K&d!l+ -0AH;eҶOZX!1IHHeH\(-QZ"@"dS4H)H2R03&>5C:&Q&d6H8!T&NC)ɤ5Npl,"I#C&]X$L"Ķm8`َƳX6NPdΪyۋHǂ-[FsXWW\p'GZ/|#\uUs! Cwwwz뭕ŋ?_O{{;_|1o{ؿ?Vbڴi1Y|9/NSOqfQ뮻}C|k_ӟ4Bַw 7?[V$?PJ۷sW7 {%- block html_head -%} {% set nb_title = nb.metadata.get('title', '') or resources['metadata']['name'] %} {{nb_title}} {%- block html_head_js -%} {%- block html_head_js_jquery -%} {%- endblock html_head_js_jquery -%} {%- block html_head_js_requirejs -%} {%- endblock html_head_js_requirejs -%} {%- endblock html_head_js -%} {% block jupyter_widgets %} {%- if "widgets" in nb.metadata -%} {%- endif -%} {% endblock jupyter_widgets %} {% block extra_css %} {% endblock extra_css %} {% for css in resources.inlining.css -%} {% endfor %} {% block notebook_css %} {{ resources.include_css("static/style.css") }} {% endblock notebook_css %} {% block custom_css %} {% endblock custom_css %} {{ mathjax(resources.mathjax_url) }} {%- block html_head_css -%} {%- endblock html_head_css -%} {%- endblock html_head -%} {%- endblock header -%} {# using the body block like this makes is difficult to be composable, added body_content/body_cells block for that#} {% block body_header %}
{% endblock body_header %} {% block body_footer %}
{% endblock body_footer %} {% block footer %} {% block footer_js %} {% endblock footer_js %} {{ super() }} {% endblock footer %} static/000077500000000000000000000000001461373220400355745ustar00rootroot00000000000000nbconvert-7.16.4/docs/api_examples/template_path/project_templates/nbconvert/templates/classic_clonestyle.css000066400000000000000000010100171461373220400374460ustar00rootroot00000000000000nbconvert-7.16.4/docs/api_examples/template_path/project_templates/nbconvert/templates/classic_clone/static/*! * * Twitter Bootstrap * */ /*! * Bootstrap v3.3.7 (http://getbootstrap.com) * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ html { font-family: sans-serif; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } body { margin: 0; } article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } audio, canvas, progress, video { display: inline-block; vertical-align: baseline; } audio:not([controls]) { display: none; height: 0; } [hidden], template { display: none; } a { background-color: transparent; } a:active, a:hover { outline: 0; } abbr[title] { border-bottom: 1px dotted; } b, strong { font-weight: bold; } dfn { font-style: italic; } h1 { font-size: 2em; margin: 0.67em 0; } mark { background: #ff0; color: #000; } small { font-size: 80%; } sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } img { border: 0; } svg:not(:root) { overflow: hidden; } figure { margin: 1em 40px; } hr { box-sizing: content-box; height: 0; } pre { overflow: auto; } code, kbd, pre, samp { font-family: monospace, monospace; font-size: 1em; } button, input, optgroup, select, textarea { color: inherit; font: inherit; margin: 0; } button { overflow: visible; } button, select { text-transform: none; } button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; cursor: pointer; } button[disabled], html input[disabled] { cursor: default; } button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } input { line-height: normal; } input[type="checkbox"], input[type="radio"] { box-sizing: border-box; padding: 0; } input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { height: auto; } input[type="search"] { -webkit-appearance: textfield; box-sizing: content-box; } input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } legend { border: 0; padding: 0; } textarea { overflow: auto; } optgroup { font-weight: bold; } table { border-collapse: collapse; border-spacing: 0; } td, th { padding: 0; } /*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ @media print { *, *:before, *:after { background: transparent !important; box-shadow: none !important; text-shadow: none !important; } a, a:visited { text-decoration: underline; } a[href]:after { content: " (" attr(href) ")"; } abbr[title]:after { content: " (" attr(title) ")"; } a[href^="#"]:after, a[href^="javascript:"]:after { content: ""; } pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } thead { display: table-header-group; } tr, img { page-break-inside: avoid; } img { max-width: 100% !important; } p, h2, h3 { orphans: 3; widows: 3; } h2, h3 { page-break-after: avoid; } .navbar { display: none; } .btn > .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px solid #000; } .table { border-collapse: collapse !important; } .table td, .table th { background-color: #fff !important; } .table-bordered th, .table-bordered td { border: 1px solid #ddd !important; } } @font-face { font-family: "Glyphicons Halflings"; src: url("../components/bootstrap/fonts/glyphicons-halflings-regular.eot"); src: url("../components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"), url("../components/bootstrap/fonts/glyphicons-halflings-regular.woff2") format("woff2"), url("../components/bootstrap/fonts/glyphicons-halflings-regular.woff") format("woff"), url("../components/bootstrap/fonts/glyphicons-halflings-regular.ttf") format("truetype"), url("../components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") format("svg"); } .glyphicon { position: relative; top: 1px; display: inline-block; font-family: "Glyphicons Halflings"; font-style: normal; font-weight: normal; line-height: 1; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .glyphicon-asterisk:before { content: "\002a"; } .glyphicon-plus:before { content: "\002b"; } .glyphicon-euro:before, .glyphicon-eur:before { content: "\20ac"; } .glyphicon-minus:before { content: "\2212"; } .glyphicon-cloud:before { content: "\2601"; } .glyphicon-envelope:before { content: "\2709"; } .glyphicon-pencil:before { content: "\270f"; } .glyphicon-glass:before { content: "\e001"; } .glyphicon-music:before { content: "\e002"; } .glyphicon-search:before { content: "\e003"; } .glyphicon-heart:before { content: "\e005"; } .glyphicon-star:before { content: "\e006"; } .glyphicon-star-empty:before { content: "\e007"; } .glyphicon-user:before { content: "\e008"; } .glyphicon-film:before { content: "\e009"; } .glyphicon-th-large:before { content: "\e010"; } .glyphicon-th:before { content: "\e011"; } .glyphicon-th-list:before { content: "\e012"; } .glyphicon-ok:before { content: "\e013"; } .glyphicon-remove:before { content: "\e014"; } .glyphicon-zoom-in:before { content: "\e015"; } .glyphicon-zoom-out:before { content: "\e016"; } .glyphicon-off:before { content: "\e017"; } .glyphicon-signal:before { content: "\e018"; } .glyphicon-cog:before { content: "\e019"; } .glyphicon-trash:before { content: "\e020"; } .glyphicon-home:before { content: "\e021"; } .glyphicon-file:before { content: "\e022"; } .glyphicon-time:before { content: "\e023"; } .glyphicon-road:before { content: "\e024"; } .glyphicon-download-alt:before { content: "\e025"; } .glyphicon-download:before { content: "\e026"; } .glyphicon-upload:before { content: "\e027"; } .glyphicon-inbox:before { content: "\e028"; } .glyphicon-play-circle:before { content: "\e029"; } .glyphicon-repeat:before { content: "\e030"; } .glyphicon-refresh:before { content: "\e031"; } .glyphicon-list-alt:before { content: "\e032"; } .glyphicon-lock:before { content: "\e033"; } .glyphicon-flag:before { content: "\e034"; } .glyphicon-headphones:before { content: "\e035"; } .glyphicon-volume-off:before { content: "\e036"; } .glyphicon-volume-down:before { content: "\e037"; } .glyphicon-volume-up:before { content: "\e038"; } .glyphicon-qrcode:before { content: "\e039"; } .glyphicon-barcode:before { content: "\e040"; } .glyphicon-tag:before { content: "\e041"; } .glyphicon-tags:before { content: "\e042"; } .glyphicon-book:before { content: "\e043"; } .glyphicon-bookmark:before { content: "\e044"; } .glyphicon-print:before { content: "\e045"; } .glyphicon-camera:before { content: "\e046"; } .glyphicon-font:before { content: "\e047"; } .glyphicon-bold:before { content: "\e048"; } .glyphicon-italic:before { content: "\e049"; } .glyphicon-text-height:before { content: "\e050"; } .glyphicon-text-width:before { content: "\e051"; } .glyphicon-align-left:before { content: "\e052"; } .glyphicon-align-center:before { content: "\e053"; } .glyphicon-align-right:before { content: "\e054"; } .glyphicon-align-justify:before { content: "\e055"; } .glyphicon-list:before { content: "\e056"; } .glyphicon-indent-left:before { content: "\e057"; } .glyphicon-indent-right:before { content: "\e058"; } .glyphicon-facetime-video:before { content: "\e059"; } .glyphicon-picture:before { content: "\e060"; } .glyphicon-map-marker:before { content: "\e062"; } .glyphicon-adjust:before { content: "\e063"; } .glyphicon-tint:before { content: "\e064"; } .glyphicon-edit:before { content: "\e065"; } .glyphicon-share:before { content: "\e066"; } .glyphicon-check:before { content: "\e067"; } .glyphicon-move:before { content: "\e068"; } .glyphicon-step-backward:before { content: "\e069"; } .glyphicon-fast-backward:before { content: "\e070"; } .glyphicon-backward:before { content: "\e071"; } .glyphicon-play:before { content: "\e072"; } .glyphicon-pause:before { content: "\e073"; } .glyphicon-stop:before { content: "\e074"; } .glyphicon-forward:before { content: "\e075"; } .glyphicon-fast-forward:before { content: "\e076"; } .glyphicon-step-forward:before { content: "\e077"; } .glyphicon-eject:before { content: "\e078"; } .glyphicon-chevron-left:before { content: "\e079"; } .glyphicon-chevron-right:before { content: "\e080"; } .glyphicon-plus-sign:before { content: "\e081"; } .glyphicon-minus-sign:before { content: "\e082"; } .glyphicon-remove-sign:before { content: "\e083"; } .glyphicon-ok-sign:before { content: "\e084"; } .glyphicon-question-sign:before { content: "\e085"; } .glyphicon-info-sign:before { content: "\e086"; } .glyphicon-screenshot:before { content: "\e087"; } .glyphicon-remove-circle:before { content: "\e088"; } .glyphicon-ok-circle:before { content: "\e089"; } .glyphicon-ban-circle:before { content: "\e090"; } .glyphicon-arrow-left:before { content: "\e091"; } .glyphicon-arrow-right:before { content: "\e092"; } .glyphicon-arrow-up:before { content: "\e093"; } .glyphicon-arrow-down:before { content: "\e094"; } .glyphicon-share-alt:before { content: "\e095"; } .glyphicon-resize-full:before { content: "\e096"; } .glyphicon-resize-small:before { content: "\e097"; } .glyphicon-exclamation-sign:before { content: "\e101"; } .glyphicon-gift:before { content: "\e102"; } .glyphicon-leaf:before { content: "\e103"; } .glyphicon-fire:before { content: "\e104"; } .glyphicon-eye-open:before { content: "\e105"; } .glyphicon-eye-close:before { content: "\e106"; } .glyphicon-warning-sign:before { content: "\e107"; } .glyphicon-plane:before { content: "\e108"; } .glyphicon-calendar:before { content: "\e109"; } .glyphicon-random:before { content: "\e110"; } .glyphicon-comment:before { content: "\e111"; } .glyphicon-magnet:before { content: "\e112"; } .glyphicon-chevron-up:before { content: "\e113"; } .glyphicon-chevron-down:before { content: "\e114"; } .glyphicon-retweet:before { content: "\e115"; } .glyphicon-shopping-cart:before { content: "\e116"; } .glyphicon-folder-close:before { content: "\e117"; } .glyphicon-folder-open:before { content: "\e118"; } .glyphicon-resize-vertical:before { content: "\e119"; } .glyphicon-resize-horizontal:before { content: "\e120"; } .glyphicon-hdd:before { content: "\e121"; } .glyphicon-bullhorn:before { content: "\e122"; } .glyphicon-bell:before { content: "\e123"; } .glyphicon-certificate:before { content: "\e124"; } .glyphicon-thumbs-up:before { content: "\e125"; } .glyphicon-thumbs-down:before { content: "\e126"; } .glyphicon-hand-right:before { content: "\e127"; } .glyphicon-hand-left:before { content: "\e128"; } .glyphicon-hand-up:before { content: "\e129"; } .glyphicon-hand-down:before { content: "\e130"; } .glyphicon-circle-arrow-right:before { content: "\e131"; } .glyphicon-circle-arrow-left:before { content: "\e132"; } .glyphicon-circle-arrow-up:before { content: "\e133"; } .glyphicon-circle-arrow-down:before { content: "\e134"; } .glyphicon-globe:before { content: "\e135"; } .glyphicon-wrench:before { content: "\e136"; } .glyphicon-tasks:before { content: "\e137"; } .glyphicon-filter:before { content: "\e138"; } .glyphicon-briefcase:before { content: "\e139"; } .glyphicon-fullscreen:before { content: "\e140"; } .glyphicon-dashboard:before { content: "\e141"; } .glyphicon-paperclip:before { content: "\e142"; } .glyphicon-heart-empty:before { content: "\e143"; } .glyphicon-link:before { content: "\e144"; } .glyphicon-phone:before { content: "\e145"; } .glyphicon-pushpin:before { content: "\e146"; } .glyphicon-usd:before { content: "\e148"; } .glyphicon-gbp:before { content: "\e149"; } .glyphicon-sort:before { content: "\e150"; } .glyphicon-sort-by-alphabet:before { content: "\e151"; } .glyphicon-sort-by-alphabet-alt:before { content: "\e152"; } .glyphicon-sort-by-order:before { content: "\e153"; } .glyphicon-sort-by-order-alt:before { content: "\e154"; } .glyphicon-sort-by-attributes:before { content: "\e155"; } .glyphicon-sort-by-attributes-alt:before { content: "\e156"; } .glyphicon-unchecked:before { content: "\e157"; } .glyphicon-expand:before { content: "\e158"; } .glyphicon-collapse-down:before { content: "\e159"; } .glyphicon-collapse-up:before { content: "\e160"; } .glyphicon-log-in:before { content: "\e161"; } .glyphicon-flash:before { content: "\e162"; } .glyphicon-log-out:before { content: "\e163"; } .glyphicon-new-window:before { content: "\e164"; } .glyphicon-record:before { content: "\e165"; } .glyphicon-save:before { content: "\e166"; } .glyphicon-open:before { content: "\e167"; } .glyphicon-saved:before { content: "\e168"; } .glyphicon-import:before { content: "\e169"; } .glyphicon-export:before { content: "\e170"; } .glyphicon-send:before { content: "\e171"; } .glyphicon-floppy-disk:before { content: "\e172"; } .glyphicon-floppy-saved:before { content: "\e173"; } .glyphicon-floppy-remove:before { content: "\e174"; } .glyphicon-floppy-save:before { content: "\e175"; } .glyphicon-floppy-open:before { content: "\e176"; } .glyphicon-credit-card:before { content: "\e177"; } .glyphicon-transfer:before { content: "\e178"; } .glyphicon-cutlery:before { content: "\e179"; } .glyphicon-header:before { content: "\e180"; } .glyphicon-compressed:before { content: "\e181"; } .glyphicon-earphone:before { content: "\e182"; } .glyphicon-phone-alt:before { content: "\e183"; } .glyphicon-tower:before { content: "\e184"; } .glyphicon-stats:before { content: "\e185"; } .glyphicon-sd-video:before { content: "\e186"; } .glyphicon-hd-video:before { content: "\e187"; } .glyphicon-subtitles:before { content: "\e188"; } .glyphicon-sound-stereo:before { content: "\e189"; } .glyphicon-sound-dolby:before { content: "\e190"; } .glyphicon-sound-5-1:before { content: "\e191"; } .glyphicon-sound-6-1:before { content: "\e192"; } .glyphicon-sound-7-1:before { content: "\e193"; } .glyphicon-copyright-mark:before { content: "\e194"; } .glyphicon-registration-mark:before { content: "\e195"; } .glyphicon-cloud-download:before { content: "\e197"; } .glyphicon-cloud-upload:before { content: "\e198"; } .glyphicon-tree-conifer:before { content: "\e199"; } .glyphicon-tree-deciduous:before { content: "\e200"; } .glyphicon-cd:before { content: "\e201"; } .glyphicon-save-file:before { content: "\e202"; } .glyphicon-open-file:before { content: "\e203"; } .glyphicon-level-up:before { content: "\e204"; } .glyphicon-copy:before { content: "\e205"; } .glyphicon-paste:before { content: "\e206"; } .glyphicon-alert:before { content: "\e209"; } .glyphicon-equalizer:before { content: "\e210"; } .glyphicon-king:before { content: "\e211"; } .glyphicon-queen:before { content: "\e212"; } .glyphicon-pawn:before { content: "\e213"; } .glyphicon-bishop:before { content: "\e214"; } .glyphicon-knight:before { content: "\e215"; } .glyphicon-baby-formula:before { content: "\e216"; } .glyphicon-tent:before { content: "\26fa"; } .glyphicon-blackboard:before { content: "\e218"; } .glyphicon-bed:before { content: "\e219"; } .glyphicon-apple:before { content: "\f8ff"; } .glyphicon-erase:before { content: "\e221"; } .glyphicon-hourglass:before { content: "\231b"; } .glyphicon-lamp:before { content: "\e223"; } .glyphicon-duplicate:before { content: "\e224"; } .glyphicon-piggy-bank:before { content: "\e225"; } .glyphicon-scissors:before { content: "\e226"; } .glyphicon-bitcoin:before { content: "\e227"; } .glyphicon-btc:before { content: "\e227"; } .glyphicon-xbt:before { content: "\e227"; } .glyphicon-yen:before { content: "\00a5"; } .glyphicon-jpy:before { content: "\00a5"; } .glyphicon-ruble:before { content: "\20bd"; } .glyphicon-rub:before { content: "\20bd"; } .glyphicon-scale:before { content: "\e230"; } .glyphicon-ice-lolly:before { content: "\e231"; } .glyphicon-ice-lolly-tasted:before { content: "\e232"; } .glyphicon-education:before { content: "\e233"; } .glyphicon-option-horizontal:before { content: "\e234"; } .glyphicon-option-vertical:before { content: "\e235"; } .glyphicon-menu-hamburger:before { content: "\e236"; } .glyphicon-modal-window:before { content: "\e237"; } .glyphicon-oil:before { content: "\e238"; } .glyphicon-grain:before { content: "\e239"; } .glyphicon-sunglasses:before { content: "\e240"; } .glyphicon-text-size:before { content: "\e241"; } .glyphicon-text-color:before { content: "\e242"; } .glyphicon-text-background:before { content: "\e243"; } .glyphicon-object-align-top:before { content: "\e244"; } .glyphicon-object-align-bottom:before { content: "\e245"; } .glyphicon-object-align-horizontal:before { content: "\e246"; } .glyphicon-object-align-left:before { content: "\e247"; } .glyphicon-object-align-vertical:before { content: "\e248"; } .glyphicon-object-align-right:before { content: "\e249"; } .glyphicon-triangle-right:before { content: "\e250"; } .glyphicon-triangle-left:before { content: "\e251"; } .glyphicon-triangle-bottom:before { content: "\e252"; } .glyphicon-triangle-top:before { content: "\e253"; } .glyphicon-console:before { content: "\e254"; } .glyphicon-superscript:before { content: "\e255"; } .glyphicon-subscript:before { content: "\e256"; } .glyphicon-menu-left:before { content: "\e257"; } .glyphicon-menu-right:before { content: "\e258"; } .glyphicon-menu-down:before { content: "\e259"; } .glyphicon-menu-up:before { content: "\e260"; } * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } *:before, *:after { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } html { font-size: 10px; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; line-height: 1.42857143; color: #000; background-color: #fff; } input, button, select, textarea { font-family: inherit; font-size: inherit; line-height: inherit; } a { color: #337ab7; text-decoration: none; } a:hover, a:focus { color: #23527c; text-decoration: underline; } a:focus { outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } figure { margin: 0; } img { vertical-align: middle; } .img-responsive, .thumbnail > img, .thumbnail a > img, .carousel-inner > .item > img, .carousel-inner > .item > a > img { display: block; max-width: 100%; height: auto; } .img-rounded { border-radius: 3px; } .img-thumbnail { padding: 4px; line-height: 1.42857143; background-color: #fff; border: 1px solid #ddd; border-radius: 2px; -webkit-transition: all 0.2s ease-in-out; -o-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; display: inline-block; max-width: 100%; height: auto; } .img-circle { border-radius: 50%; } hr { margin-top: 18px; margin-bottom: 18px; border: 0; border-top: 1px solid #eeeeee; } .sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; } .sr-only-focusable:active, .sr-only-focusable:focus { position: static; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; } [role="button"] { cursor: pointer; } h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { font-family: inherit; font-weight: 500; line-height: 1.1; color: inherit; } h1 small, h2 small, h3 small, h4 small, h5 small, h6 small, .h1 small, .h2 small, .h3 small, .h4 small, .h5 small, .h6 small, h1 .small, h2 .small, h3 .small, h4 .small, h5 .small, h6 .small, .h1 .small, .h2 .small, .h3 .small, .h4 .small, .h5 .small, .h6 .small { font-weight: normal; line-height: 1; color: #777777; } h1, .h1, h2, .h2, h3, .h3 { margin-top: 18px; margin-bottom: 9px; } h1 small, .h1 small, h2 small, .h2 small, h3 small, .h3 small, h1 .small, .h1 .small, h2 .small, .h2 .small, h3 .small, .h3 .small { font-size: 65%; } h4, .h4, h5, .h5, h6, .h6 { margin-top: 9px; margin-bottom: 9px; } h4 small, .h4 small, h5 small, .h5 small, h6 small, .h6 small, h4 .small, .h4 .small, h5 .small, .h5 .small, h6 .small, .h6 .small { font-size: 75%; } h1, .h1 { font-size: 33px; } h2, .h2 { font-size: 27px; } h3, .h3 { font-size: 23px; } h4, .h4 { font-size: 17px; } h5, .h5 { font-size: 13px; } h6, .h6 { font-size: 12px; } p { margin: 0 0 9px; } .lead { margin-bottom: 18px; font-size: 14px; font-weight: 300; line-height: 1.4; } @media (min-width: 768px) { .lead { font-size: 19.5px; } } small, .small { font-size: 92%; } mark, .mark { background-color: #fcf8e3; padding: 0.2em; } .text-left { text-align: left; } .text-right { text-align: right; } .text-center { text-align: center; } .text-justify { text-align: justify; } .text-nowrap { white-space: nowrap; } .text-lowercase { text-transform: lowercase; } .text-uppercase { text-transform: uppercase; } .text-capitalize { text-transform: capitalize; } .text-muted { color: #777777; } .text-primary { color: #337ab7; } a.text-primary:hover, a.text-primary:focus { color: #286090; } .text-success { color: #3c763d; } a.text-success:hover, a.text-success:focus { color: #2b542c; } .text-info { color: #31708f; } a.text-info:hover, a.text-info:focus { color: #245269; } .text-warning { color: #8a6d3b; } a.text-warning:hover, a.text-warning:focus { color: #66512c; } .text-danger { color: #a94442; } a.text-danger:hover, a.text-danger:focus { color: #843534; } .bg-primary { color: #fff; background-color: #337ab7; } a.bg-primary:hover, a.bg-primary:focus { background-color: #286090; } .bg-success { background-color: #dff0d8; } a.bg-success:hover, a.bg-success:focus { background-color: #c1e2b3; } .bg-info { background-color: #d9edf7; } a.bg-info:hover, a.bg-info:focus { background-color: #afd9ee; } .bg-warning { background-color: #fcf8e3; } a.bg-warning:hover, a.bg-warning:focus { background-color: #f7ecb5; } .bg-danger { background-color: #f2dede; } a.bg-danger:hover, a.bg-danger:focus { background-color: #e4b9b9; } .page-header { padding-bottom: 8px; margin: 36px 0 18px; border-bottom: 1px solid #eeeeee; } ul, ol { margin-top: 0; margin-bottom: 9px; } ul ul, ol ul, ul ol, ol ol { margin-bottom: 0; } .list-unstyled { padding-left: 0; list-style: none; } .list-inline { padding-left: 0; list-style: none; margin-left: -5px; } .list-inline > li { display: inline-block; padding-left: 5px; padding-right: 5px; } dl { margin-top: 0; margin-bottom: 18px; } dt, dd { line-height: 1.42857143; } dt { font-weight: bold; } dd { margin-left: 0; } @media (min-width: 541px) { .dl-horizontal dt { float: left; width: 160px; clear: left; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .dl-horizontal dd { margin-left: 180px; } } abbr[title], abbr[data-original-title] { cursor: help; border-bottom: 1px dotted #777777; } .initialism { font-size: 90%; text-transform: uppercase; } blockquote { padding: 9px 18px; margin: 0 0 18px; font-size: inherit; border-left: 5px solid #eeeeee; } blockquote p:last-child, blockquote ul:last-child, blockquote ol:last-child { margin-bottom: 0; } blockquote footer, blockquote small, blockquote .small { display: block; font-size: 80%; line-height: 1.42857143; color: #777777; } blockquote footer:before, blockquote small:before, blockquote .small:before { content: "\2014 \00A0"; } .blockquote-reverse, blockquote.pull-right { padding-right: 15px; padding-left: 0; border-right: 5px solid #eeeeee; border-left: 0; text-align: right; } .blockquote-reverse footer:before, blockquote.pull-right footer:before, .blockquote-reverse small:before, blockquote.pull-right small:before, .blockquote-reverse .small:before, blockquote.pull-right .small:before { content: ""; } .blockquote-reverse footer:after, blockquote.pull-right footer:after, .blockquote-reverse small:after, blockquote.pull-right small:after, .blockquote-reverse .small:after, blockquote.pull-right .small:after { content: "\00A0 \2014"; } address { margin-bottom: 18px; font-style: normal; line-height: 1.42857143; } code, kbd, pre, samp { font-family: monospace; } code { padding: 2px 4px; font-size: 90%; color: #c7254e; background-color: #f9f2f4; border-radius: 2px; } kbd { padding: 2px 4px; font-size: 90%; color: #888; background-color: transparent; border-radius: 1px; box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); } kbd kbd { padding: 0; font-size: 100%; font-weight: bold; box-shadow: none; } pre { display: block; padding: 8.5px; margin: 0 0 9px; font-size: 12px; line-height: 1.42857143; word-break: break-all; word-wrap: break-word; color: #333333; background-color: #f5f5f5; border: 1px solid #ccc; border-radius: 2px; } pre code { padding: 0; font-size: inherit; color: inherit; white-space: pre-wrap; background-color: transparent; border-radius: 0; } .pre-scrollable { max-height: 340px; overflow-y: scroll; } .container { margin-right: auto; margin-left: auto; padding-left: 0px; padding-right: 0px; } @media (min-width: 768px) { .container { width: 768px; } } @media (min-width: 992px) { .container { width: 940px; } } @media (min-width: 1200px) { .container { width: 1140px; } } .container-fluid { margin-right: auto; margin-left: auto; padding-left: 0px; padding-right: 0px; } .row { margin-left: 0px; margin-right: 0px; } .col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { position: relative; min-height: 1px; padding-left: 0px; padding-right: 0px; } .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { float: left; } .col-xs-12 { width: 100%; } .col-xs-11 { width: 91.66666667%; } .col-xs-10 { width: 83.33333333%; } .col-xs-9 { width: 75%; } .col-xs-8 { width: 66.66666667%; } .col-xs-7 { width: 58.33333333%; } .col-xs-6 { width: 50%; } .col-xs-5 { width: 41.66666667%; } .col-xs-4 { width: 33.33333333%; } .col-xs-3 { width: 25%; } .col-xs-2 { width: 16.66666667%; } .col-xs-1 { width: 8.33333333%; } .col-xs-pull-12 { right: 100%; } .col-xs-pull-11 { right: 91.66666667%; } .col-xs-pull-10 { right: 83.33333333%; } .col-xs-pull-9 { right: 75%; } .col-xs-pull-8 { right: 66.66666667%; } .col-xs-pull-7 { right: 58.33333333%; } .col-xs-pull-6 { right: 50%; } .col-xs-pull-5 { right: 41.66666667%; } .col-xs-pull-4 { right: 33.33333333%; } .col-xs-pull-3 { right: 25%; } .col-xs-pull-2 { right: 16.66666667%; } .col-xs-pull-1 { right: 8.33333333%; } .col-xs-pull-0 { right: auto; } .col-xs-push-12 { left: 100%; } .col-xs-push-11 { left: 91.66666667%; } .col-xs-push-10 { left: 83.33333333%; } .col-xs-push-9 { left: 75%; } .col-xs-push-8 { left: 66.66666667%; } .col-xs-push-7 { left: 58.33333333%; } .col-xs-push-6 { left: 50%; } .col-xs-push-5 { left: 41.66666667%; } .col-xs-push-4 { left: 33.33333333%; } .col-xs-push-3 { left: 25%; } .col-xs-push-2 { left: 16.66666667%; } .col-xs-push-1 { left: 8.33333333%; } .col-xs-push-0 { left: auto; } .col-xs-offset-12 { margin-left: 100%; } .col-xs-offset-11 { margin-left: 91.66666667%; } .col-xs-offset-10 { margin-left: 83.33333333%; } .col-xs-offset-9 { margin-left: 75%; } .col-xs-offset-8 { margin-left: 66.66666667%; } .col-xs-offset-7 { margin-left: 58.33333333%; } .col-xs-offset-6 { margin-left: 50%; } .col-xs-offset-5 { margin-left: 41.66666667%; } .col-xs-offset-4 { margin-left: 33.33333333%; } .col-xs-offset-3 { margin-left: 25%; } .col-xs-offset-2 { margin-left: 16.66666667%; } .col-xs-offset-1 { margin-left: 8.33333333%; } .col-xs-offset-0 { margin-left: 0%; } @media (min-width: 768px) { .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { float: left; } .col-sm-12 { width: 100%; } .col-sm-11 { width: 91.66666667%; } .col-sm-10 { width: 83.33333333%; } .col-sm-9 { width: 75%; } .col-sm-8 { width: 66.66666667%; } .col-sm-7 { width: 58.33333333%; } .col-sm-6 { width: 50%; } .col-sm-5 { width: 41.66666667%; } .col-sm-4 { width: 33.33333333%; } .col-sm-3 { width: 25%; } .col-sm-2 { width: 16.66666667%; } .col-sm-1 { width: 8.33333333%; } .col-sm-pull-12 { right: 100%; } .col-sm-pull-11 { right: 91.66666667%; } .col-sm-pull-10 { right: 83.33333333%; } .col-sm-pull-9 { right: 75%; } .col-sm-pull-8 { right: 66.66666667%; } .col-sm-pull-7 { right: 58.33333333%; } .col-sm-pull-6 { right: 50%; } .col-sm-pull-5 { right: 41.66666667%; } .col-sm-pull-4 { right: 33.33333333%; } .col-sm-pull-3 { right: 25%; } .col-sm-pull-2 { right: 16.66666667%; } .col-sm-pull-1 { right: 8.33333333%; } .col-sm-pull-0 { right: auto; } .col-sm-push-12 { left: 100%; } .col-sm-push-11 { left: 91.66666667%; } .col-sm-push-10 { left: 83.33333333%; } .col-sm-push-9 { left: 75%; } .col-sm-push-8 { left: 66.66666667%; } .col-sm-push-7 { left: 58.33333333%; } .col-sm-push-6 { left: 50%; } .col-sm-push-5 { left: 41.66666667%; } .col-sm-push-4 { left: 33.33333333%; } .col-sm-push-3 { left: 25%; } .col-sm-push-2 { left: 16.66666667%; } .col-sm-push-1 { left: 8.33333333%; } .col-sm-push-0 { left: auto; } .col-sm-offset-12 { margin-left: 100%; } .col-sm-offset-11 { margin-left: 91.66666667%; } .col-sm-offset-10 { margin-left: 83.33333333%; } .col-sm-offset-9 { margin-left: 75%; } .col-sm-offset-8 { margin-left: 66.66666667%; } .col-sm-offset-7 { margin-left: 58.33333333%; } .col-sm-offset-6 { margin-left: 50%; } .col-sm-offset-5 { margin-left: 41.66666667%; } .col-sm-offset-4 { margin-left: 33.33333333%; } .col-sm-offset-3 { margin-left: 25%; } .col-sm-offset-2 { margin-left: 16.66666667%; } .col-sm-offset-1 { margin-left: 8.33333333%; } .col-sm-offset-0 { margin-left: 0%; } } @media (min-width: 992px) { .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { float: left; } .col-md-12 { width: 100%; } .col-md-11 { width: 91.66666667%; } .col-md-10 { width: 83.33333333%; } .col-md-9 { width: 75%; } .col-md-8 { width: 66.66666667%; } .col-md-7 { width: 58.33333333%; } .col-md-6 { width: 50%; } .col-md-5 { width: 41.66666667%; } .col-md-4 { width: 33.33333333%; } .col-md-3 { width: 25%; } .col-md-2 { width: 16.66666667%; } .col-md-1 { width: 8.33333333%; } .col-md-pull-12 { right: 100%; } .col-md-pull-11 { right: 91.66666667%; } .col-md-pull-10 { right: 83.33333333%; } .col-md-pull-9 { right: 75%; } .col-md-pull-8 { right: 66.66666667%; } .col-md-pull-7 { right: 58.33333333%; } .col-md-pull-6 { right: 50%; } .col-md-pull-5 { right: 41.66666667%; } .col-md-pull-4 { right: 33.33333333%; } .col-md-pull-3 { right: 25%; } .col-md-pull-2 { right: 16.66666667%; } .col-md-pull-1 { right: 8.33333333%; } .col-md-pull-0 { right: auto; } .col-md-push-12 { left: 100%; } .col-md-push-11 { left: 91.66666667%; } .col-md-push-10 { left: 83.33333333%; } .col-md-push-9 { left: 75%; } .col-md-push-8 { left: 66.66666667%; } .col-md-push-7 { left: 58.33333333%; } .col-md-push-6 { left: 50%; } .col-md-push-5 { left: 41.66666667%; } .col-md-push-4 { left: 33.33333333%; } .col-md-push-3 { left: 25%; } .col-md-push-2 { left: 16.66666667%; } .col-md-push-1 { left: 8.33333333%; } .col-md-push-0 { left: auto; } .col-md-offset-12 { margin-left: 100%; } .col-md-offset-11 { margin-left: 91.66666667%; } .col-md-offset-10 { margin-left: 83.33333333%; } .col-md-offset-9 { margin-left: 75%; } .col-md-offset-8 { margin-left: 66.66666667%; } .col-md-offset-7 { margin-left: 58.33333333%; } .col-md-offset-6 { margin-left: 50%; } .col-md-offset-5 { margin-left: 41.66666667%; } .col-md-offset-4 { margin-left: 33.33333333%; } .col-md-offset-3 { margin-left: 25%; } .col-md-offset-2 { margin-left: 16.66666667%; } .col-md-offset-1 { margin-left: 8.33333333%; } .col-md-offset-0 { margin-left: 0%; } } @media (min-width: 1200px) { .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { float: left; } .col-lg-12 { width: 100%; } .col-lg-11 { width: 91.66666667%; } .col-lg-10 { width: 83.33333333%; } .col-lg-9 { width: 75%; } .col-lg-8 { width: 66.66666667%; } .col-lg-7 { width: 58.33333333%; } .col-lg-6 { width: 50%; } .col-lg-5 { width: 41.66666667%; } .col-lg-4 { width: 33.33333333%; } .col-lg-3 { width: 25%; } .col-lg-2 { width: 16.66666667%; } .col-lg-1 { width: 8.33333333%; } .col-lg-pull-12 { right: 100%; } .col-lg-pull-11 { right: 91.66666667%; } .col-lg-pull-10 { right: 83.33333333%; } .col-lg-pull-9 { right: 75%; } .col-lg-pull-8 { right: 66.66666667%; } .col-lg-pull-7 { right: 58.33333333%; } .col-lg-pull-6 { right: 50%; } .col-lg-pull-5 { right: 41.66666667%; } .col-lg-pull-4 { right: 33.33333333%; } .col-lg-pull-3 { right: 25%; } .col-lg-pull-2 { right: 16.66666667%; } .col-lg-pull-1 { right: 8.33333333%; } .col-lg-pull-0 { right: auto; } .col-lg-push-12 { left: 100%; } .col-lg-push-11 { left: 91.66666667%; } .col-lg-push-10 { left: 83.33333333%; } .col-lg-push-9 { left: 75%; } .col-lg-push-8 { left: 66.66666667%; } .col-lg-push-7 { left: 58.33333333%; } .col-lg-push-6 { left: 50%; } .col-lg-push-5 { left: 41.66666667%; } .col-lg-push-4 { left: 33.33333333%; } .col-lg-push-3 { left: 25%; } .col-lg-push-2 { left: 16.66666667%; } .col-lg-push-1 { left: 8.33333333%; } .col-lg-push-0 { left: auto; } .col-lg-offset-12 { margin-left: 100%; } .col-lg-offset-11 { margin-left: 91.66666667%; } .col-lg-offset-10 { margin-left: 83.33333333%; } .col-lg-offset-9 { margin-left: 75%; } .col-lg-offset-8 { margin-left: 66.66666667%; } .col-lg-offset-7 { margin-left: 58.33333333%; } .col-lg-offset-6 { margin-left: 50%; } .col-lg-offset-5 { margin-left: 41.66666667%; } .col-lg-offset-4 { margin-left: 33.33333333%; } .col-lg-offset-3 { margin-left: 25%; } .col-lg-offset-2 { margin-left: 16.66666667%; } .col-lg-offset-1 { margin-left: 8.33333333%; } .col-lg-offset-0 { margin-left: 0%; } } table { background-color: transparent; } caption { padding-top: 8px; padding-bottom: 8px; color: #777777; text-align: left; } th { text-align: left; } .table { width: 100%; max-width: 100%; margin-bottom: 18px; } .table > thead > tr > th, .table > tbody > tr > th, .table > tfoot > tr > th, .table > thead > tr > td, .table > tbody > tr > td, .table > tfoot > tr > td { padding: 8px; line-height: 1.42857143; vertical-align: top; border-top: 1px solid #ddd; } .table > thead > tr > th { vertical-align: bottom; border-bottom: 2px solid #ddd; } .table > caption + thead > tr:first-child > th, .table > colgroup + thead > tr:first-child > th, .table > thead:first-child > tr:first-child > th, .table > caption + thead > tr:first-child > td, .table > colgroup + thead > tr:first-child > td, .table > thead:first-child > tr:first-child > td { border-top: 0; } .table > tbody + tbody { border-top: 2px solid #ddd; } .table .table { background-color: #fff; } .table-condensed > thead > tr > th, .table-condensed > tbody > tr > th, .table-condensed > tfoot > tr > th, .table-condensed > thead > tr > td, .table-condensed > tbody > tr > td, .table-condensed > tfoot > tr > td { padding: 5px; } .table-bordered { border: 1px solid #ddd; } .table-bordered > thead > tr > th, .table-bordered > tbody > tr > th, .table-bordered > tfoot > tr > th, .table-bordered > thead > tr > td, .table-bordered > tbody > tr > td, .table-bordered > tfoot > tr > td { border: 1px solid #ddd; } .table-bordered > thead > tr > th, .table-bordered > thead > tr > td { border-bottom-width: 2px; } .table-striped > tbody > tr:nth-of-type(odd) { background-color: #f9f9f9; } .table-hover > tbody > tr:hover { background-color: #f5f5f5; } table col[class*="col-"] { position: static; float: none; display: table-column; } table td[class*="col-"], table th[class*="col-"] { position: static; float: none; display: table-cell; } .table > thead > tr > td.active, .table > tbody > tr > td.active, .table > tfoot > tr > td.active, .table > thead > tr > th.active, .table > tbody > tr > th.active, .table > tfoot > tr > th.active, .table > thead > tr.active > td, .table > tbody > tr.active > td, .table > tfoot > tr.active > td, .table > thead > tr.active > th, .table > tbody > tr.active > th, .table > tfoot > tr.active > th { background-color: #f5f5f5; } .table-hover > tbody > tr > td.active:hover, .table-hover > tbody > tr > th.active:hover, .table-hover > tbody > tr.active:hover > td, .table-hover > tbody > tr:hover > .active, .table-hover > tbody > tr.active:hover > th { background-color: #e8e8e8; } .table > thead > tr > td.success, .table > tbody > tr > td.success, .table > tfoot > tr > td.success, .table > thead > tr > th.success, .table > tbody > tr > th.success, .table > tfoot > tr > th.success, .table > thead > tr.success > td, .table > tbody > tr.success > td, .table > tfoot > tr.success > td, .table > thead > tr.success > th, .table > tbody > tr.success > th, .table > tfoot > tr.success > th { background-color: #dff0d8; } .table-hover > tbody > tr > td.success:hover, .table-hover > tbody > tr > th.success:hover, .table-hover > tbody > tr.success:hover > td, .table-hover > tbody > tr:hover > .success, .table-hover > tbody > tr.success:hover > th { background-color: #d0e9c6; } .table > thead > tr > td.info, .table > tbody > tr > td.info, .table > tfoot > tr > td.info, .table > thead > tr > th.info, .table > tbody > tr > th.info, .table > tfoot > tr > th.info, .table > thead > tr.info > td, .table > tbody > tr.info > td, .table > tfoot > tr.info > td, .table > thead > tr.info > th, .table > tbody > tr.info > th, .table > tfoot > tr.info > th { background-color: #d9edf7; } .table-hover > tbody > tr > td.info:hover, .table-hover > tbody > tr > th.info:hover, .table-hover > tbody > tr.info:hover > td, .table-hover > tbody > tr:hover > .info, .table-hover > tbody > tr.info:hover > th { background-color: #c4e3f3; } .table > thead > tr > td.warning, .table > tbody > tr > td.warning, .table > tfoot > tr > td.warning, .table > thead > tr > th.warning, .table > tbody > tr > th.warning, .table > tfoot > tr > th.warning, .table > thead > tr.warning > td, .table > tbody > tr.warning > td, .table > tfoot > tr.warning > td, .table > thead > tr.warning > th, .table > tbody > tr.warning > th, .table > tfoot > tr.warning > th { background-color: #fcf8e3; } .table-hover > tbody > tr > td.warning:hover, .table-hover > tbody > tr > th.warning:hover, .table-hover > tbody > tr.warning:hover > td, .table-hover > tbody > tr:hover > .warning, .table-hover > tbody > tr.warning:hover > th { background-color: #faf2cc; } .table > thead > tr > td.danger, .table > tbody > tr > td.danger, .table > tfoot > tr > td.danger, .table > thead > tr > th.danger, .table > tbody > tr > th.danger, .table > tfoot > tr > th.danger, .table > thead > tr.danger > td, .table > tbody > tr.danger > td, .table > tfoot > tr.danger > td, .table > thead > tr.danger > th, .table > tbody > tr.danger > th, .table > tfoot > tr.danger > th { background-color: #f2dede; } .table-hover > tbody > tr > td.danger:hover, .table-hover > tbody > tr > th.danger:hover, .table-hover > tbody > tr.danger:hover > td, .table-hover > tbody > tr:hover > .danger, .table-hover > tbody > tr.danger:hover > th { background-color: #ebcccc; } .table-responsive { overflow-x: auto; min-height: 0.01%; } @media screen and (max-width: 767px) { .table-responsive { width: 100%; margin-bottom: 13.5px; overflow-y: hidden; -ms-overflow-style: -ms-autohiding-scrollbar; border: 1px solid #ddd; } .table-responsive > .table { margin-bottom: 0; } .table-responsive > .table > thead > tr > th, .table-responsive > .table > tbody > tr > th, .table-responsive > .table > tfoot > tr > th, .table-responsive > .table > thead > tr > td, .table-responsive > .table > tbody > tr > td, .table-responsive > .table > tfoot > tr > td { white-space: nowrap; } .table-responsive > .table-bordered { border: 0; } .table-responsive > .table-bordered > thead > tr > th:first-child, .table-responsive > .table-bordered > tbody > tr > th:first-child, .table-responsive > .table-bordered > tfoot > tr > th:first-child, .table-responsive > .table-bordered > thead > tr > td:first-child, .table-responsive > .table-bordered > tbody > tr > td:first-child, .table-responsive > .table-bordered > tfoot > tr > td:first-child { border-left: 0; } .table-responsive > .table-bordered > thead > tr > th:last-child, .table-responsive > .table-bordered > tbody > tr > th:last-child, .table-responsive > .table-bordered > tfoot > tr > th:last-child, .table-responsive > .table-bordered > thead > tr > td:last-child, .table-responsive > .table-bordered > tbody > tr > td:last-child, .table-responsive > .table-bordered > tfoot > tr > td:last-child { border-right: 0; } .table-responsive > .table-bordered > tbody > tr:last-child > th, .table-responsive > .table-bordered > tfoot > tr:last-child > th, .table-responsive > .table-bordered > tbody > tr:last-child > td, .table-responsive > .table-bordered > tfoot > tr:last-child > td { border-bottom: 0; } } fieldset { padding: 0; margin: 0; border: 0; min-width: 0; } legend { display: block; width: 100%; padding: 0; margin-bottom: 18px; font-size: 19.5px; line-height: inherit; color: #333333; border: 0; border-bottom: 1px solid #e5e5e5; } label { display: inline-block; max-width: 100%; margin-bottom: 5px; font-weight: bold; } input[type="search"] { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } input[type="radio"], input[type="checkbox"] { margin: 4px 0 0; margin-top: 1px \9; line-height: normal; } input[type="file"] { display: block; } input[type="range"] { display: block; width: 100%; } select[multiple], select[size] { height: auto; } input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus { outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } output { display: block; padding-top: 7px; font-size: 13px; line-height: 1.42857143; color: #555555; } .form-control { display: block; width: 100%; height: 32px; padding: 6px 12px; font-size: 13px; line-height: 1.42857143; color: #555555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 2px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; } .form-control:focus { border-color: #66afe9; outline: 0; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); } .form-control::-moz-placeholder { color: #999; opacity: 1; } .form-control:-ms-input-placeholder { color: #999; } .form-control::-webkit-input-placeholder { color: #999; } .form-control::-ms-expand { border: 0; background-color: transparent; } .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { background-color: #eeeeee; opacity: 1; } .form-control[disabled], fieldset[disabled] .form-control { cursor: not-allowed; } textarea.form-control { height: auto; } input[type="search"] { -webkit-appearance: none; } @media screen and (-webkit-min-device-pixel-ratio: 0) { input[type="date"].form-control, input[type="time"].form-control, input[type="datetime-local"].form-control, input[type="month"].form-control { line-height: 32px; } input[type="date"].input-sm, input[type="time"].input-sm, input[type="datetime-local"].input-sm, input[type="month"].input-sm, .input-group-sm input[type="date"], .input-group-sm input[type="time"], .input-group-sm input[type="datetime-local"], .input-group-sm input[type="month"] { line-height: 30px; } input[type="date"].input-lg, input[type="time"].input-lg, input[type="datetime-local"].input-lg, input[type="month"].input-lg, .input-group-lg input[type="date"], .input-group-lg input[type="time"], .input-group-lg input[type="datetime-local"], .input-group-lg input[type="month"] { line-height: 45px; } } .form-group { margin-bottom: 15px; } .radio, .checkbox { position: relative; display: block; margin-top: 10px; margin-bottom: 10px; } .radio label, .checkbox label { min-height: 18px; padding-left: 20px; margin-bottom: 0; font-weight: normal; cursor: pointer; } .radio input[type="radio"], .radio-inline input[type="radio"], .checkbox input[type="checkbox"], .checkbox-inline input[type="checkbox"] { position: absolute; margin-left: -20px; margin-top: 4px \9; } .radio + .radio, .checkbox + .checkbox { margin-top: -5px; } .radio-inline, .checkbox-inline { position: relative; display: inline-block; padding-left: 20px; margin-bottom: 0; vertical-align: middle; font-weight: normal; cursor: pointer; } .radio-inline + .radio-inline, .checkbox-inline + .checkbox-inline { margin-top: 0; margin-left: 10px; } input[type="radio"][disabled], input[type="checkbox"][disabled], input[type="radio"].disabled, input[type="checkbox"].disabled, fieldset[disabled] input[type="radio"], fieldset[disabled] input[type="checkbox"] { cursor: not-allowed; } .radio-inline.disabled, .checkbox-inline.disabled, fieldset[disabled] .radio-inline, fieldset[disabled] .checkbox-inline { cursor: not-allowed; } .radio.disabled label, .checkbox.disabled label, fieldset[disabled] .radio label, fieldset[disabled] .checkbox label { cursor: not-allowed; } .form-control-static { padding-top: 7px; padding-bottom: 7px; margin-bottom: 0; min-height: 31px; } .form-control-static.input-lg, .form-control-static.input-sm { padding-left: 0; padding-right: 0; } .input-sm { height: 30px; padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 1px; } select.input-sm { height: 30px; line-height: 30px; } textarea.input-sm, select[multiple].input-sm { height: auto; } .form-group-sm .form-control { height: 30px; padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 1px; } .form-group-sm select.form-control { height: 30px; line-height: 30px; } .form-group-sm textarea.form-control, .form-group-sm select[multiple].form-control { height: auto; } .form-group-sm .form-control-static { height: 30px; min-height: 30px; padding: 6px 10px; font-size: 12px; line-height: 1.5; } .input-lg { height: 45px; padding: 10px 16px; font-size: 17px; line-height: 1.3333333; border-radius: 3px; } select.input-lg { height: 45px; line-height: 45px; } textarea.input-lg, select[multiple].input-lg { height: auto; } .form-group-lg .form-control { height: 45px; padding: 10px 16px; font-size: 17px; line-height: 1.3333333; border-radius: 3px; } .form-group-lg select.form-control { height: 45px; line-height: 45px; } .form-group-lg textarea.form-control, .form-group-lg select[multiple].form-control { height: auto; } .form-group-lg .form-control-static { height: 45px; min-height: 35px; padding: 11px 16px; font-size: 17px; line-height: 1.3333333; } .has-feedback { position: relative; } .has-feedback .form-control { padding-right: 40px; } .form-control-feedback { position: absolute; top: 0; right: 0; z-index: 2; display: block; width: 32px; height: 32px; line-height: 32px; text-align: center; pointer-events: none; } .input-lg + .form-control-feedback, .input-group-lg + .form-control-feedback, .form-group-lg .form-control + .form-control-feedback { width: 45px; height: 45px; line-height: 45px; } .input-sm + .form-control-feedback, .input-group-sm + .form-control-feedback, .form-group-sm .form-control + .form-control-feedback { width: 30px; height: 30px; line-height: 30px; } .has-success .help-block, .has-success .control-label, .has-success .radio, .has-success .checkbox, .has-success .radio-inline, .has-success .checkbox-inline, .has-success.radio label, .has-success.checkbox label, .has-success.radio-inline label, .has-success.checkbox-inline label { color: #3c763d; } .has-success .form-control { border-color: #3c763d; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .has-success .form-control:focus { border-color: #2b542c; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; } .has-success .input-group-addon { color: #3c763d; border-color: #3c763d; background-color: #dff0d8; } .has-success .form-control-feedback { color: #3c763d; } .has-warning .help-block, .has-warning .control-label, .has-warning .radio, .has-warning .checkbox, .has-warning .radio-inline, .has-warning .checkbox-inline, .has-warning.radio label, .has-warning.checkbox label, .has-warning.radio-inline label, .has-warning.checkbox-inline label { color: #8a6d3b; } .has-warning .form-control { border-color: #8a6d3b; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .has-warning .form-control:focus { border-color: #66512c; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; } .has-warning .input-group-addon { color: #8a6d3b; border-color: #8a6d3b; background-color: #fcf8e3; } .has-warning .form-control-feedback { color: #8a6d3b; } .has-error .help-block, .has-error .control-label, .has-error .radio, .has-error .checkbox, .has-error .radio-inline, .has-error .checkbox-inline, .has-error.radio label, .has-error.checkbox label, .has-error.radio-inline label, .has-error.checkbox-inline label { color: #a94442; } .has-error .form-control { border-color: #a94442; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .has-error .form-control:focus { border-color: #843534; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; } .has-error .input-group-addon { color: #a94442; border-color: #a94442; background-color: #f2dede; } .has-error .form-control-feedback { color: #a94442; } .has-feedback label ~ .form-control-feedback { top: 23px; } .has-feedback label.sr-only ~ .form-control-feedback { top: 0; } .help-block { display: block; margin-top: 5px; margin-bottom: 10px; color: #404040; } @media (min-width: 768px) { .form-inline .form-group { display: inline-block; margin-bottom: 0; vertical-align: middle; } .form-inline .form-control { display: inline-block; width: auto; vertical-align: middle; } .form-inline .form-control-static { display: inline-block; } .form-inline .input-group { display: inline-table; vertical-align: middle; } .form-inline .input-group .input-group-addon, .form-inline .input-group .input-group-btn, .form-inline .input-group .form-control { width: auto; } .form-inline .input-group > .form-control { width: 100%; } .form-inline .control-label { margin-bottom: 0; vertical-align: middle; } .form-inline .radio, .form-inline .checkbox { display: inline-block; margin-top: 0; margin-bottom: 0; vertical-align: middle; } .form-inline .radio label, .form-inline .checkbox label { padding-left: 0; } .form-inline .radio input[type="radio"], .form-inline .checkbox input[type="checkbox"] { position: relative; margin-left: 0; } .form-inline .has-feedback .form-control-feedback { top: 0; } } .form-horizontal .radio, .form-horizontal .checkbox, .form-horizontal .radio-inline, .form-horizontal .checkbox-inline { margin-top: 0; margin-bottom: 0; padding-top: 7px; } .form-horizontal .radio, .form-horizontal .checkbox { min-height: 25px; } .form-horizontal .form-group { margin-left: 0px; margin-right: 0px; } @media (min-width: 768px) { .form-horizontal .control-label { text-align: right; margin-bottom: 0; padding-top: 7px; } } .form-horizontal .has-feedback .form-control-feedback { right: 0px; } @media (min-width: 768px) { .form-horizontal .form-group-lg .control-label { padding-top: 11px; font-size: 17px; } } @media (min-width: 768px) { .form-horizontal .form-group-sm .control-label { padding-top: 6px; font-size: 12px; } } .btn { display: inline-block; margin-bottom: 0; font-weight: normal; text-align: center; vertical-align: middle; touch-action: manipulation; cursor: pointer; background-image: none; border: 1px solid transparent; white-space: nowrap; padding: 6px 12px; font-size: 13px; line-height: 1.42857143; border-radius: 2px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .btn:focus, .btn:active:focus, .btn.active:focus, .btn.focus, .btn:active.focus, .btn.active.focus { outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } .btn:hover, .btn:focus, .btn.focus { color: #333; text-decoration: none; } .btn:active, .btn.active { outline: 0; background-image: none; -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); } .btn.disabled, .btn[disabled], fieldset[disabled] .btn { cursor: not-allowed; opacity: 0.65; filter: alpha(opacity=65); -webkit-box-shadow: none; box-shadow: none; } a.btn.disabled, fieldset[disabled] a.btn { pointer-events: none; } .btn-default { color: #333; background-color: #fff; border-color: #ccc; } .btn-default:focus, .btn-default.focus { color: #333; background-color: #e6e6e6; border-color: #8c8c8c; } .btn-default:hover { color: #333; background-color: #e6e6e6; border-color: #adadad; } .btn-default:active, .btn-default.active, .open > .dropdown-toggle.btn-default { color: #333; background-color: #e6e6e6; border-color: #adadad; } .btn-default:active:hover, .btn-default.active:hover, .open > .dropdown-toggle.btn-default:hover, .btn-default:active:focus, .btn-default.active:focus, .open > .dropdown-toggle.btn-default:focus, .btn-default:active.focus, .btn-default.active.focus, .open > .dropdown-toggle.btn-default.focus { color: #333; background-color: #d4d4d4; border-color: #8c8c8c; } .btn-default:active, .btn-default.active, .open > .dropdown-toggle.btn-default { background-image: none; } .btn-default.disabled:hover, .btn-default[disabled]:hover, fieldset[disabled] .btn-default:hover, .btn-default.disabled:focus, .btn-default[disabled]:focus, fieldset[disabled] .btn-default:focus, .btn-default.disabled.focus, .btn-default[disabled].focus, fieldset[disabled] .btn-default.focus { background-color: #fff; border-color: #ccc; } .btn-default .badge { color: #fff; background-color: #333; } .btn-primary { color: #fff; background-color: #337ab7; border-color: #2e6da4; } .btn-primary:focus, .btn-primary.focus { color: #fff; background-color: #286090; border-color: #122b40; } .btn-primary:hover { color: #fff; background-color: #286090; border-color: #204d74; } .btn-primary:active, .btn-primary.active, .open > .dropdown-toggle.btn-primary { color: #fff; background-color: #286090; border-color: #204d74; } .btn-primary:active:hover, .btn-primary.active:hover, .open > .dropdown-toggle.btn-primary:hover, .btn-primary:active:focus, .btn-primary.active:focus, .open > .dropdown-toggle.btn-primary:focus, .btn-primary:active.focus, .btn-primary.active.focus, .open > .dropdown-toggle.btn-primary.focus { color: #fff; background-color: #204d74; border-color: #122b40; } .btn-primary:active, .btn-primary.active, .open > .dropdown-toggle.btn-primary { background-image: none; } .btn-primary.disabled:hover, .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary:hover, .btn-primary.disabled:focus, .btn-primary[disabled]:focus, fieldset[disabled] .btn-primary:focus, .btn-primary.disabled.focus, .btn-primary[disabled].focus, fieldset[disabled] .btn-primary.focus { background-color: #337ab7; border-color: #2e6da4; } .btn-primary .badge { color: #337ab7; background-color: #fff; } .btn-success { color: #fff; background-color: #5cb85c; border-color: #4cae4c; } .btn-success:focus, .btn-success.focus { color: #fff; background-color: #449d44; border-color: #255625; } .btn-success:hover { color: #fff; background-color: #449d44; border-color: #398439; } .btn-success:active, .btn-success.active, .open > .dropdown-toggle.btn-success { color: #fff; background-color: #449d44; border-color: #398439; } .btn-success:active:hover, .btn-success.active:hover, .open > .dropdown-toggle.btn-success:hover, .btn-success:active:focus, .btn-success.active:focus, .open > .dropdown-toggle.btn-success:focus, .btn-success:active.focus, .btn-success.active.focus, .open > .dropdown-toggle.btn-success.focus { color: #fff; background-color: #398439; border-color: #255625; } .btn-success:active, .btn-success.active, .open > .dropdown-toggle.btn-success { background-image: none; } .btn-success.disabled:hover, .btn-success[disabled]:hover, fieldset[disabled] .btn-success:hover, .btn-success.disabled:focus, .btn-success[disabled]:focus, fieldset[disabled] .btn-success:focus, .btn-success.disabled.focus, .btn-success[disabled].focus, fieldset[disabled] .btn-success.focus { background-color: #5cb85c; border-color: #4cae4c; } .btn-success .badge { color: #5cb85c; background-color: #fff; } .btn-info { color: #fff; background-color: #5bc0de; border-color: #46b8da; } .btn-info:focus, .btn-info.focus { color: #fff; background-color: #31b0d5; border-color: #1b6d85; } .btn-info:hover { color: #fff; background-color: #31b0d5; border-color: #269abc; } .btn-info:active, .btn-info.active, .open > .dropdown-toggle.btn-info { color: #fff; background-color: #31b0d5; border-color: #269abc; } .btn-info:active:hover, .btn-info.active:hover, .open > .dropdown-toggle.btn-info:hover, .btn-info:active:focus, .btn-info.active:focus, .open > .dropdown-toggle.btn-info:focus, .btn-info:active.focus, .btn-info.active.focus, .open > .dropdown-toggle.btn-info.focus { color: #fff; background-color: #269abc; border-color: #1b6d85; } .btn-info:active, .btn-info.active, .open > .dropdown-toggle.btn-info { background-image: none; } .btn-info.disabled:hover, .btn-info[disabled]:hover, fieldset[disabled] .btn-info:hover, .btn-info.disabled:focus, .btn-info[disabled]:focus, fieldset[disabled] .btn-info:focus, .btn-info.disabled.focus, .btn-info[disabled].focus, fieldset[disabled] .btn-info.focus { background-color: #5bc0de; border-color: #46b8da; } .btn-info .badge { color: #5bc0de; background-color: #fff; } .btn-warning { color: #fff; background-color: #f0ad4e; border-color: #eea236; } .btn-warning:focus, .btn-warning.focus { color: #fff; background-color: #ec971f; border-color: #985f0d; } .btn-warning:hover { color: #fff; background-color: #ec971f; border-color: #d58512; } .btn-warning:active, .btn-warning.active, .open > .dropdown-toggle.btn-warning { color: #fff; background-color: #ec971f; border-color: #d58512; } .btn-warning:active:hover, .btn-warning.active:hover, .open > .dropdown-toggle.btn-warning:hover, .btn-warning:active:focus, .btn-warning.active:focus, .open > .dropdown-toggle.btn-warning:focus, .btn-warning:active.focus, .btn-warning.active.focus, .open > .dropdown-toggle.btn-warning.focus { color: #fff; background-color: #d58512; border-color: #985f0d; } .btn-warning:active, .btn-warning.active, .open > .dropdown-toggle.btn-warning { background-image: none; } .btn-warning.disabled:hover, .btn-warning[disabled]:hover, fieldset[disabled] .btn-warning:hover, .btn-warning.disabled:focus, .btn-warning[disabled]:focus, fieldset[disabled] .btn-warning:focus, .btn-warning.disabled.focus, .btn-warning[disabled].focus, fieldset[disabled] .btn-warning.focus { background-color: #f0ad4e; border-color: #eea236; } .btn-warning .badge { color: #f0ad4e; background-color: #fff; } .btn-danger { color: #fff; background-color: #d9534f; border-color: #d43f3a; } .btn-danger:focus, .btn-danger.focus { color: #fff; background-color: #c9302c; border-color: #761c19; } .btn-danger:hover { color: #fff; background-color: #c9302c; border-color: #ac2925; } .btn-danger:active, .btn-danger.active, .open > .dropdown-toggle.btn-danger { color: #fff; background-color: #c9302c; border-color: #ac2925; } .btn-danger:active:hover, .btn-danger.active:hover, .open > .dropdown-toggle.btn-danger:hover, .btn-danger:active:focus, .btn-danger.active:focus, .open > .dropdown-toggle.btn-danger:focus, .btn-danger:active.focus, .btn-danger.active.focus, .open > .dropdown-toggle.btn-danger.focus { color: #fff; background-color: #ac2925; border-color: #761c19; } .btn-danger:active, .btn-danger.active, .open > .dropdown-toggle.btn-danger { background-image: none; } .btn-danger.disabled:hover, .btn-danger[disabled]:hover, fieldset[disabled] .btn-danger:hover, .btn-danger.disabled:focus, .btn-danger[disabled]:focus, fieldset[disabled] .btn-danger:focus, .btn-danger.disabled.focus, .btn-danger[disabled].focus, fieldset[disabled] .btn-danger.focus { background-color: #d9534f; border-color: #d43f3a; } .btn-danger .badge { color: #d9534f; background-color: #fff; } .btn-link { color: #337ab7; font-weight: normal; border-radius: 0; } .btn-link, .btn-link:active, .btn-link.active, .btn-link[disabled], fieldset[disabled] .btn-link { background-color: transparent; -webkit-box-shadow: none; box-shadow: none; } .btn-link, .btn-link:hover, .btn-link:focus, .btn-link:active { border-color: transparent; } .btn-link:hover, .btn-link:focus { color: #23527c; text-decoration: underline; background-color: transparent; } .btn-link[disabled]:hover, fieldset[disabled] .btn-link:hover, .btn-link[disabled]:focus, fieldset[disabled] .btn-link:focus { color: #777777; text-decoration: none; } .btn-lg, .btn-group-lg > .btn { padding: 10px 16px; font-size: 17px; line-height: 1.3333333; border-radius: 3px; } .btn-sm, .btn-group-sm > .btn { padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 1px; } .btn-xs, .btn-group-xs > .btn { padding: 1px 5px; font-size: 12px; line-height: 1.5; border-radius: 1px; } .btn-block { display: block; width: 100%; } .btn-block + .btn-block { margin-top: 5px; } input[type="submit"].btn-block, input[type="reset"].btn-block, input[type="button"].btn-block { width: 100%; } .fade { opacity: 0; -webkit-transition: opacity 0.15s linear; -o-transition: opacity 0.15s linear; transition: opacity 0.15s linear; } .fade.in { opacity: 1; } .collapse { display: none; } .collapse.in { display: block; } tr.collapse.in { display: table-row; } tbody.collapse.in { display: table-row-group; } .collapsing { position: relative; height: 0; overflow: hidden; -webkit-transition-property: height, visibility; transition-property: height, visibility; -webkit-transition-duration: 0.35s; transition-duration: 0.35s; -webkit-transition-timing-function: ease; transition-timing-function: ease; } .caret { display: inline-block; width: 0; height: 0; margin-left: 2px; vertical-align: middle; border-top: 4px dashed; border-top: 4px solid \9; border-right: 4px solid transparent; border-left: 4px solid transparent; } .dropup, .dropdown { position: relative; } .dropdown-toggle:focus { outline: 0; } .dropdown-menu { position: absolute; top: 100%; left: 0; z-index: 1000; display: none; float: left; min-width: 160px; padding: 5px 0; margin: 2px 0 0; list-style: none; font-size: 13px; text-align: left; background-color: #fff; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 2px; -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); background-clip: padding-box; } .dropdown-menu.pull-right { right: 0; left: auto; } .dropdown-menu .divider { height: 1px; margin: 8px 0; overflow: hidden; background-color: #e5e5e5; } .dropdown-menu > li > a { display: block; padding: 3px 20px; clear: both; font-weight: normal; line-height: 1.42857143; color: #333333; white-space: nowrap; } .dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus { text-decoration: none; color: #262626; background-color: #f5f5f5; } .dropdown-menu > .active > a, .dropdown-menu > .active > a:hover, .dropdown-menu > .active > a:focus { color: #fff; text-decoration: none; outline: 0; background-color: #337ab7; } .dropdown-menu > .disabled > a, .dropdown-menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus { color: #777777; } .dropdown-menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus { text-decoration: none; background-color: transparent; background-image: none; filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); cursor: not-allowed; } .open > .dropdown-menu { display: block; } .open > a { outline: 0; } .dropdown-menu-right { left: auto; right: 0; } .dropdown-menu-left { left: 0; right: auto; } .dropdown-header { display: block; padding: 3px 20px; font-size: 12px; line-height: 1.42857143; color: #777777; white-space: nowrap; } .dropdown-backdrop { position: fixed; left: 0; right: 0; bottom: 0; top: 0; z-index: 990; } .pull-right > .dropdown-menu { right: 0; left: auto; } .dropup .caret, .navbar-fixed-bottom .dropdown .caret { border-top: 0; border-bottom: 4px dashed; border-bottom: 4px solid \9; content: ""; } .dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu { top: auto; bottom: 100%; margin-bottom: 2px; } @media (min-width: 541px) { .navbar-right .dropdown-menu { left: auto; right: 0; } .navbar-right .dropdown-menu-left { left: 0; right: auto; } } .btn-group, .btn-group-vertical { position: relative; display: inline-block; vertical-align: middle; } .btn-group > .btn, .btn-group-vertical > .btn { position: relative; float: left; } .btn-group > .btn:hover, .btn-group-vertical > .btn:hover, .btn-group > .btn:focus, .btn-group-vertical > .btn:focus, .btn-group > .btn:active, .btn-group-vertical > .btn:active, .btn-group > .btn.active, .btn-group-vertical > .btn.active { z-index: 2; } .btn-group .btn + .btn, .btn-group .btn + .btn-group, .btn-group .btn-group + .btn, .btn-group .btn-group + .btn-group { margin-left: -1px; } .btn-toolbar { margin-left: -5px; } .btn-toolbar .btn, .btn-toolbar .btn-group, .btn-toolbar .input-group { float: left; } .btn-toolbar > .btn, .btn-toolbar > .btn-group, .btn-toolbar > .input-group { margin-left: 5px; } .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { border-radius: 0; } .btn-group > .btn:first-child { margin-left: 0; } .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { border-bottom-right-radius: 0; border-top-right-radius: 0; } .btn-group > .btn:last-child:not(:first-child), .btn-group > .dropdown-toggle:not(:first-child) { border-bottom-left-radius: 0; border-top-left-radius: 0; } .btn-group > .btn-group { float: left; } .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { border-radius: 0; } .btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child, .btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle { border-bottom-right-radius: 0; border-top-right-radius: 0; } .btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { border-bottom-left-radius: 0; border-top-left-radius: 0; } .btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { outline: 0; } .btn-group > .btn + .dropdown-toggle { padding-left: 8px; padding-right: 8px; } .btn-group > .btn-lg + .dropdown-toggle { padding-left: 12px; padding-right: 12px; } .btn-group.open .dropdown-toggle { -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); } .btn-group.open .dropdown-toggle.btn-link { -webkit-box-shadow: none; box-shadow: none; } .btn .caret { margin-left: 0; } .btn-lg .caret { border-width: 5px 5px 0; border-bottom-width: 0; } .dropup .btn-lg .caret { border-width: 0 5px 5px; } .btn-group-vertical > .btn, .btn-group-vertical > .btn-group, .btn-group-vertical > .btn-group > .btn { display: block; float: none; width: 100%; max-width: 100%; } .btn-group-vertical > .btn-group > .btn { float: none; } .btn-group-vertical > .btn + .btn, .btn-group-vertical > .btn + .btn-group, .btn-group-vertical > .btn-group + .btn, .btn-group-vertical > .btn-group + .btn-group { margin-top: -1px; margin-left: 0; } .btn-group-vertical > .btn:not(:first-child):not(:last-child) { border-radius: 0; } .btn-group-vertical > .btn:first-child:not(:last-child) { border-top-right-radius: 2px; border-top-left-radius: 2px; border-bottom-right-radius: 0; border-bottom-left-radius: 0; } .btn-group-vertical > .btn:last-child:not(:first-child) { border-top-right-radius: 0; border-top-left-radius: 0; border-bottom-right-radius: 2px; border-bottom-left-radius: 2px; } .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { border-radius: 0; } .btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, .btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { border-bottom-right-radius: 0; border-bottom-left-radius: 0; } .btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { border-top-right-radius: 0; border-top-left-radius: 0; } .btn-group-justified { display: table; width: 100%; table-layout: fixed; border-collapse: separate; } .btn-group-justified > .btn, .btn-group-justified > .btn-group { float: none; display: table-cell; width: 1%; } .btn-group-justified > .btn-group .btn { width: 100%; } .btn-group-justified > .btn-group .dropdown-menu { left: auto; } [data-toggle="buttons"] > .btn input[type="radio"], [data-toggle="buttons"] > .btn-group > .btn input[type="radio"], [data-toggle="buttons"] > .btn input[type="checkbox"], [data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { position: absolute; clip: rect(0, 0, 0, 0); pointer-events: none; } .input-group { position: relative; display: table; border-collapse: separate; } .input-group[class*="col-"] { float: none; padding-left: 0; padding-right: 0; } .input-group .form-control { position: relative; z-index: 2; float: left; width: 100%; margin-bottom: 0; } .input-group .form-control:focus { z-index: 3; } .input-group-lg > .form-control, .input-group-lg > .input-group-addon, .input-group-lg > .input-group-btn > .btn { height: 45px; padding: 10px 16px; font-size: 17px; line-height: 1.3333333; border-radius: 3px; } select.input-group-lg > .form-control, select.input-group-lg > .input-group-addon, select.input-group-lg > .input-group-btn > .btn { height: 45px; line-height: 45px; } textarea.input-group-lg > .form-control, textarea.input-group-lg > .input-group-addon, textarea.input-group-lg > .input-group-btn > .btn, select[multiple].input-group-lg > .form-control, select[multiple].input-group-lg > .input-group-addon, select[multiple].input-group-lg > .input-group-btn > .btn { height: auto; } .input-group-sm > .form-control, .input-group-sm > .input-group-addon, .input-group-sm > .input-group-btn > .btn { height: 30px; padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 1px; } select.input-group-sm > .form-control, select.input-group-sm > .input-group-addon, select.input-group-sm > .input-group-btn > .btn { height: 30px; line-height: 30px; } textarea.input-group-sm > .form-control, textarea.input-group-sm > .input-group-addon, textarea.input-group-sm > .input-group-btn > .btn, select[multiple].input-group-sm > .form-control, select[multiple].input-group-sm > .input-group-addon, select[multiple].input-group-sm > .input-group-btn > .btn { height: auto; } .input-group-addon, .input-group-btn, .input-group .form-control { display: table-cell; } .input-group-addon:not(:first-child):not(:last-child), .input-group-btn:not(:first-child):not(:last-child), .input-group .form-control:not(:first-child):not(:last-child) { border-radius: 0; } .input-group-addon, .input-group-btn { width: 1%; white-space: nowrap; vertical-align: middle; } .input-group-addon { padding: 6px 12px; font-size: 13px; font-weight: normal; line-height: 1; color: #555555; text-align: center; background-color: #eeeeee; border: 1px solid #ccc; border-radius: 2px; } .input-group-addon.input-sm { padding: 5px 10px; font-size: 12px; border-radius: 1px; } .input-group-addon.input-lg { padding: 10px 16px; font-size: 17px; border-radius: 3px; } .input-group-addon input[type="radio"], .input-group-addon input[type="checkbox"] { margin-top: 0; } .input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child > .btn, .input-group-btn:first-child > .btn-group > .btn, .input-group-btn:first-child > .dropdown-toggle, .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), .input-group-btn:last-child > .btn-group:not(:last-child) > .btn { border-bottom-right-radius: 0; border-top-right-radius: 0; } .input-group-addon:first-child { border-right: 0; } .input-group .form-control:last-child, .input-group-addon:last-child, .input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group > .btn, .input-group-btn:last-child > .dropdown-toggle, .input-group-btn:first-child > .btn:not(:first-child), .input-group-btn:first-child > .btn-group:not(:first-child) > .btn { border-bottom-left-radius: 0; border-top-left-radius: 0; } .input-group-addon:last-child { border-left: 0; } .input-group-btn { position: relative; font-size: 0; white-space: nowrap; } .input-group-btn > .btn { position: relative; } .input-group-btn > .btn + .btn { margin-left: -1px; } .input-group-btn > .btn:hover, .input-group-btn > .btn:focus, .input-group-btn > .btn:active { z-index: 2; } .input-group-btn:first-child > .btn, .input-group-btn:first-child > .btn-group { margin-right: -1px; } .input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group { z-index: 2; margin-left: -1px; } .nav { margin-bottom: 0; padding-left: 0; list-style: none; } .nav > li { position: relative; display: block; } .nav > li > a { position: relative; display: block; padding: 10px 15px; } .nav > li > a:hover, .nav > li > a:focus { text-decoration: none; background-color: #eeeeee; } .nav > li.disabled > a { color: #777777; } .nav > li.disabled > a:hover, .nav > li.disabled > a:focus { color: #777777; text-decoration: none; background-color: transparent; cursor: not-allowed; } .nav .open > a, .nav .open > a:hover, .nav .open > a:focus { background-color: #eeeeee; border-color: #337ab7; } .nav .nav-divider { height: 1px; margin: 8px 0; overflow: hidden; background-color: #e5e5e5; } .nav > li > a > img { max-width: none; } .nav-tabs { border-bottom: 1px solid #ddd; } .nav-tabs > li { float: left; margin-bottom: -1px; } .nav-tabs > li > a { margin-right: 2px; line-height: 1.42857143; border: 1px solid transparent; border-radius: 2px 2px 0 0; } .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #ddd; } .nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus { color: #555555; background-color: #fff; border: 1px solid #ddd; border-bottom-color: transparent; cursor: default; } .nav-tabs.nav-justified { width: 100%; border-bottom: 0; } .nav-tabs.nav-justified > li { float: none; } .nav-tabs.nav-justified > li > a { text-align: center; margin-bottom: 5px; } .nav-tabs.nav-justified > .dropdown .dropdown-menu { top: auto; left: auto; } @media (min-width: 768px) { .nav-tabs.nav-justified > li { display: table-cell; width: 1%; } .nav-tabs.nav-justified > li > a { margin-bottom: 0; } } .nav-tabs.nav-justified > li > a { margin-right: 0; border-radius: 2px; } .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a:focus { border: 1px solid #ddd; } @media (min-width: 768px) { .nav-tabs.nav-justified > li > a { border-bottom: 1px solid #ddd; border-radius: 2px 2px 0 0; } .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a:focus { border-bottom-color: #fff; } } .nav-pills > li { float: left; } .nav-pills > li > a { border-radius: 2px; } .nav-pills > li + li { margin-left: 2px; } .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus { color: #fff; background-color: #337ab7; } .nav-stacked > li { float: none; } .nav-stacked > li + li { margin-top: 2px; margin-left: 0; } .nav-justified { width: 100%; } .nav-justified > li { float: none; } .nav-justified > li > a { text-align: center; margin-bottom: 5px; } .nav-justified > .dropdown .dropdown-menu { top: auto; left: auto; } @media (min-width: 768px) { .nav-justified > li { display: table-cell; width: 1%; } .nav-justified > li > a { margin-bottom: 0; } } .nav-tabs-justified { border-bottom: 0; } .nav-tabs-justified > li > a { margin-right: 0; border-radius: 2px; } .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:hover, .nav-tabs-justified > .active > a:focus { border: 1px solid #ddd; } @media (min-width: 768px) { .nav-tabs-justified > li > a { border-bottom: 1px solid #ddd; border-radius: 2px 2px 0 0; } .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:hover, .nav-tabs-justified > .active > a:focus { border-bottom-color: #fff; } } .tab-content > .tab-pane { display: none; } .tab-content > .active { display: block; } .nav-tabs .dropdown-menu { margin-top: -1px; border-top-right-radius: 0; border-top-left-radius: 0; } .navbar { position: relative; min-height: 30px; margin-bottom: 18px; border: 1px solid transparent; } @media (min-width: 541px) { .navbar { border-radius: 2px; } } @media (min-width: 541px) { .navbar-header { float: left; } } .navbar-collapse { overflow-x: visible; padding-right: 0px; padding-left: 0px; border-top: 1px solid transparent; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); -webkit-overflow-scrolling: touch; } .navbar-collapse.in { overflow-y: auto; } @media (min-width: 541px) { .navbar-collapse { width: auto; border-top: 0; box-shadow: none; } .navbar-collapse.collapse { display: block !important; height: auto !important; padding-bottom: 0; overflow: visible !important; } .navbar-collapse.in { overflow-y: visible; } .navbar-fixed-top .navbar-collapse, .navbar-static-top .navbar-collapse, .navbar-fixed-bottom .navbar-collapse { padding-left: 0; padding-right: 0; } } .navbar-fixed-top .navbar-collapse, .navbar-fixed-bottom .navbar-collapse { max-height: 340px; } @media (max-device-width: 540px) and (orientation: landscape) { .navbar-fixed-top .navbar-collapse, .navbar-fixed-bottom .navbar-collapse { max-height: 200px; } } .container > .navbar-header, .container-fluid > .navbar-header, .container > .navbar-collapse, .container-fluid > .navbar-collapse { margin-right: 0px; margin-left: 0px; } @media (min-width: 541px) { .container > .navbar-header, .container-fluid > .navbar-header, .container > .navbar-collapse, .container-fluid > .navbar-collapse { margin-right: 0; margin-left: 0; } } .navbar-static-top { z-index: 1000; border-width: 0 0 1px; } @media (min-width: 541px) { .navbar-static-top { border-radius: 0; } } .navbar-fixed-top, .navbar-fixed-bottom { position: fixed; right: 0; left: 0; z-index: 1030; } @media (min-width: 541px) { .navbar-fixed-top, .navbar-fixed-bottom { border-radius: 0; } } .navbar-fixed-top { top: 0; border-width: 0 0 1px; } .navbar-fixed-bottom { bottom: 0; margin-bottom: 0; border-width: 1px 0 0; } .navbar-brand { float: left; padding: 6px 0px; font-size: 17px; line-height: 18px; height: 30px; } .navbar-brand:hover, .navbar-brand:focus { text-decoration: none; } .navbar-brand > img { display: block; } @media (min-width: 541px) { .navbar > .container .navbar-brand, .navbar > .container-fluid .navbar-brand { margin-left: 0px; } } .navbar-toggle { position: relative; float: right; margin-right: 0px; padding: 9px 10px; margin-top: -2px; margin-bottom: -2px; background-color: transparent; background-image: none; border: 1px solid transparent; border-radius: 2px; } .navbar-toggle:focus { outline: 0; } .navbar-toggle .icon-bar { display: block; width: 22px; height: 2px; border-radius: 1px; } .navbar-toggle .icon-bar + .icon-bar { margin-top: 4px; } @media (min-width: 541px) { .navbar-toggle { display: none; } } .navbar-nav { margin: 3px 0px; } .navbar-nav > li > a { padding-top: 10px; padding-bottom: 10px; line-height: 18px; } @media (max-width: 540px) { .navbar-nav .open .dropdown-menu { position: static; float: none; width: auto; margin-top: 0; background-color: transparent; border: 0; box-shadow: none; } .navbar-nav .open .dropdown-menu > li > a, .navbar-nav .open .dropdown-menu .dropdown-header { padding: 5px 15px 5px 25px; } .navbar-nav .open .dropdown-menu > li > a { line-height: 18px; } .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-nav .open .dropdown-menu > li > a:focus { background-image: none; } } @media (min-width: 541px) { .navbar-nav { float: left; margin: 0; } .navbar-nav > li { float: left; } .navbar-nav > li > a { padding-top: 6px; padding-bottom: 6px; } } .navbar-form { margin-left: 0px; margin-right: 0px; padding: 10px 0px; border-top: 1px solid transparent; border-bottom: 1px solid transparent; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); margin-top: -1px; margin-bottom: -1px; } @media (min-width: 768px) { .navbar-form .form-group { display: inline-block; margin-bottom: 0; vertical-align: middle; } .navbar-form .form-control { display: inline-block; width: auto; vertical-align: middle; } .navbar-form .form-control-static { display: inline-block; } .navbar-form .input-group { display: inline-table; vertical-align: middle; } .navbar-form .input-group .input-group-addon, .navbar-form .input-group .input-group-btn, .navbar-form .input-group .form-control { width: auto; } .navbar-form .input-group > .form-control { width: 100%; } .navbar-form .control-label { margin-bottom: 0; vertical-align: middle; } .navbar-form .radio, .navbar-form .checkbox { display: inline-block; margin-top: 0; margin-bottom: 0; vertical-align: middle; } .navbar-form .radio label, .navbar-form .checkbox label { padding-left: 0; } .navbar-form .radio input[type="radio"], .navbar-form .checkbox input[type="checkbox"] { position: relative; margin-left: 0; } .navbar-form .has-feedback .form-control-feedback { top: 0; } } @media (max-width: 540px) { .navbar-form .form-group { margin-bottom: 5px; } .navbar-form .form-group:last-child { margin-bottom: 0; } } @media (min-width: 541px) { .navbar-form { width: auto; border: 0; margin-left: 0; margin-right: 0; padding-top: 0; padding-bottom: 0; -webkit-box-shadow: none; box-shadow: none; } } .navbar-nav > li > .dropdown-menu { margin-top: 0; border-top-right-radius: 0; border-top-left-radius: 0; } .navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { margin-bottom: 0; border-top-right-radius: 2px; border-top-left-radius: 2px; border-bottom-right-radius: 0; border-bottom-left-radius: 0; } .navbar-btn { margin-top: -1px; margin-bottom: -1px; } .navbar-btn.btn-sm { margin-top: 0px; margin-bottom: 0px; } .navbar-btn.btn-xs { margin-top: 4px; margin-bottom: 4px; } .navbar-text { margin-top: 6px; margin-bottom: 6px; } @media (min-width: 541px) { .navbar-text { float: left; margin-left: 0px; margin-right: 0px; } } @media (min-width: 541px) { .navbar-left { float: left !important; float: left; } .navbar-right { float: right !important; float: right; margin-right: 0px; } .navbar-right ~ .navbar-right { margin-right: 0; } } .navbar-default { background-color: #f8f8f8; border-color: #e7e7e7; } .navbar-default .navbar-brand { color: #777; } .navbar-default .navbar-brand:hover, .navbar-default .navbar-brand:focus { color: #5e5e5e; background-color: transparent; } .navbar-default .navbar-text { color: #777; } .navbar-default .navbar-nav > li > a { color: #777; } .navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus { color: #333; background-color: transparent; } .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { color: #555; background-color: #e7e7e7; } .navbar-default .navbar-nav > .disabled > a, .navbar-default .navbar-nav > .disabled > a:hover, .navbar-default .navbar-nav > .disabled > a:focus { color: #ccc; background-color: transparent; } .navbar-default .navbar-toggle { border-color: #ddd; } .navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus { background-color: #ddd; } .navbar-default .navbar-toggle .icon-bar { background-color: #888; } .navbar-default .navbar-collapse, .navbar-default .navbar-form { border-color: #e7e7e7; } .navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:hover, .navbar-default .navbar-nav > .open > a:focus { background-color: #e7e7e7; color: #555; } @media (max-width: 540px) { .navbar-default .navbar-nav .open .dropdown-menu > li > a { color: #777; } .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { color: #333; background-color: transparent; } .navbar-default .navbar-nav .open .dropdown-menu > .active > a, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { color: #555; background-color: #e7e7e7; } .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { color: #ccc; background-color: transparent; } } .navbar-default .navbar-link { color: #777; } .navbar-default .navbar-link:hover { color: #333; } .navbar-default .btn-link { color: #777; } .navbar-default .btn-link:hover, .navbar-default .btn-link:focus { color: #333; } .navbar-default .btn-link[disabled]:hover, fieldset[disabled] .navbar-default .btn-link:hover, .navbar-default .btn-link[disabled]:focus, fieldset[disabled] .navbar-default .btn-link:focus { color: #ccc; } .navbar-inverse { background-color: #222; border-color: #080808; } .navbar-inverse .navbar-brand { color: #9d9d9d; } .navbar-inverse .navbar-brand:hover, .navbar-inverse .navbar-brand:focus { color: #fff; background-color: transparent; } .navbar-inverse .navbar-text { color: #9d9d9d; } .navbar-inverse .navbar-nav > li > a { color: #9d9d9d; } .navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus { color: #fff; background-color: transparent; } .navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus { color: #fff; background-color: #080808; } .navbar-inverse .navbar-nav > .disabled > a, .navbar-inverse .navbar-nav > .disabled > a:hover, .navbar-inverse .navbar-nav > .disabled > a:focus { color: #444; background-color: transparent; } .navbar-inverse .navbar-toggle { border-color: #333; } .navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus { background-color: #333; } .navbar-inverse .navbar-toggle .icon-bar { background-color: #fff; } .navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form { border-color: #101010; } .navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus { background-color: #080808; color: #fff; } @media (max-width: 540px) { .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { border-color: #080808; } .navbar-inverse .navbar-nav .open .dropdown-menu .divider { background-color: #080808; } .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { color: #9d9d9d; } .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { color: #fff; background-color: transparent; } .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { color: #fff; background-color: #080808; } .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { color: #444; background-color: transparent; } } .navbar-inverse .navbar-link { color: #9d9d9d; } .navbar-inverse .navbar-link:hover { color: #fff; } .navbar-inverse .btn-link { color: #9d9d9d; } .navbar-inverse .btn-link:hover, .navbar-inverse .btn-link:focus { color: #fff; } .navbar-inverse .btn-link[disabled]:hover, fieldset[disabled] .navbar-inverse .btn-link:hover, .navbar-inverse .btn-link[disabled]:focus, fieldset[disabled] .navbar-inverse .btn-link:focus { color: #444; } .breadcrumb { padding: 8px 15px; margin-bottom: 18px; list-style: none; background-color: #f5f5f5; border-radius: 2px; } .breadcrumb > li { display: inline-block; } .breadcrumb > li + li:before { content: "/\00a0"; padding: 0 5px; color: #5e5e5e; } .breadcrumb > .active { color: #777777; } .pagination { display: inline-block; padding-left: 0; margin: 18px 0; border-radius: 2px; } .pagination > li { display: inline; } .pagination > li > a, .pagination > li > span { position: relative; float: left; padding: 6px 12px; line-height: 1.42857143; text-decoration: none; color: #337ab7; background-color: #fff; border: 1px solid #ddd; margin-left: -1px; } .pagination > li:first-child > a, .pagination > li:first-child > span { margin-left: 0; border-bottom-left-radius: 2px; border-top-left-radius: 2px; } .pagination > li:last-child > a, .pagination > li:last-child > span { border-bottom-right-radius: 2px; border-top-right-radius: 2px; } .pagination > li > a:hover, .pagination > li > span:hover, .pagination > li > a:focus, .pagination > li > span:focus { z-index: 2; color: #23527c; background-color: #eeeeee; border-color: #ddd; } .pagination > .active > a, .pagination > .active > span, .pagination > .active > a:hover, .pagination > .active > span:hover, .pagination > .active > a:focus, .pagination > .active > span:focus { z-index: 3; color: #fff; background-color: #337ab7; border-color: #337ab7; cursor: default; } .pagination > .disabled > span, .pagination > .disabled > span:hover, .pagination > .disabled > span:focus, .pagination > .disabled > a, .pagination > .disabled > a:hover, .pagination > .disabled > a:focus { color: #777777; background-color: #fff; border-color: #ddd; cursor: not-allowed; } .pagination-lg > li > a, .pagination-lg > li > span { padding: 10px 16px; font-size: 17px; line-height: 1.3333333; } .pagination-lg > li:first-child > a, .pagination-lg > li:first-child > span { border-bottom-left-radius: 3px; border-top-left-radius: 3px; } .pagination-lg > li:last-child > a, .pagination-lg > li:last-child > span { border-bottom-right-radius: 3px; border-top-right-radius: 3px; } .pagination-sm > li > a, .pagination-sm > li > span { padding: 5px 10px; font-size: 12px; line-height: 1.5; } .pagination-sm > li:first-child > a, .pagination-sm > li:first-child > span { border-bottom-left-radius: 1px; border-top-left-radius: 1px; } .pagination-sm > li:last-child > a, .pagination-sm > li:last-child > span { border-bottom-right-radius: 1px; border-top-right-radius: 1px; } .pager { padding-left: 0; margin: 18px 0; list-style: none; text-align: center; } .pager li { display: inline; } .pager li > a, .pager li > span { display: inline-block; padding: 5px 14px; background-color: #fff; border: 1px solid #ddd; border-radius: 15px; } .pager li > a:hover, .pager li > a:focus { text-decoration: none; background-color: #eeeeee; } .pager .next > a, .pager .next > span { float: right; } .pager .previous > a, .pager .previous > span { float: left; } .pager .disabled > a, .pager .disabled > a:hover, .pager .disabled > a:focus, .pager .disabled > span { color: #777777; background-color: #fff; cursor: not-allowed; } .label { display: inline; padding: 0.2em 0.6em 0.3em; font-size: 75%; font-weight: bold; line-height: 1; color: #fff; text-align: center; white-space: nowrap; vertical-align: baseline; border-radius: 0.25em; } a.label:hover, a.label:focus { color: #fff; text-decoration: none; cursor: pointer; } .label:empty { display: none; } .btn .label { position: relative; top: -1px; } .label-default { background-color: #777777; } .label-default[href]:hover, .label-default[href]:focus { background-color: #5e5e5e; } .label-primary { background-color: #337ab7; } .label-primary[href]:hover, .label-primary[href]:focus { background-color: #286090; } .label-success { background-color: #5cb85c; } .label-success[href]:hover, .label-success[href]:focus { background-color: #449d44; } .label-info { background-color: #5bc0de; } .label-info[href]:hover, .label-info[href]:focus { background-color: #31b0d5; } .label-warning { background-color: #f0ad4e; } .label-warning[href]:hover, .label-warning[href]:focus { background-color: #ec971f; } .label-danger { background-color: #d9534f; } .label-danger[href]:hover, .label-danger[href]:focus { background-color: #c9302c; } .badge { display: inline-block; min-width: 10px; padding: 3px 7px; font-size: 12px; font-weight: bold; color: #fff; line-height: 1; vertical-align: middle; white-space: nowrap; text-align: center; background-color: #777777; border-radius: 10px; } .badge:empty { display: none; } .btn .badge { position: relative; top: -1px; } .btn-xs .badge, .btn-group-xs > .btn .badge { top: 0; padding: 1px 5px; } a.badge:hover, a.badge:focus { color: #fff; text-decoration: none; cursor: pointer; } .list-group-item.active > .badge, .nav-pills > .active > a > .badge { color: #337ab7; background-color: #fff; } .list-group-item > .badge { float: right; } .list-group-item > .badge + .badge { margin-right: 5px; } .nav-pills > li > a > .badge { margin-left: 3px; } .jumbotron { padding-top: 30px; padding-bottom: 30px; margin-bottom: 30px; color: inherit; background-color: #eeeeee; } .jumbotron h1, .jumbotron .h1 { color: inherit; } .jumbotron p { margin-bottom: 15px; font-size: 20px; font-weight: 200; } .jumbotron > hr { border-top-color: #d5d5d5; } .container .jumbotron, .container-fluid .jumbotron { border-radius: 3px; padding-left: 0px; padding-right: 0px; } .jumbotron .container { max-width: 100%; } @media screen and (min-width: 768px) { .jumbotron { padding-top: 48px; padding-bottom: 48px; } .container .jumbotron, .container-fluid .jumbotron { padding-left: 60px; padding-right: 60px; } .jumbotron h1, .jumbotron .h1 { font-size: 59px; } } .thumbnail { display: block; padding: 4px; margin-bottom: 18px; line-height: 1.42857143; background-color: #fff; border: 1px solid #ddd; border-radius: 2px; -webkit-transition: border 0.2s ease-in-out; -o-transition: border 0.2s ease-in-out; transition: border 0.2s ease-in-out; } .thumbnail > img, .thumbnail a > img { margin-left: auto; margin-right: auto; } a.thumbnail:hover, a.thumbnail:focus, a.thumbnail.active { border-color: #337ab7; } .thumbnail .caption { padding: 9px; color: #000; } .alert { padding: 15px; margin-bottom: 18px; border: 1px solid transparent; border-radius: 2px; } .alert h4 { margin-top: 0; color: inherit; } .alert .alert-link { font-weight: bold; } .alert > p, .alert > ul { margin-bottom: 0; } .alert > p + p { margin-top: 5px; } .alert-dismissable, .alert-dismissible { padding-right: 35px; } .alert-dismissable .close, .alert-dismissible .close { position: relative; top: -2px; right: -21px; color: inherit; } .alert-success { background-color: #dff0d8; border-color: #d6e9c6; color: #3c763d; } .alert-success hr { border-top-color: #c9e2b3; } .alert-success .alert-link { color: #2b542c; } .alert-info { background-color: #d9edf7; border-color: #bce8f1; color: #31708f; } .alert-info hr { border-top-color: #a6e1ec; } .alert-info .alert-link { color: #245269; } .alert-warning { background-color: #fcf8e3; border-color: #faebcc; color: #8a6d3b; } .alert-warning hr { border-top-color: #f7e1b5; } .alert-warning .alert-link { color: #66512c; } .alert-danger { background-color: #f2dede; border-color: #ebccd1; color: #a94442; } .alert-danger hr { border-top-color: #e4b9c0; } .alert-danger .alert-link { color: #843534; } @-webkit-keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } @keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } .progress { overflow: hidden; height: 18px; margin-bottom: 18px; background-color: #f5f5f5; border-radius: 2px; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); } .progress-bar { float: left; width: 0%; height: 100%; font-size: 12px; line-height: 18px; color: #fff; text-align: center; background-color: #337ab7; -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -webkit-transition: width 0.6s ease; -o-transition: width 0.6s ease; transition: width 0.6s ease; } .progress-striped .progress-bar, .progress-bar-striped { background-image: -webkit-linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-image: -o-linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-image: linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-size: 40px 40px; } .progress.active .progress-bar, .progress-bar.active { -webkit-animation: progress-bar-stripes 2s linear infinite; -o-animation: progress-bar-stripes 2s linear infinite; animation: progress-bar-stripes 2s linear infinite; } .progress-bar-success { background-color: #5cb85c; } .progress-striped .progress-bar-success { background-image: -webkit-linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-image: -o-linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-image: linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); } .progress-bar-info { background-color: #5bc0de; } .progress-striped .progress-bar-info { background-image: -webkit-linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-image: -o-linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-image: linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); } .progress-bar-warning { background-color: #f0ad4e; } .progress-striped .progress-bar-warning { background-image: -webkit-linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-image: -o-linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-image: linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); } .progress-bar-danger { background-color: #d9534f; } .progress-striped .progress-bar-danger { background-image: -webkit-linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-image: -o-linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); background-image: linear-gradient( 45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent ); } .media { margin-top: 15px; } .media:first-child { margin-top: 0; } .media, .media-body { zoom: 1; overflow: hidden; } .media-body { width: 10000px; } .media-object { display: block; } .media-object.img-thumbnail { max-width: none; } .media-right, .media > .pull-right { padding-left: 10px; } .media-left, .media > .pull-left { padding-right: 10px; } .media-left, .media-right, .media-body { display: table-cell; vertical-align: top; } .media-middle { vertical-align: middle; } .media-bottom { vertical-align: bottom; } .media-heading { margin-top: 0; margin-bottom: 5px; } .media-list { padding-left: 0; list-style: none; } .list-group { margin-bottom: 20px; padding-left: 0; } .list-group-item { position: relative; display: block; padding: 10px 15px; margin-bottom: -1px; background-color: #fff; border: 1px solid #ddd; } .list-group-item:first-child { border-top-right-radius: 2px; border-top-left-radius: 2px; } .list-group-item:last-child { margin-bottom: 0; border-bottom-right-radius: 2px; border-bottom-left-radius: 2px; } a.list-group-item, button.list-group-item { color: #555; } a.list-group-item .list-group-item-heading, button.list-group-item .list-group-item-heading { color: #333; } a.list-group-item:hover, button.list-group-item:hover, a.list-group-item:focus, button.list-group-item:focus { text-decoration: none; color: #555; background-color: #f5f5f5; } button.list-group-item { width: 100%; text-align: left; } .list-group-item.disabled, .list-group-item.disabled:hover, .list-group-item.disabled:focus { background-color: #eeeeee; color: #777777; cursor: not-allowed; } .list-group-item.disabled .list-group-item-heading, .list-group-item.disabled:hover .list-group-item-heading, .list-group-item.disabled:focus .list-group-item-heading { color: inherit; } .list-group-item.disabled .list-group-item-text, .list-group-item.disabled:hover .list-group-item-text, .list-group-item.disabled:focus .list-group-item-text { color: #777777; } .list-group-item.active, .list-group-item.active:hover, .list-group-item.active:focus { z-index: 2; color: #fff; background-color: #337ab7; border-color: #337ab7; } .list-group-item.active .list-group-item-heading, .list-group-item.active:hover .list-group-item-heading, .list-group-item.active:focus .list-group-item-heading, .list-group-item.active .list-group-item-heading > small, .list-group-item.active:hover .list-group-item-heading > small, .list-group-item.active:focus .list-group-item-heading > small, .list-group-item.active .list-group-item-heading > .small, .list-group-item.active:hover .list-group-item-heading > .small, .list-group-item.active:focus .list-group-item-heading > .small { color: inherit; } .list-group-item.active .list-group-item-text, .list-group-item.active:hover .list-group-item-text, .list-group-item.active:focus .list-group-item-text { color: #c7ddef; } .list-group-item-success { color: #3c763d; background-color: #dff0d8; } a.list-group-item-success, button.list-group-item-success { color: #3c763d; } a.list-group-item-success .list-group-item-heading, button.list-group-item-success .list-group-item-heading { color: inherit; } a.list-group-item-success:hover, button.list-group-item-success:hover, a.list-group-item-success:focus, button.list-group-item-success:focus { color: #3c763d; background-color: #d0e9c6; } a.list-group-item-success.active, button.list-group-item-success.active, a.list-group-item-success.active:hover, button.list-group-item-success.active:hover, a.list-group-item-success.active:focus, button.list-group-item-success.active:focus { color: #fff; background-color: #3c763d; border-color: #3c763d; } .list-group-item-info { color: #31708f; background-color: #d9edf7; } a.list-group-item-info, button.list-group-item-info { color: #31708f; } a.list-group-item-info .list-group-item-heading, button.list-group-item-info .list-group-item-heading { color: inherit; } a.list-group-item-info:hover, button.list-group-item-info:hover, a.list-group-item-info:focus, button.list-group-item-info:focus { color: #31708f; background-color: #c4e3f3; } a.list-group-item-info.active, button.list-group-item-info.active, a.list-group-item-info.active:hover, button.list-group-item-info.active:hover, a.list-group-item-info.active:focus, button.list-group-item-info.active:focus { color: #fff; background-color: #31708f; border-color: #31708f; } .list-group-item-warning { color: #8a6d3b; background-color: #fcf8e3; } a.list-group-item-warning, button.list-group-item-warning { color: #8a6d3b; } a.list-group-item-warning .list-group-item-heading, button.list-group-item-warning .list-group-item-heading { color: inherit; } a.list-group-item-warning:hover, button.list-group-item-warning:hover, a.list-group-item-warning:focus, button.list-group-item-warning:focus { color: #8a6d3b; background-color: #faf2cc; } a.list-group-item-warning.active, button.list-group-item-warning.active, a.list-group-item-warning.active:hover, button.list-group-item-warning.active:hover, a.list-group-item-warning.active:focus, button.list-group-item-warning.active:focus { color: #fff; background-color: #8a6d3b; border-color: #8a6d3b; } .list-group-item-danger { color: #a94442; background-color: #f2dede; } a.list-group-item-danger, button.list-group-item-danger { color: #a94442; } a.list-group-item-danger .list-group-item-heading, button.list-group-item-danger .list-group-item-heading { color: inherit; } a.list-group-item-danger:hover, button.list-group-item-danger:hover, a.list-group-item-danger:focus, button.list-group-item-danger:focus { color: #a94442; background-color: #ebcccc; } a.list-group-item-danger.active, button.list-group-item-danger.active, a.list-group-item-danger.active:hover, button.list-group-item-danger.active:hover, a.list-group-item-danger.active:focus, button.list-group-item-danger.active:focus { color: #fff; background-color: #a94442; border-color: #a94442; } .list-group-item-heading { margin-top: 0; margin-bottom: 5px; } .list-group-item-text { margin-bottom: 0; line-height: 1.3; } .panel { margin-bottom: 18px; background-color: #fff; border: 1px solid transparent; border-radius: 2px; -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); } .panel-body { padding: 15px; } .panel-heading { padding: 10px 15px; border-bottom: 1px solid transparent; border-top-right-radius: 1px; border-top-left-radius: 1px; } .panel-heading > .dropdown .dropdown-toggle { color: inherit; } .panel-title { margin-top: 0; margin-bottom: 0; font-size: 15px; color: inherit; } .panel-title > a, .panel-title > small, .panel-title > .small, .panel-title > small > a, .panel-title > .small > a { color: inherit; } .panel-footer { padding: 10px 15px; background-color: #f5f5f5; border-top: 1px solid #ddd; border-bottom-right-radius: 1px; border-bottom-left-radius: 1px; } .panel > .list-group, .panel > .panel-collapse > .list-group { margin-bottom: 0; } .panel > .list-group .list-group-item, .panel > .panel-collapse > .list-group .list-group-item { border-width: 1px 0; border-radius: 0; } .panel > .list-group:first-child .list-group-item:first-child, .panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { border-top: 0; border-top-right-radius: 1px; border-top-left-radius: 1px; } .panel > .list-group:last-child .list-group-item:last-child, .panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { border-bottom: 0; border-bottom-right-radius: 1px; border-bottom-left-radius: 1px; } .panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { border-top-right-radius: 0; border-top-left-radius: 0; } .panel-heading + .list-group .list-group-item:first-child { border-top-width: 0; } .list-group + .panel-footer { border-top-width: 0; } .panel > .table, .panel > .table-responsive > .table, .panel > .panel-collapse > .table { margin-bottom: 0; } .panel > .table caption, .panel > .table-responsive > .table caption, .panel > .panel-collapse > .table caption { padding-left: 15px; padding-right: 15px; } .panel > .table:first-child, .panel > .table-responsive:first-child > .table:first-child { border-top-right-radius: 1px; border-top-left-radius: 1px; } .panel > .table:first-child > thead:first-child > tr:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { border-top-left-radius: 1px; border-top-right-radius: 1px; } .panel > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, .panel > .table:first-child > thead:first-child > tr:first-child th:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { border-top-left-radius: 1px; } .panel > .table:first-child > thead:first-child > tr:first-child td:last-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, .panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, .panel > .table:first-child > thead:first-child > tr:first-child th:last-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, .panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { border-top-right-radius: 1px; } .panel > .table:last-child, .panel > .table-responsive:last-child > .table:last-child { border-bottom-right-radius: 1px; border-bottom-left-radius: 1px; } .panel > .table:last-child > tbody:last-child > tr:last-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { border-bottom-left-radius: 1px; border-bottom-right-radius: 1px; } .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, .panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, .panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { border-bottom-left-radius: 1px; } .panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, .panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { border-bottom-right-radius: 1px; } .panel > .panel-body + .table, .panel > .panel-body + .table-responsive, .panel > .table + .panel-body, .panel > .table-responsive + .panel-body { border-top: 1px solid #ddd; } .panel > .table > tbody:first-child > tr:first-child th, .panel > .table > tbody:first-child > tr:first-child td { border-top: 0; } .panel > .table-bordered, .panel > .table-responsive > .table-bordered { border: 0; } .panel > .table-bordered > thead > tr > th:first-child, .panel > .table-responsive > .table-bordered > thead > tr > th:first-child, .panel > .table-bordered > tbody > tr > th:first-child, .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, .panel > .table-bordered > tfoot > tr > th:first-child, .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, .panel > .table-bordered > thead > tr > td:first-child, .panel > .table-responsive > .table-bordered > thead > tr > td:first-child, .panel > .table-bordered > tbody > tr > td:first-child, .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, .panel > .table-bordered > tfoot > tr > td:first-child, .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { border-left: 0; } .panel > .table-bordered > thead > tr > th:last-child, .panel > .table-responsive > .table-bordered > thead > tr > th:last-child, .panel > .table-bordered > tbody > tr > th:last-child, .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, .panel > .table-bordered > tfoot > tr > th:last-child, .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, .panel > .table-bordered > thead > tr > td:last-child, .panel > .table-responsive > .table-bordered > thead > tr > td:last-child, .panel > .table-bordered > tbody > tr > td:last-child, .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, .panel > .table-bordered > tfoot > tr > td:last-child, .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { border-right: 0; } .panel > .table-bordered > thead > tr:first-child > td, .panel > .table-responsive > .table-bordered > thead > tr:first-child > td, .panel > .table-bordered > tbody > tr:first-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, .panel > .table-bordered > thead > tr:first-child > th, .panel > .table-responsive > .table-bordered > thead > tr:first-child > th, .panel > .table-bordered > tbody > tr:first-child > th, .panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { border-bottom: 0; } .panel > .table-bordered > tbody > tr:last-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, .panel > .table-bordered > tfoot > tr:last-child > td, .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, .panel > .table-bordered > tbody > tr:last-child > th, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, .panel > .table-bordered > tfoot > tr:last-child > th, .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { border-bottom: 0; } .panel > .table-responsive { border: 0; margin-bottom: 0; } .panel-group { margin-bottom: 18px; } .panel-group .panel { margin-bottom: 0; border-radius: 2px; } .panel-group .panel + .panel { margin-top: 5px; } .panel-group .panel-heading { border-bottom: 0; } .panel-group .panel-heading + .panel-collapse > .panel-body, .panel-group .panel-heading + .panel-collapse > .list-group { border-top: 1px solid #ddd; } .panel-group .panel-footer { border-top: 0; } .panel-group .panel-footer + .panel-collapse .panel-body { border-bottom: 1px solid #ddd; } .panel-default { border-color: #ddd; } .panel-default > .panel-heading { color: #333333; background-color: #f5f5f5; border-color: #ddd; } .panel-default > .panel-heading + .panel-collapse > .panel-body { border-top-color: #ddd; } .panel-default > .panel-heading .badge { color: #f5f5f5; background-color: #333333; } .panel-default > .panel-footer + .panel-collapse > .panel-body { border-bottom-color: #ddd; } .panel-primary { border-color: #337ab7; } .panel-primary > .panel-heading { color: #fff; background-color: #337ab7; border-color: #337ab7; } .panel-primary > .panel-heading + .panel-collapse > .panel-body { border-top-color: #337ab7; } .panel-primary > .panel-heading .badge { color: #337ab7; background-color: #fff; } .panel-primary > .panel-footer + .panel-collapse > .panel-body { border-bottom-color: #337ab7; } .panel-success { border-color: #d6e9c6; } .panel-success > .panel-heading { color: #3c763d; background-color: #dff0d8; border-color: #d6e9c6; } .panel-success > .panel-heading + .panel-collapse > .panel-body { border-top-color: #d6e9c6; } .panel-success > .panel-heading .badge { color: #dff0d8; background-color: #3c763d; } .panel-success > .panel-footer + .panel-collapse > .panel-body { border-bottom-color: #d6e9c6; } .panel-info { border-color: #bce8f1; } .panel-info > .panel-heading { color: #31708f; background-color: #d9edf7; border-color: #bce8f1; } .panel-info > .panel-heading + .panel-collapse > .panel-body { border-top-color: #bce8f1; } .panel-info > .panel-heading .badge { color: #d9edf7; background-color: #31708f; } .panel-info > .panel-footer + .panel-collapse > .panel-body { border-bottom-color: #bce8f1; } .panel-warning { border-color: #faebcc; } .panel-warning > .panel-heading { color: #8a6d3b; background-color: #fcf8e3; border-color: #faebcc; } .panel-warning > .panel-heading + .panel-collapse > .panel-body { border-top-color: #faebcc; } .panel-warning > .panel-heading .badge { color: #fcf8e3; background-color: #8a6d3b; } .panel-warning > .panel-footer + .panel-collapse > .panel-body { border-bottom-color: #faebcc; } .panel-danger { border-color: #ebccd1; } .panel-danger > .panel-heading { color: #a94442; background-color: #f2dede; border-color: #ebccd1; } .panel-danger > .panel-heading + .panel-collapse > .panel-body { border-top-color: #ebccd1; } .panel-danger > .panel-heading .badge { color: #f2dede; background-color: #a94442; } .panel-danger > .panel-footer + .panel-collapse > .panel-body { border-bottom-color: #ebccd1; } .embed-responsive { position: relative; display: block; height: 0; padding: 0; overflow: hidden; } .embed-responsive .embed-responsive-item, .embed-responsive iframe, .embed-responsive embed, .embed-responsive object, .embed-responsive video { position: absolute; top: 0; left: 0; bottom: 0; height: 100%; width: 100%; border: 0; } .embed-responsive-16by9 { padding-bottom: 56.25%; } .embed-responsive-4by3 { padding-bottom: 75%; } .well { min-height: 20px; padding: 19px; margin-bottom: 20px; background-color: #f5f5f5; border: 1px solid #e3e3e3; border-radius: 2px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); } .well blockquote { border-color: #ddd; border-color: rgba(0, 0, 0, 0.15); } .well-lg { padding: 24px; border-radius: 3px; } .well-sm { padding: 9px; border-radius: 1px; } .close { float: right; font-size: 19.5px; font-weight: bold; line-height: 1; color: #000; text-shadow: 0 1px 0 #fff; opacity: 0.2; filter: alpha(opacity=20); } .close:hover, .close:focus { color: #000; text-decoration: none; cursor: pointer; opacity: 0.5; filter: alpha(opacity=50); } button.close { padding: 0; cursor: pointer; background: transparent; border: 0; -webkit-appearance: none; } .modal-open { overflow: hidden; } .modal { display: none; overflow: hidden; position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1050; -webkit-overflow-scrolling: touch; outline: 0; } .modal.fade .modal-dialog { -webkit-transform: translate(0, -25%); -ms-transform: translate(0, -25%); -o-transform: translate(0, -25%); transform: translate(0, -25%); -webkit-transition: -webkit-transform 0.3s ease-out; -moz-transition: -moz-transform 0.3s ease-out; -o-transition: -o-transform 0.3s ease-out; transition: transform 0.3s ease-out; } .modal.in .modal-dialog { -webkit-transform: translate(0, 0); -ms-transform: translate(0, 0); -o-transform: translate(0, 0); transform: translate(0, 0); } .modal-open .modal { overflow-x: hidden; overflow-y: auto; } .modal-dialog { position: relative; width: auto; margin: 10px; } .modal-content { position: relative; background-color: #fff; border: 1px solid #999; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 3px; -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); background-clip: padding-box; outline: 0; } .modal-backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1040; background-color: #000; } .modal-backdrop.fade { opacity: 0; filter: alpha(opacity=0); } .modal-backdrop.in { opacity: 0.5; filter: alpha(opacity=50); } .modal-header { padding: 15px; border-bottom: 1px solid #e5e5e5; } .modal-header .close { margin-top: -2px; } .modal-title { margin: 0; line-height: 1.42857143; } .modal-body { position: relative; padding: 15px; } .modal-footer { padding: 15px; text-align: right; border-top: 1px solid #e5e5e5; } .modal-footer .btn + .btn { margin-left: 5px; margin-bottom: 0; } .modal-footer .btn-group .btn + .btn { margin-left: -1px; } .modal-footer .btn-block + .btn-block { margin-left: 0; } .modal-scrollbar-measure { position: absolute; top: -9999px; width: 50px; height: 50px; overflow: scroll; } @media (min-width: 768px) { .modal-dialog { width: 600px; margin: 30px auto; } .modal-content { -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); } .modal-sm { width: 300px; } } @media (min-width: 992px) { .modal-lg { width: 900px; } } .tooltip { position: absolute; z-index: 1070; display: block; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-style: normal; font-weight: normal; letter-spacing: normal; line-break: auto; line-height: 1.42857143; text-align: left; text-align: start; text-decoration: none; text-shadow: none; text-transform: none; white-space: normal; word-break: normal; word-spacing: normal; word-wrap: normal; font-size: 12px; opacity: 0; filter: alpha(opacity=0); } .tooltip.in { opacity: 0.9; filter: alpha(opacity=90); } .tooltip.top { margin-top: -3px; padding: 5px 0; } .tooltip.right { margin-left: 3px; padding: 0 5px; } .tooltip.bottom { margin-top: 3px; padding: 5px 0; } .tooltip.left { margin-left: -3px; padding: 0 5px; } .tooltip-inner { max-width: 200px; padding: 3px 8px; color: #fff; text-align: center; background-color: #000; border-radius: 2px; } .tooltip-arrow { position: absolute; width: 0; height: 0; border-color: transparent; border-style: solid; } .tooltip.top .tooltip-arrow { bottom: 0; left: 50%; margin-left: -5px; border-width: 5px 5px 0; border-top-color: #000; } .tooltip.top-left .tooltip-arrow { bottom: 0; right: 5px; margin-bottom: -5px; border-width: 5px 5px 0; border-top-color: #000; } .tooltip.top-right .tooltip-arrow { bottom: 0; left: 5px; margin-bottom: -5px; border-width: 5px 5px 0; border-top-color: #000; } .tooltip.right .tooltip-arrow { top: 50%; left: 0; margin-top: -5px; border-width: 5px 5px 5px 0; border-right-color: #000; } .tooltip.left .tooltip-arrow { top: 50%; right: 0; margin-top: -5px; border-width: 5px 0 5px 5px; border-left-color: #000; } .tooltip.bottom .tooltip-arrow { top: 0; left: 50%; margin-left: -5px; border-width: 0 5px 5px; border-bottom-color: #000; } .tooltip.bottom-left .tooltip-arrow { top: 0; right: 5px; margin-top: -5px; border-width: 0 5px 5px; border-bottom-color: #000; } .tooltip.bottom-right .tooltip-arrow { top: 0; left: 5px; margin-top: -5px; border-width: 0 5px 5px; border-bottom-color: #000; } .popover { position: absolute; top: 0; left: 0; z-index: 1060; display: none; max-width: 276px; padding: 1px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-style: normal; font-weight: normal; letter-spacing: normal; line-break: auto; line-height: 1.42857143; text-align: left; text-align: start; text-decoration: none; text-shadow: none; text-transform: none; white-space: normal; word-break: normal; word-spacing: normal; word-wrap: normal; font-size: 13px; background-color: #fff; background-clip: padding-box; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 3px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); } .popover.top { margin-top: -10px; } .popover.right { margin-left: 10px; } .popover.bottom { margin-top: 10px; } .popover.left { margin-left: -10px; } .popover-title { margin: 0; padding: 8px 14px; font-size: 13px; background-color: #f7f7f7; border-bottom: 1px solid #ebebeb; border-radius: 2px 2px 0 0; } .popover-content { padding: 9px 14px; } .popover > .arrow, .popover > .arrow:after { position: absolute; display: block; width: 0; height: 0; border-color: transparent; border-style: solid; } .popover > .arrow { border-width: 11px; } .popover > .arrow:after { border-width: 10px; content: ""; } .popover.top > .arrow { left: 50%; margin-left: -11px; border-bottom-width: 0; border-top-color: #999999; border-top-color: rgba(0, 0, 0, 0.25); bottom: -11px; } .popover.top > .arrow:after { content: " "; bottom: 1px; margin-left: -10px; border-bottom-width: 0; border-top-color: #fff; } .popover.right > .arrow { top: 50%; left: -11px; margin-top: -11px; border-left-width: 0; border-right-color: #999999; border-right-color: rgba(0, 0, 0, 0.25); } .popover.right > .arrow:after { content: " "; left: 1px; bottom: -10px; border-left-width: 0; border-right-color: #fff; } .popover.bottom > .arrow { left: 50%; margin-left: -11px; border-top-width: 0; border-bottom-color: #999999; border-bottom-color: rgba(0, 0, 0, 0.25); top: -11px; } .popover.bottom > .arrow:after { content: " "; top: 1px; margin-left: -10px; border-top-width: 0; border-bottom-color: #fff; } .popover.left > .arrow { top: 50%; right: -11px; margin-top: -11px; border-right-width: 0; border-left-color: #999999; border-left-color: rgba(0, 0, 0, 0.25); } .popover.left > .arrow:after { content: " "; right: 1px; border-right-width: 0; border-left-color: #fff; bottom: -10px; } .carousel { position: relative; } .carousel-inner { position: relative; overflow: hidden; width: 100%; } .carousel-inner > .item { display: none; position: relative; -webkit-transition: 0.6s ease-in-out left; -o-transition: 0.6s ease-in-out left; transition: 0.6s ease-in-out left; } .carousel-inner > .item > img, .carousel-inner > .item > a > img { line-height: 1; } @media all and (transform-3d), (-webkit-transform-3d) { .carousel-inner > .item { -webkit-transition: -webkit-transform 0.6s ease-in-out; -moz-transition: -moz-transform 0.6s ease-in-out; -o-transition: -o-transform 0.6s ease-in-out; transition: transform 0.6s ease-in-out; -webkit-backface-visibility: hidden; -moz-backface-visibility: hidden; backface-visibility: hidden; -webkit-perspective: 1000px; -moz-perspective: 1000px; perspective: 1000px; } .carousel-inner > .item.next, .carousel-inner > .item.active.right { -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); left: 0; } .carousel-inner > .item.prev, .carousel-inner > .item.active.left { -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); left: 0; } .carousel-inner > .item.next.left, .carousel-inner > .item.prev.right, .carousel-inner > .item.active { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); left: 0; } } .carousel-inner > .active, .carousel-inner > .next, .carousel-inner > .prev { display: block; } .carousel-inner > .active { left: 0; } .carousel-inner > .next, .carousel-inner > .prev { position: absolute; top: 0; width: 100%; } .carousel-inner > .next { left: 100%; } .carousel-inner > .prev { left: -100%; } .carousel-inner > .next.left, .carousel-inner > .prev.right { left: 0; } .carousel-inner > .active.left { left: -100%; } .carousel-inner > .active.right { left: 100%; } .carousel-control { position: absolute; top: 0; left: 0; bottom: 0; width: 15%; opacity: 0.5; filter: alpha(opacity=50); font-size: 20px; color: #fff; text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); background-color: rgba(0, 0, 0, 0); } .carousel-control.left { background-image: -webkit-linear-gradient( left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100% ); background-image: -o-linear-gradient( left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100% ); background-image: linear-gradient( to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100% ); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); } .carousel-control.right { left: auto; right: 0; background-image: -webkit-linear-gradient( left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100% ); background-image: -o-linear-gradient( left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100% ); background-image: linear-gradient( to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100% ); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); } .carousel-control:hover, .carousel-control:focus { outline: 0; color: #fff; text-decoration: none; opacity: 0.9; filter: alpha(opacity=90); } .carousel-control .icon-prev, .carousel-control .icon-next, .carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right { position: absolute; top: 50%; margin-top: -10px; z-index: 5; display: inline-block; } .carousel-control .icon-prev, .carousel-control .glyphicon-chevron-left { left: 50%; margin-left: -10px; } .carousel-control .icon-next, .carousel-control .glyphicon-chevron-right { right: 50%; margin-right: -10px; } .carousel-control .icon-prev, .carousel-control .icon-next { width: 20px; height: 20px; line-height: 1; font-family: serif; } .carousel-control .icon-prev:before { content: "\2039"; } .carousel-control .icon-next:before { content: "\203a"; } .carousel-indicators { position: absolute; bottom: 10px; left: 50%; z-index: 15; width: 60%; margin-left: -30%; padding-left: 0; list-style: none; text-align: center; } .carousel-indicators li { display: inline-block; width: 10px; height: 10px; margin: 1px; text-indent: -999px; border: 1px solid #fff; border-radius: 10px; cursor: pointer; background-color: #000 \9; background-color: rgba(0, 0, 0, 0); } .carousel-indicators .active { margin: 0; width: 12px; height: 12px; background-color: #fff; } .carousel-caption { position: absolute; left: 15%; right: 15%; bottom: 20px; z-index: 10; padding-top: 20px; padding-bottom: 20px; color: #fff; text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); } .carousel-caption .btn { text-shadow: none; } @media screen and (min-width: 768px) { .carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right, .carousel-control .icon-prev, .carousel-control .icon-next { width: 30px; height: 30px; margin-top: -10px; font-size: 30px; } .carousel-control .glyphicon-chevron-left, .carousel-control .icon-prev { margin-left: -10px; } .carousel-control .glyphicon-chevron-right, .carousel-control .icon-next { margin-right: -10px; } .carousel-caption { left: 20%; right: 20%; padding-bottom: 30px; } .carousel-indicators { bottom: 20px; } } .clearfix:before, .clearfix:after, .dl-horizontal dd:before, .dl-horizontal dd:after, .container:before, .container:after, .container-fluid:before, .container-fluid:after, .row:before, .row:after, .form-horizontal .form-group:before, .form-horizontal .form-group:after, .btn-toolbar:before, .btn-toolbar:after, .btn-group-vertical > .btn-group:before, .btn-group-vertical > .btn-group:after, .nav:before, .nav:after, .navbar:before, .navbar:after, .navbar-header:before, .navbar-header:after, .navbar-collapse:before, .navbar-collapse:after, .pager:before, .pager:after, .panel-body:before, .panel-body:after, .modal-header:before, .modal-header:after, .modal-footer:before, .modal-footer:after, .item_buttons:before, .item_buttons:after { content: " "; display: table; } .clearfix:after, .dl-horizontal dd:after, .container:after, .container-fluid:after, .row:after, .form-horizontal .form-group:after, .btn-toolbar:after, .btn-group-vertical > .btn-group:after, .nav:after, .navbar:after, .navbar-header:after, .navbar-collapse:after, .pager:after, .panel-body:after, .modal-header:after, .modal-footer:after, .item_buttons:after { clear: both; } .center-block { display: block; margin-left: auto; margin-right: auto; } .pull-right { float: right !important; } .pull-left { float: left !important; } .hide { display: none !important; } .show { display: block !important; } .invisible { visibility: hidden; } .text-hide { font: 0/0 a; color: transparent; text-shadow: none; background-color: transparent; border: 0; } .hidden { display: none !important; } .affix { position: fixed; } @-ms-viewport { width: device-width; } .visible-xs, .visible-sm, .visible-md, .visible-lg { display: none !important; } .visible-xs-block, .visible-xs-inline, .visible-xs-inline-block, .visible-sm-block, .visible-sm-inline, .visible-sm-inline-block, .visible-md-block, .visible-md-inline, .visible-md-inline-block, .visible-lg-block, .visible-lg-inline, .visible-lg-inline-block { display: none !important; } @media (max-width: 767px) { .visible-xs { display: block !important; } table.visible-xs { display: table !important; } tr.visible-xs { display: table-row !important; } th.visible-xs, td.visible-xs { display: table-cell !important; } } @media (max-width: 767px) { .visible-xs-block { display: block !important; } } @media (max-width: 767px) { .visible-xs-inline { display: inline !important; } } @media (max-width: 767px) { .visible-xs-inline-block { display: inline-block !important; } } @media (min-width: 768px) and (max-width: 991px) { .visible-sm { display: block !important; } table.visible-sm { display: table !important; } tr.visible-sm { display: table-row !important; } th.visible-sm, td.visible-sm { display: table-cell !important; } } @media (min-width: 768px) and (max-width: 991px) { .visible-sm-block { display: block !important; } } @media (min-width: 768px) and (max-width: 991px) { .visible-sm-inline { display: inline !important; } } @media (min-width: 768px) and (max-width: 991px) { .visible-sm-inline-block { display: inline-block !important; } } @media (min-width: 992px) and (max-width: 1199px) { .visible-md { display: block !important; } table.visible-md { display: table !important; } tr.visible-md { display: table-row !important; } th.visible-md, td.visible-md { display: table-cell !important; } } @media (min-width: 992px) and (max-width: 1199px) { .visible-md-block { display: block !important; } } @media (min-width: 992px) and (max-width: 1199px) { .visible-md-inline { display: inline !important; } } @media (min-width: 992px) and (max-width: 1199px) { .visible-md-inline-block { display: inline-block !important; } } @media (min-width: 1200px) { .visible-lg { display: block !important; } table.visible-lg { display: table !important; } tr.visible-lg { display: table-row !important; } th.visible-lg, td.visible-lg { display: table-cell !important; } } @media (min-width: 1200px) { .visible-lg-block { display: block !important; } } @media (min-width: 1200px) { .visible-lg-inline { display: inline !important; } } @media (min-width: 1200px) { .visible-lg-inline-block { display: inline-block !important; } } @media (max-width: 767px) { .hidden-xs { display: none !important; } } @media (min-width: 768px) and (max-width: 991px) { .hidden-sm { display: none !important; } } @media (min-width: 992px) and (max-width: 1199px) { .hidden-md { display: none !important; } } @media (min-width: 1200px) { .hidden-lg { display: none !important; } } .visible-print { display: none !important; } @media print { .visible-print { display: block !important; } table.visible-print { display: table !important; } tr.visible-print { display: table-row !important; } th.visible-print, td.visible-print { display: table-cell !important; } } .visible-print-block { display: none !important; } @media print { .visible-print-block { display: block !important; } } .visible-print-inline { display: none !important; } @media print { .visible-print-inline { display: inline !important; } } .visible-print-inline-block { display: none !important; } @media print { .visible-print-inline-block { display: inline-block !important; } } @media print { .hidden-print { display: none !important; } } /*! * * Font Awesome * */ /*! * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ /* FONT PATH * -------------------------- */ @font-face { font-family: "FontAwesome"; src: url("../components/font-awesome/fonts/fontawesome-webfont.eot?v=4.7.0"); src: url("../components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"), url("../components/font-awesome/fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"), url("../components/font-awesome/fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"), url("../components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"), url("../components/font-awesome/fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg"); font-weight: normal; font-style: normal; } .fa { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } /* makes the font 33% larger relative to the icon container */ .fa-lg { font-size: 1.33333333em; line-height: 0.75em; vertical-align: -15%; } .fa-2x { font-size: 2em; } .fa-3x { font-size: 3em; } .fa-4x { font-size: 4em; } .fa-5x { font-size: 5em; } .fa-fw { width: 1.28571429em; text-align: center; } .fa-ul { padding-left: 0; margin-left: 2.14285714em; list-style-type: none; } .fa-ul > li { position: relative; } .fa-li { position: absolute; left: -2.14285714em; width: 2.14285714em; top: 0.14285714em; text-align: center; } .fa-li.fa-lg { left: -1.85714286em; } .fa-border { padding: 0.2em 0.25em 0.15em; border: solid 0.08em #eee; border-radius: 0.1em; } .fa-pull-left { float: left; } .fa-pull-right { float: right; } .fa.fa-pull-left { margin-right: 0.3em; } .fa.fa-pull-right { margin-left: 0.3em; } /* Deprecated as of 4.4.0 */ .pull-right { float: right; } .pull-left { float: left; } .fa.pull-left { margin-right: 0.3em; } .fa.pull-right { margin-left: 0.3em; } .fa-spin { -webkit-animation: fa-spin 2s infinite linear; animation: fa-spin 2s infinite linear; } .fa-pulse { -webkit-animation: fa-spin 1s infinite steps(8); animation: fa-spin 1s infinite steps(8); } @-webkit-keyframes fa-spin { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(359deg); transform: rotate(359deg); } } @keyframes fa-spin { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(359deg); transform: rotate(359deg); } } .fa-rotate-90 { -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; -webkit-transform: rotate(90deg); -ms-transform: rotate(90deg); transform: rotate(90deg); } .fa-rotate-180 { -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; -webkit-transform: rotate(180deg); -ms-transform: rotate(180deg); transform: rotate(180deg); } .fa-rotate-270 { -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; -webkit-transform: rotate(270deg); -ms-transform: rotate(270deg); transform: rotate(270deg); } .fa-flip-horizontal { -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; -webkit-transform: scale(-1, 1); -ms-transform: scale(-1, 1); transform: scale(-1, 1); } .fa-flip-vertical { -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; -webkit-transform: scale(1, -1); -ms-transform: scale(1, -1); transform: scale(1, -1); } :root .fa-rotate-90, :root .fa-rotate-180, :root .fa-rotate-270, :root .fa-flip-horizontal, :root .fa-flip-vertical { filter: none; } .fa-stack { position: relative; display: inline-block; width: 2em; height: 2em; line-height: 2em; vertical-align: middle; } .fa-stack-1x, .fa-stack-2x { position: absolute; left: 0; width: 100%; text-align: center; } .fa-stack-1x { line-height: inherit; } .fa-stack-2x { font-size: 2em; } .fa-inverse { color: #fff; } /* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen readers do not read off random characters that represent icons */ .fa-glass:before { content: "\f000"; } .fa-music:before { content: "\f001"; } .fa-search:before { content: "\f002"; } .fa-envelope-o:before { content: "\f003"; } .fa-heart:before { content: "\f004"; } .fa-star:before { content: "\f005"; } .fa-star-o:before { content: "\f006"; } .fa-user:before { content: "\f007"; } .fa-film:before { content: "\f008"; } .fa-th-large:before { content: "\f009"; } .fa-th:before { content: "\f00a"; } .fa-th-list:before { content: "\f00b"; } .fa-check:before { content: "\f00c"; } .fa-remove:before, .fa-close:before, .fa-times:before { content: "\f00d"; } .fa-search-plus:before { content: "\f00e"; } .fa-search-minus:before { content: "\f010"; } .fa-power-off:before { content: "\f011"; } .fa-signal:before { content: "\f012"; } .fa-gear:before, .fa-cog:before { content: "\f013"; } .fa-trash-o:before { content: "\f014"; } .fa-home:before { content: "\f015"; } .fa-file-o:before { content: "\f016"; } .fa-clock-o:before { content: "\f017"; } .fa-road:before { content: "\f018"; } .fa-download:before { content: "\f019"; } .fa-arrow-circle-o-down:before { content: "\f01a"; } .fa-arrow-circle-o-up:before { content: "\f01b"; } .fa-inbox:before { content: "\f01c"; } .fa-play-circle-o:before { content: "\f01d"; } .fa-rotate-right:before, .fa-repeat:before { content: "\f01e"; } .fa-refresh:before { content: "\f021"; } .fa-list-alt:before { content: "\f022"; } .fa-lock:before { content: "\f023"; } .fa-flag:before { content: "\f024"; } .fa-headphones:before { content: "\f025"; } .fa-volume-off:before { content: "\f026"; } .fa-volume-down:before { content: "\f027"; } .fa-volume-up:before { content: "\f028"; } .fa-qrcode:before { content: "\f029"; } .fa-barcode:before { content: "\f02a"; } .fa-tag:before { content: "\f02b"; } .fa-tags:before { content: "\f02c"; } .fa-book:before { content: "\f02d"; } .fa-bookmark:before { content: "\f02e"; } .fa-print:before { content: "\f02f"; } .fa-camera:before { content: "\f030"; } .fa-font:before { content: "\f031"; } .fa-bold:before { content: "\f032"; } .fa-italic:before { content: "\f033"; } .fa-text-height:before { content: "\f034"; } .fa-text-width:before { content: "\f035"; } .fa-align-left:before { content: "\f036"; } .fa-align-center:before { content: "\f037"; } .fa-align-right:before { content: "\f038"; } .fa-align-justify:before { content: "\f039"; } .fa-list:before { content: "\f03a"; } .fa-dedent:before, .fa-outdent:before { content: "\f03b"; } .fa-indent:before { content: "\f03c"; } .fa-video-camera:before { content: "\f03d"; } .fa-photo:before, .fa-image:before, .fa-picture-o:before { content: "\f03e"; } .fa-pencil:before { content: "\f040"; } .fa-map-marker:before { content: "\f041"; } .fa-adjust:before { content: "\f042"; } .fa-tint:before { content: "\f043"; } .fa-edit:before, .fa-pencil-square-o:before { content: "\f044"; } .fa-share-square-o:before { content: "\f045"; } .fa-check-square-o:before { content: "\f046"; } .fa-arrows:before { content: "\f047"; } .fa-step-backward:before { content: "\f048"; } .fa-fast-backward:before { content: "\f049"; } .fa-backward:before { content: "\f04a"; } .fa-play:before { content: "\f04b"; } .fa-pause:before { content: "\f04c"; } .fa-stop:before { content: "\f04d"; } .fa-forward:before { content: "\f04e"; } .fa-fast-forward:before { content: "\f050"; } .fa-step-forward:before { content: "\f051"; } .fa-eject:before { content: "\f052"; } .fa-chevron-left:before { content: "\f053"; } .fa-chevron-right:before { content: "\f054"; } .fa-plus-circle:before { content: "\f055"; } .fa-minus-circle:before { content: "\f056"; } .fa-times-circle:before { content: "\f057"; } .fa-check-circle:before { content: "\f058"; } .fa-question-circle:before { content: "\f059"; } .fa-info-circle:before { content: "\f05a"; } .fa-crosshairs:before { content: "\f05b"; } .fa-times-circle-o:before { content: "\f05c"; } .fa-check-circle-o:before { content: "\f05d"; } .fa-ban:before { content: "\f05e"; } .fa-arrow-left:before { content: "\f060"; } .fa-arrow-right:before { content: "\f061"; } .fa-arrow-up:before { content: "\f062"; } .fa-arrow-down:before { content: "\f063"; } .fa-mail-forward:before, .fa-share:before { content: "\f064"; } .fa-expand:before { content: "\f065"; } .fa-compress:before { content: "\f066"; } .fa-plus:before { content: "\f067"; } .fa-minus:before { content: "\f068"; } .fa-asterisk:before { content: "\f069"; } .fa-exclamation-circle:before { content: "\f06a"; } .fa-gift:before { content: "\f06b"; } .fa-leaf:before { content: "\f06c"; } .fa-fire:before { content: "\f06d"; } .fa-eye:before { content: "\f06e"; } .fa-eye-slash:before { content: "\f070"; } .fa-warning:before, .fa-exclamation-triangle:before { content: "\f071"; } .fa-plane:before { content: "\f072"; } .fa-calendar:before { content: "\f073"; } .fa-random:before { content: "\f074"; } .fa-comment:before { content: "\f075"; } .fa-magnet:before { content: "\f076"; } .fa-chevron-up:before { content: "\f077"; } .fa-chevron-down:before { content: "\f078"; } .fa-retweet:before { content: "\f079"; } .fa-shopping-cart:before { content: "\f07a"; } .fa-folder:before { content: "\f07b"; } .fa-folder-open:before { content: "\f07c"; } .fa-arrows-v:before { content: "\f07d"; } .fa-arrows-h:before { content: "\f07e"; } .fa-bar-chart-o:before, .fa-bar-chart:before { content: "\f080"; } .fa-twitter-square:before { content: "\f081"; } .fa-facebook-square:before { content: "\f082"; } .fa-camera-retro:before { content: "\f083"; } .fa-key:before { content: "\f084"; } .fa-gears:before, .fa-cogs:before { content: "\f085"; } .fa-comments:before { content: "\f086"; } .fa-thumbs-o-up:before { content: "\f087"; } .fa-thumbs-o-down:before { content: "\f088"; } .fa-star-half:before { content: "\f089"; } .fa-heart-o:before { content: "\f08a"; } .fa-sign-out:before { content: "\f08b"; } .fa-linkedin-square:before { content: "\f08c"; } .fa-thumb-tack:before { content: "\f08d"; } .fa-external-link:before { content: "\f08e"; } .fa-sign-in:before { content: "\f090"; } .fa-trophy:before { content: "\f091"; } .fa-github-square:before { content: "\f092"; } .fa-upload:before { content: "\f093"; } .fa-lemon-o:before { content: "\f094"; } .fa-phone:before { content: "\f095"; } .fa-square-o:before { content: "\f096"; } .fa-bookmark-o:before { content: "\f097"; } .fa-phone-square:before { content: "\f098"; } .fa-twitter:before { content: "\f099"; } .fa-facebook-f:before, .fa-facebook:before { content: "\f09a"; } .fa-github:before { content: "\f09b"; } .fa-unlock:before { content: "\f09c"; } .fa-credit-card:before { content: "\f09d"; } .fa-feed:before, .fa-rss:before { content: "\f09e"; } .fa-hdd-o:before { content: "\f0a0"; } .fa-bullhorn:before { content: "\f0a1"; } .fa-bell:before { content: "\f0f3"; } .fa-certificate:before { content: "\f0a3"; } .fa-hand-o-right:before { content: "\f0a4"; } .fa-hand-o-left:before { content: "\f0a5"; } .fa-hand-o-up:before { content: "\f0a6"; } .fa-hand-o-down:before { content: "\f0a7"; } .fa-arrow-circle-left:before { content: "\f0a8"; } .fa-arrow-circle-right:before { content: "\f0a9"; } .fa-arrow-circle-up:before { content: "\f0aa"; } .fa-arrow-circle-down:before { content: "\f0ab"; } .fa-globe:before { content: "\f0ac"; } .fa-wrench:before { content: "\f0ad"; } .fa-tasks:before { content: "\f0ae"; } .fa-filter:before { content: "\f0b0"; } .fa-briefcase:before { content: "\f0b1"; } .fa-arrows-alt:before { content: "\f0b2"; } .fa-group:before, .fa-users:before { content: "\f0c0"; } .fa-chain:before, .fa-link:before { content: "\f0c1"; } .fa-cloud:before { content: "\f0c2"; } .fa-flask:before { content: "\f0c3"; } .fa-cut:before, .fa-scissors:before { content: "\f0c4"; } .fa-copy:before, .fa-files-o:before { content: "\f0c5"; } .fa-paperclip:before { content: "\f0c6"; } .fa-save:before, .fa-floppy-o:before { content: "\f0c7"; } .fa-square:before { content: "\f0c8"; } .fa-navicon:before, .fa-reorder:before, .fa-bars:before { content: "\f0c9"; } .fa-list-ul:before { content: "\f0ca"; } .fa-list-ol:before { content: "\f0cb"; } .fa-strikethrough:before { content: "\f0cc"; } .fa-underline:before { content: "\f0cd"; } .fa-table:before { content: "\f0ce"; } .fa-magic:before { content: "\f0d0"; } .fa-truck:before { content: "\f0d1"; } .fa-pinterest:before { content: "\f0d2"; } .fa-pinterest-square:before { content: "\f0d3"; } .fa-google-plus-square:before { content: "\f0d4"; } .fa-google-plus:before { content: "\f0d5"; } .fa-money:before { content: "\f0d6"; } .fa-caret-down:before { content: "\f0d7"; } .fa-caret-up:before { content: "\f0d8"; } .fa-caret-left:before { content: "\f0d9"; } .fa-caret-right:before { content: "\f0da"; } .fa-columns:before { content: "\f0db"; } .fa-unsorted:before, .fa-sort:before { content: "\f0dc"; } .fa-sort-down:before, .fa-sort-desc:before { content: "\f0dd"; } .fa-sort-up:before, .fa-sort-asc:before { content: "\f0de"; } .fa-envelope:before { content: "\f0e0"; } .fa-linkedin:before { content: "\f0e1"; } .fa-rotate-left:before, .fa-undo:before { content: "\f0e2"; } .fa-legal:before, .fa-gavel:before { content: "\f0e3"; } .fa-dashboard:before, .fa-tachometer:before { content: "\f0e4"; } .fa-comment-o:before { content: "\f0e5"; } .fa-comments-o:before { content: "\f0e6"; } .fa-flash:before, .fa-bolt:before { content: "\f0e7"; } .fa-sitemap:before { content: "\f0e8"; } .fa-umbrella:before { content: "\f0e9"; } .fa-paste:before, .fa-clipboard:before { content: "\f0ea"; } .fa-lightbulb-o:before { content: "\f0eb"; } .fa-exchange:before { content: "\f0ec"; } .fa-cloud-download:before { content: "\f0ed"; } .fa-cloud-upload:before { content: "\f0ee"; } .fa-user-md:before { content: "\f0f0"; } .fa-stethoscope:before { content: "\f0f1"; } .fa-suitcase:before { content: "\f0f2"; } .fa-bell-o:before { content: "\f0a2"; } .fa-coffee:before { content: "\f0f4"; } .fa-cutlery:before { content: "\f0f5"; } .fa-file-text-o:before { content: "\f0f6"; } .fa-building-o:before { content: "\f0f7"; } .fa-hospital-o:before { content: "\f0f8"; } .fa-ambulance:before { content: "\f0f9"; } .fa-medkit:before { content: "\f0fa"; } .fa-fighter-jet:before { content: "\f0fb"; } .fa-beer:before { content: "\f0fc"; } .fa-h-square:before { content: "\f0fd"; } .fa-plus-square:before { content: "\f0fe"; } .fa-angle-double-left:before { content: "\f100"; } .fa-angle-double-right:before { content: "\f101"; } .fa-angle-double-up:before { content: "\f102"; } .fa-angle-double-down:before { content: "\f103"; } .fa-angle-left:before { content: "\f104"; } .fa-angle-right:before { content: "\f105"; } .fa-angle-up:before { content: "\f106"; } .fa-angle-down:before { content: "\f107"; } .fa-desktop:before { content: "\f108"; } .fa-laptop:before { content: "\f109"; } .fa-tablet:before { content: "\f10a"; } .fa-mobile-phone:before, .fa-mobile:before { content: "\f10b"; } .fa-circle-o:before { content: "\f10c"; } .fa-quote-left:before { content: "\f10d"; } .fa-quote-right:before { content: "\f10e"; } .fa-spinner:before { content: "\f110"; } .fa-circle:before { content: "\f111"; } .fa-mail-reply:before, .fa-reply:before { content: "\f112"; } .fa-github-alt:before { content: "\f113"; } .fa-folder-o:before { content: "\f114"; } .fa-folder-open-o:before { content: "\f115"; } .fa-smile-o:before { content: "\f118"; } .fa-frown-o:before { content: "\f119"; } .fa-meh-o:before { content: "\f11a"; } .fa-gamepad:before { content: "\f11b"; } .fa-keyboard-o:before { content: "\f11c"; } .fa-flag-o:before { content: "\f11d"; } .fa-flag-checkered:before { content: "\f11e"; } .fa-terminal:before { content: "\f120"; } .fa-code:before { content: "\f121"; } .fa-mail-reply-all:before, .fa-reply-all:before { content: "\f122"; } .fa-star-half-empty:before, .fa-star-half-full:before, .fa-star-half-o:before { content: "\f123"; } .fa-location-arrow:before { content: "\f124"; } .fa-crop:before { content: "\f125"; } .fa-code-fork:before { content: "\f126"; } .fa-unlink:before, .fa-chain-broken:before { content: "\f127"; } .fa-question:before { content: "\f128"; } .fa-info:before { content: "\f129"; } .fa-exclamation:before { content: "\f12a"; } .fa-superscript:before { content: "\f12b"; } .fa-subscript:before { content: "\f12c"; } .fa-eraser:before { content: "\f12d"; } .fa-puzzle-piece:before { content: "\f12e"; } .fa-microphone:before { content: "\f130"; } .fa-microphone-slash:before { content: "\f131"; } .fa-shield:before { content: "\f132"; } .fa-calendar-o:before { content: "\f133"; } .fa-fire-extinguisher:before { content: "\f134"; } .fa-rocket:before { content: "\f135"; } .fa-maxcdn:before { content: "\f136"; } .fa-chevron-circle-left:before { content: "\f137"; } .fa-chevron-circle-right:before { content: "\f138"; } .fa-chevron-circle-up:before { content: "\f139"; } .fa-chevron-circle-down:before { content: "\f13a"; } .fa-html5:before { content: "\f13b"; } .fa-css3:before { content: "\f13c"; } .fa-anchor:before { content: "\f13d"; } .fa-unlock-alt:before { content: "\f13e"; } .fa-bullseye:before { content: "\f140"; } .fa-ellipsis-h:before { content: "\f141"; } .fa-ellipsis-v:before { content: "\f142"; } .fa-rss-square:before { content: "\f143"; } .fa-play-circle:before { content: "\f144"; } .fa-ticket:before { content: "\f145"; } .fa-minus-square:before { content: "\f146"; } .fa-minus-square-o:before { content: "\f147"; } .fa-level-up:before { content: "\f148"; } .fa-level-down:before { content: "\f149"; } .fa-check-square:before { content: "\f14a"; } .fa-pencil-square:before { content: "\f14b"; } .fa-external-link-square:before { content: "\f14c"; } .fa-share-square:before { content: "\f14d"; } .fa-compass:before { content: "\f14e"; } .fa-toggle-down:before, .fa-caret-square-o-down:before { content: "\f150"; } .fa-toggle-up:before, .fa-caret-square-o-up:before { content: "\f151"; } .fa-toggle-right:before, .fa-caret-square-o-right:before { content: "\f152"; } .fa-euro:before, .fa-eur:before { content: "\f153"; } .fa-gbp:before { content: "\f154"; } .fa-dollar:before, .fa-usd:before { content: "\f155"; } .fa-rupee:before, .fa-inr:before { content: "\f156"; } .fa-cny:before, .fa-rmb:before, .fa-yen:before, .fa-jpy:before { content: "\f157"; } .fa-ruble:before, .fa-rouble:before, .fa-rub:before { content: "\f158"; } .fa-won:before, .fa-krw:before { content: "\f159"; } .fa-bitcoin:before, .fa-btc:before { content: "\f15a"; } .fa-file:before { content: "\f15b"; } .fa-file-text:before { content: "\f15c"; } .fa-sort-alpha-asc:before { content: "\f15d"; } .fa-sort-alpha-desc:before { content: "\f15e"; } .fa-sort-amount-asc:before { content: "\f160"; } .fa-sort-amount-desc:before { content: "\f161"; } .fa-sort-numeric-asc:before { content: "\f162"; } .fa-sort-numeric-desc:before { content: "\f163"; } .fa-thumbs-up:before { content: "\f164"; } .fa-thumbs-down:before { content: "\f165"; } .fa-youtube-square:before { content: "\f166"; } .fa-youtube:before { content: "\f167"; } .fa-xing:before { content: "\f168"; } .fa-xing-square:before { content: "\f169"; } .fa-youtube-play:before { content: "\f16a"; } .fa-dropbox:before { content: "\f16b"; } .fa-stack-overflow:before { content: "\f16c"; } .fa-instagram:before { content: "\f16d"; } .fa-flickr:before { content: "\f16e"; } .fa-adn:before { content: "\f170"; } .fa-bitbucket:before { content: "\f171"; } .fa-bitbucket-square:before { content: "\f172"; } .fa-tumblr:before { content: "\f173"; } .fa-tumblr-square:before { content: "\f174"; } .fa-long-arrow-down:before { content: "\f175"; } .fa-long-arrow-up:before { content: "\f176"; } .fa-long-arrow-left:before { content: "\f177"; } .fa-long-arrow-right:before { content: "\f178"; } .fa-apple:before { content: "\f179"; } .fa-windows:before { content: "\f17a"; } .fa-android:before { content: "\f17b"; } .fa-linux:before { content: "\f17c"; } .fa-dribbble:before { content: "\f17d"; } .fa-skype:before { content: "\f17e"; } .fa-foursquare:before { content: "\f180"; } .fa-trello:before { content: "\f181"; } .fa-female:before { content: "\f182"; } .fa-male:before { content: "\f183"; } .fa-gittip:before, .fa-gratipay:before { content: "\f184"; } .fa-sun-o:before { content: "\f185"; } .fa-moon-o:before { content: "\f186"; } .fa-archive:before { content: "\f187"; } .fa-bug:before { content: "\f188"; } .fa-vk:before { content: "\f189"; } .fa-weibo:before { content: "\f18a"; } .fa-renren:before { content: "\f18b"; } .fa-pagelines:before { content: "\f18c"; } .fa-stack-exchange:before { content: "\f18d"; } .fa-arrow-circle-o-right:before { content: "\f18e"; } .fa-arrow-circle-o-left:before { content: "\f190"; } .fa-toggle-left:before, .fa-caret-square-o-left:before { content: "\f191"; } .fa-dot-circle-o:before { content: "\f192"; } .fa-wheelchair:before { content: "\f193"; } .fa-vimeo-square:before { content: "\f194"; } .fa-turkish-lira:before, .fa-try:before { content: "\f195"; } .fa-plus-square-o:before { content: "\f196"; } .fa-space-shuttle:before { content: "\f197"; } .fa-slack:before { content: "\f198"; } .fa-envelope-square:before { content: "\f199"; } .fa-wordpress:before { content: "\f19a"; } .fa-openid:before { content: "\f19b"; } .fa-institution:before, .fa-bank:before, .fa-university:before { content: "\f19c"; } .fa-mortar-board:before, .fa-graduation-cap:before { content: "\f19d"; } .fa-yahoo:before { content: "\f19e"; } .fa-google:before { content: "\f1a0"; } .fa-reddit:before { content: "\f1a1"; } .fa-reddit-square:before { content: "\f1a2"; } .fa-stumbleupon-circle:before { content: "\f1a3"; } .fa-stumbleupon:before { content: "\f1a4"; } .fa-delicious:before { content: "\f1a5"; } .fa-digg:before { content: "\f1a6"; } .fa-pied-piper-pp:before { content: "\f1a7"; } .fa-pied-piper-alt:before { content: "\f1a8"; } .fa-drupal:before { content: "\f1a9"; } .fa-joomla:before { content: "\f1aa"; } .fa-language:before { content: "\f1ab"; } .fa-fax:before { content: "\f1ac"; } .fa-building:before { content: "\f1ad"; } .fa-child:before { content: "\f1ae"; } .fa-paw:before { content: "\f1b0"; } .fa-spoon:before { content: "\f1b1"; } .fa-cube:before { content: "\f1b2"; } .fa-cubes:before { content: "\f1b3"; } .fa-behance:before { content: "\f1b4"; } .fa-behance-square:before { content: "\f1b5"; } .fa-steam:before { content: "\f1b6"; } .fa-steam-square:before { content: "\f1b7"; } .fa-recycle:before { content: "\f1b8"; } .fa-automobile:before, .fa-car:before { content: "\f1b9"; } .fa-cab:before, .fa-taxi:before { content: "\f1ba"; } .fa-tree:before { content: "\f1bb"; } .fa-spotify:before { content: "\f1bc"; } .fa-deviantart:before { content: "\f1bd"; } .fa-soundcloud:before { content: "\f1be"; } .fa-database:before { content: "\f1c0"; } .fa-file-pdf-o:before { content: "\f1c1"; } .fa-file-word-o:before { content: "\f1c2"; } .fa-file-excel-o:before { content: "\f1c3"; } .fa-file-powerpoint-o:before { content: "\f1c4"; } .fa-file-photo-o:before, .fa-file-picture-o:before, .fa-file-image-o:before { content: "\f1c5"; } .fa-file-zip-o:before, .fa-file-archive-o:before { content: "\f1c6"; } .fa-file-sound-o:before, .fa-file-audio-o:before { content: "\f1c7"; } .fa-file-movie-o:before, .fa-file-video-o:before { content: "\f1c8"; } .fa-file-code-o:before { content: "\f1c9"; } .fa-vine:before { content: "\f1ca"; } .fa-codepen:before { content: "\f1cb"; } .fa-jsfiddle:before { content: "\f1cc"; } .fa-life-bouy:before, .fa-life-buoy:before, .fa-life-saver:before, .fa-support:before, .fa-life-ring:before { content: "\f1cd"; } .fa-circle-o-notch:before { content: "\f1ce"; } .fa-ra:before, .fa-resistance:before, .fa-rebel:before { content: "\f1d0"; } .fa-ge:before, .fa-empire:before { content: "\f1d1"; } .fa-git-square:before { content: "\f1d2"; } .fa-git:before { content: "\f1d3"; } .fa-y-combinator-square:before, .fa-yc-square:before, .fa-hacker-news:before { content: "\f1d4"; } .fa-tencent-weibo:before { content: "\f1d5"; } .fa-qq:before { content: "\f1d6"; } .fa-wechat:before, .fa-weixin:before { content: "\f1d7"; } .fa-send:before, .fa-paper-plane:before { content: "\f1d8"; } .fa-send-o:before, .fa-paper-plane-o:before { content: "\f1d9"; } .fa-history:before { content: "\f1da"; } .fa-circle-thin:before { content: "\f1db"; } .fa-header:before { content: "\f1dc"; } .fa-paragraph:before { content: "\f1dd"; } .fa-sliders:before { content: "\f1de"; } .fa-share-alt:before { content: "\f1e0"; } .fa-share-alt-square:before { content: "\f1e1"; } .fa-bomb:before { content: "\f1e2"; } .fa-soccer-ball-o:before, .fa-futbol-o:before { content: "\f1e3"; } .fa-tty:before { content: "\f1e4"; } .fa-binoculars:before { content: "\f1e5"; } .fa-plug:before { content: "\f1e6"; } .fa-slideshare:before { content: "\f1e7"; } .fa-twitch:before { content: "\f1e8"; } .fa-yelp:before { content: "\f1e9"; } .fa-newspaper-o:before { content: "\f1ea"; } .fa-wifi:before { content: "\f1eb"; } .fa-calculator:before { content: "\f1ec"; } .fa-paypal:before { content: "\f1ed"; } .fa-google-wallet:before { content: "\f1ee"; } .fa-cc-visa:before { content: "\f1f0"; } .fa-cc-mastercard:before { content: "\f1f1"; } .fa-cc-discover:before { content: "\f1f2"; } .fa-cc-amex:before { content: "\f1f3"; } .fa-cc-paypal:before { content: "\f1f4"; } .fa-cc-stripe:before { content: "\f1f5"; } .fa-bell-slash:before { content: "\f1f6"; } .fa-bell-slash-o:before { content: "\f1f7"; } .fa-trash:before { content: "\f1f8"; } .fa-copyright:before { content: "\f1f9"; } .fa-at:before { content: "\f1fa"; } .fa-eyedropper:before { content: "\f1fb"; } .fa-paint-brush:before { content: "\f1fc"; } .fa-birthday-cake:before { content: "\f1fd"; } .fa-area-chart:before { content: "\f1fe"; } .fa-pie-chart:before { content: "\f200"; } .fa-line-chart:before { content: "\f201"; } .fa-lastfm:before { content: "\f202"; } .fa-lastfm-square:before { content: "\f203"; } .fa-toggle-off:before { content: "\f204"; } .fa-toggle-on:before { content: "\f205"; } .fa-bicycle:before { content: "\f206"; } .fa-bus:before { content: "\f207"; } .fa-ioxhost:before { content: "\f208"; } .fa-angellist:before { content: "\f209"; } .fa-cc:before { content: "\f20a"; } .fa-shekel:before, .fa-sheqel:before, .fa-ils:before { content: "\f20b"; } .fa-meanpath:before { content: "\f20c"; } .fa-buysellads:before { content: "\f20d"; } .fa-connectdevelop:before { content: "\f20e"; } .fa-dashcube:before { content: "\f210"; } .fa-forumbee:before { content: "\f211"; } .fa-leanpub:before { content: "\f212"; } .fa-sellsy:before { content: "\f213"; } .fa-shirtsinbulk:before { content: "\f214"; } .fa-simplybuilt:before { content: "\f215"; } .fa-skyatlas:before { content: "\f216"; } .fa-cart-plus:before { content: "\f217"; } .fa-cart-arrow-down:before { content: "\f218"; } .fa-diamond:before { content: "\f219"; } .fa-ship:before { content: "\f21a"; } .fa-user-secret:before { content: "\f21b"; } .fa-motorcycle:before { content: "\f21c"; } .fa-street-view:before { content: "\f21d"; } .fa-heartbeat:before { content: "\f21e"; } .fa-venus:before { content: "\f221"; } .fa-mars:before { content: "\f222"; } .fa-mercury:before { content: "\f223"; } .fa-intersex:before, .fa-transgender:before { content: "\f224"; } .fa-transgender-alt:before { content: "\f225"; } .fa-venus-double:before { content: "\f226"; } .fa-mars-double:before { content: "\f227"; } .fa-venus-mars:before { content: "\f228"; } .fa-mars-stroke:before { content: "\f229"; } .fa-mars-stroke-v:before { content: "\f22a"; } .fa-mars-stroke-h:before { content: "\f22b"; } .fa-neuter:before { content: "\f22c"; } .fa-genderless:before { content: "\f22d"; } .fa-facebook-official:before { content: "\f230"; } .fa-pinterest-p:before { content: "\f231"; } .fa-whatsapp:before { content: "\f232"; } .fa-server:before { content: "\f233"; } .fa-user-plus:before { content: "\f234"; } .fa-user-times:before { content: "\f235"; } .fa-hotel:before, .fa-bed:before { content: "\f236"; } .fa-viacoin:before { content: "\f237"; } .fa-train:before { content: "\f238"; } .fa-subway:before { content: "\f239"; } .fa-medium:before { content: "\f23a"; } .fa-yc:before, .fa-y-combinator:before { content: "\f23b"; } .fa-optin-monster:before { content: "\f23c"; } .fa-opencart:before { content: "\f23d"; } .fa-expeditedssl:before { content: "\f23e"; } .fa-battery-4:before, .fa-battery:before, .fa-battery-full:before { content: "\f240"; } .fa-battery-3:before, .fa-battery-three-quarters:before { content: "\f241"; } .fa-battery-2:before, .fa-battery-half:before { content: "\f242"; } .fa-battery-1:before, .fa-battery-quarter:before { content: "\f243"; } .fa-battery-0:before, .fa-battery-empty:before { content: "\f244"; } .fa-mouse-pointer:before { content: "\f245"; } .fa-i-cursor:before { content: "\f246"; } .fa-object-group:before { content: "\f247"; } .fa-object-ungroup:before { content: "\f248"; } .fa-sticky-note:before { content: "\f249"; } .fa-sticky-note-o:before { content: "\f24a"; } .fa-cc-jcb:before { content: "\f24b"; } .fa-cc-diners-club:before { content: "\f24c"; } .fa-clone:before { content: "\f24d"; } .fa-balance-scale:before { content: "\f24e"; } .fa-hourglass-o:before { content: "\f250"; } .fa-hourglass-1:before, .fa-hourglass-start:before { content: "\f251"; } .fa-hourglass-2:before, .fa-hourglass-half:before { content: "\f252"; } .fa-hourglass-3:before, .fa-hourglass-end:before { content: "\f253"; } .fa-hourglass:before { content: "\f254"; } .fa-hand-grab-o:before, .fa-hand-rock-o:before { content: "\f255"; } .fa-hand-stop-o:before, .fa-hand-paper-o:before { content: "\f256"; } .fa-hand-scissors-o:before { content: "\f257"; } .fa-hand-lizard-o:before { content: "\f258"; } .fa-hand-spock-o:before { content: "\f259"; } .fa-hand-pointer-o:before { content: "\f25a"; } .fa-hand-peace-o:before { content: "\f25b"; } .fa-trademark:before { content: "\f25c"; } .fa-registered:before { content: "\f25d"; } .fa-creative-commons:before { content: "\f25e"; } .fa-gg:before { content: "\f260"; } .fa-gg-circle:before { content: "\f261"; } .fa-tripadvisor:before { content: "\f262"; } .fa-odnoklassniki:before { content: "\f263"; } .fa-odnoklassniki-square:before { content: "\f264"; } .fa-get-pocket:before { content: "\f265"; } .fa-wikipedia-w:before { content: "\f266"; } .fa-safari:before { content: "\f267"; } .fa-chrome:before { content: "\f268"; } .fa-firefox:before { content: "\f269"; } .fa-opera:before { content: "\f26a"; } .fa-internet-explorer:before { content: "\f26b"; } .fa-tv:before, .fa-television:before { content: "\f26c"; } .fa-contao:before { content: "\f26d"; } .fa-500px:before { content: "\f26e"; } .fa-amazon:before { content: "\f270"; } .fa-calendar-plus-o:before { content: "\f271"; } .fa-calendar-minus-o:before { content: "\f272"; } .fa-calendar-times-o:before { content: "\f273"; } .fa-calendar-check-o:before { content: "\f274"; } .fa-industry:before { content: "\f275"; } .fa-map-pin:before { content: "\f276"; } .fa-map-signs:before { content: "\f277"; } .fa-map-o:before { content: "\f278"; } .fa-map:before { content: "\f279"; } .fa-commenting:before { content: "\f27a"; } .fa-commenting-o:before { content: "\f27b"; } .fa-houzz:before { content: "\f27c"; } .fa-vimeo:before { content: "\f27d"; } .fa-black-tie:before { content: "\f27e"; } .fa-fonticons:before { content: "\f280"; } .fa-reddit-alien:before { content: "\f281"; } .fa-edge:before { content: "\f282"; } .fa-credit-card-alt:before { content: "\f283"; } .fa-codiepie:before { content: "\f284"; } .fa-modx:before { content: "\f285"; } .fa-fort-awesome:before { content: "\f286"; } .fa-usb:before { content: "\f287"; } .fa-product-hunt:before { content: "\f288"; } .fa-mixcloud:before { content: "\f289"; } .fa-scribd:before { content: "\f28a"; } .fa-pause-circle:before { content: "\f28b"; } .fa-pause-circle-o:before { content: "\f28c"; } .fa-stop-circle:before { content: "\f28d"; } .fa-stop-circle-o:before { content: "\f28e"; } .fa-shopping-bag:before { content: "\f290"; } .fa-shopping-basket:before { content: "\f291"; } .fa-hashtag:before { content: "\f292"; } .fa-bluetooth:before { content: "\f293"; } .fa-bluetooth-b:before { content: "\f294"; } .fa-percent:before { content: "\f295"; } .fa-gitlab:before { content: "\f296"; } .fa-wpbeginner:before { content: "\f297"; } .fa-wpforms:before { content: "\f298"; } .fa-envira:before { content: "\f299"; } .fa-universal-access:before { content: "\f29a"; } .fa-wheelchair-alt:before { content: "\f29b"; } .fa-question-circle-o:before { content: "\f29c"; } .fa-blind:before { content: "\f29d"; } .fa-audio-description:before { content: "\f29e"; } .fa-volume-control-phone:before { content: "\f2a0"; } .fa-braille:before { content: "\f2a1"; } .fa-assistive-listening-systems:before { content: "\f2a2"; } .fa-asl-interpreting:before, .fa-american-sign-language-interpreting:before { content: "\f2a3"; } .fa-deafness:before, .fa-hard-of-hearing:before, .fa-deaf:before { content: "\f2a4"; } .fa-glide:before { content: "\f2a5"; } .fa-glide-g:before { content: "\f2a6"; } .fa-signing:before, .fa-sign-language:before { content: "\f2a7"; } .fa-low-vision:before { content: "\f2a8"; } .fa-viadeo:before { content: "\f2a9"; } .fa-viadeo-square:before { content: "\f2aa"; } .fa-snapchat:before { content: "\f2ab"; } .fa-snapchat-ghost:before { content: "\f2ac"; } .fa-snapchat-square:before { content: "\f2ad"; } .fa-pied-piper:before { content: "\f2ae"; } .fa-first-order:before { content: "\f2b0"; } .fa-yoast:before { content: "\f2b1"; } .fa-themeisle:before { content: "\f2b2"; } .fa-google-plus-circle:before, .fa-google-plus-official:before { content: "\f2b3"; } .fa-fa:before, .fa-font-awesome:before { content: "\f2b4"; } .fa-handshake-o:before { content: "\f2b5"; } .fa-envelope-open:before { content: "\f2b6"; } .fa-envelope-open-o:before { content: "\f2b7"; } .fa-linode:before { content: "\f2b8"; } .fa-address-book:before { content: "\f2b9"; } .fa-address-book-o:before { content: "\f2ba"; } .fa-vcard:before, .fa-address-card:before { content: "\f2bb"; } .fa-vcard-o:before, .fa-address-card-o:before { content: "\f2bc"; } .fa-user-circle:before { content: "\f2bd"; } .fa-user-circle-o:before { content: "\f2be"; } .fa-user-o:before { content: "\f2c0"; } .fa-id-badge:before { content: "\f2c1"; } .fa-drivers-license:before, .fa-id-card:before { content: "\f2c2"; } .fa-drivers-license-o:before, .fa-id-card-o:before { content: "\f2c3"; } .fa-quora:before { content: "\f2c4"; } .fa-free-code-camp:before { content: "\f2c5"; } .fa-telegram:before { content: "\f2c6"; } .fa-thermometer-4:before, .fa-thermometer:before, .fa-thermometer-full:before { content: "\f2c7"; } .fa-thermometer-3:before, .fa-thermometer-three-quarters:before { content: "\f2c8"; } .fa-thermometer-2:before, .fa-thermometer-half:before { content: "\f2c9"; } .fa-thermometer-1:before, .fa-thermometer-quarter:before { content: "\f2ca"; } .fa-thermometer-0:before, .fa-thermometer-empty:before { content: "\f2cb"; } .fa-shower:before { content: "\f2cc"; } .fa-bathtub:before, .fa-s15:before, .fa-bath:before { content: "\f2cd"; } .fa-podcast:before { content: "\f2ce"; } .fa-window-maximize:before { content: "\f2d0"; } .fa-window-minimize:before { content: "\f2d1"; } .fa-window-restore:before { content: "\f2d2"; } .fa-times-rectangle:before, .fa-window-close:before { content: "\f2d3"; } .fa-times-rectangle-o:before, .fa-window-close-o:before { content: "\f2d4"; } .fa-bandcamp:before { content: "\f2d5"; } .fa-grav:before { content: "\f2d6"; } .fa-etsy:before { content: "\f2d7"; } .fa-imdb:before { content: "\f2d8"; } .fa-ravelry:before { content: "\f2d9"; } .fa-eercast:before { content: "\f2da"; } .fa-microchip:before { content: "\f2db"; } .fa-snowflake-o:before { content: "\f2dc"; } .fa-superpowers:before { content: "\f2dd"; } .fa-wpexplorer:before { content: "\f2de"; } .fa-meetup:before { content: "\f2e0"; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; } .sr-only-focusable:active, .sr-only-focusable:focus { position: static; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; } .sr-only-focusable:active, .sr-only-focusable:focus { position: static; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; } /*! * * IPython base * */ .modal.fade .modal-dialog { -webkit-transform: translate(0, 0); -ms-transform: translate(0, 0); -o-transform: translate(0, 0); transform: translate(0, 0); } code { color: #000; } pre { font-size: inherit; line-height: inherit; } label { font-weight: normal; } /* Make the page background atleast 100% the height of the view port */ /* Make the page itself atleast 70% the height of the view port */ .border-box-sizing { box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; } .corner-all { border-radius: 2px; } .no-padding { padding: 0px; } /* Flexible box model classes */ /* Taken from Alex Russell http://infrequently.org/2009/08/css-3-progress/ */ /* This file is a compatability layer. It allows the usage of flexible box model layouts accross multiple browsers, including older browsers. The newest, universal implementation of the flexible box model is used when available (see `Modern browsers` comments below). Browsers that are known to implement this new spec completely include: Firefox 28.0+ Chrome 29.0+ Internet Explorer 11+ Opera 17.0+ Browsers not listed, including Safari, are supported via the styling under the `Old browsers` comments below. */ .hbox { /* Old browsers */ display: -webkit-box; -webkit-box-orient: horizontal; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: horizontal; -moz-box-align: stretch; display: box; box-orient: horizontal; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: row; align-items: stretch; } .hbox > * { /* Old browsers */ -webkit-box-flex: 0; -moz-box-flex: 0; box-flex: 0; /* Modern browsers */ flex: none; } .vbox { /* Old browsers */ display: -webkit-box; -webkit-box-orient: vertical; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: vertical; -moz-box-align: stretch; display: box; box-orient: vertical; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: column; align-items: stretch; } .vbox > * { /* Old browsers */ -webkit-box-flex: 0; -moz-box-flex: 0; box-flex: 0; /* Modern browsers */ flex: none; } .hbox.reverse, .vbox.reverse, .reverse { /* Old browsers */ -webkit-box-direction: reverse; -moz-box-direction: reverse; box-direction: reverse; /* Modern browsers */ flex-direction: row-reverse; } .hbox.box-flex0, .vbox.box-flex0, .box-flex0 { /* Old browsers */ -webkit-box-flex: 0; -moz-box-flex: 0; box-flex: 0; /* Modern browsers */ flex: none; width: auto; } .hbox.box-flex1, .vbox.box-flex1, .box-flex1 { /* Old browsers */ -webkit-box-flex: 1; -moz-box-flex: 1; box-flex: 1; /* Modern browsers */ flex: 1; } .hbox.box-flex, .vbox.box-flex, .box-flex { /* Old browsers */ /* Old browsers */ -webkit-box-flex: 1; -moz-box-flex: 1; box-flex: 1; /* Modern browsers */ flex: 1; } .hbox.box-flex2, .vbox.box-flex2, .box-flex2 { /* Old browsers */ -webkit-box-flex: 2; -moz-box-flex: 2; box-flex: 2; /* Modern browsers */ flex: 2; } .box-group1 { /* Deprecated */ -webkit-box-flex-group: 1; -moz-box-flex-group: 1; box-flex-group: 1; } .box-group2 { /* Deprecated */ -webkit-box-flex-group: 2; -moz-box-flex-group: 2; box-flex-group: 2; } .hbox.start, .vbox.start, .start { /* Old browsers */ -webkit-box-pack: start; -moz-box-pack: start; box-pack: start; /* Modern browsers */ justify-content: flex-start; } .hbox.end, .vbox.end, .end { /* Old browsers */ -webkit-box-pack: end; -moz-box-pack: end; box-pack: end; /* Modern browsers */ justify-content: flex-end; } .hbox.center, .vbox.center, .center { /* Old browsers */ -webkit-box-pack: center; -moz-box-pack: center; box-pack: center; /* Modern browsers */ justify-content: center; } .hbox.baseline, .vbox.baseline, .baseline { /* Old browsers */ -webkit-box-pack: baseline; -moz-box-pack: baseline; box-pack: baseline; /* Modern browsers */ justify-content: baseline; } .hbox.stretch, .vbox.stretch, .stretch { /* Old browsers */ -webkit-box-pack: stretch; -moz-box-pack: stretch; box-pack: stretch; /* Modern browsers */ justify-content: stretch; } .hbox.align-start, .vbox.align-start, .align-start { /* Old browsers */ -webkit-box-align: start; -moz-box-align: start; box-align: start; /* Modern browsers */ align-items: flex-start; } .hbox.align-end, .vbox.align-end, .align-end { /* Old browsers */ -webkit-box-align: end; -moz-box-align: end; box-align: end; /* Modern browsers */ align-items: flex-end; } .hbox.align-center, .vbox.align-center, .align-center { /* Old browsers */ -webkit-box-align: center; -moz-box-align: center; box-align: center; /* Modern browsers */ align-items: center; } .hbox.align-baseline, .vbox.align-baseline, .align-baseline { /* Old browsers */ -webkit-box-align: baseline; -moz-box-align: baseline; box-align: baseline; /* Modern browsers */ align-items: baseline; } .hbox.align-stretch, .vbox.align-stretch, .align-stretch { /* Old browsers */ -webkit-box-align: stretch; -moz-box-align: stretch; box-align: stretch; /* Modern browsers */ align-items: stretch; } div.error { margin: 2em; text-align: center; } div.error > h1 { font-size: 500%; line-height: normal; } div.error > p { font-size: 200%; line-height: normal; } div.traceback-wrapper { text-align: left; max-width: 800px; margin: auto; } div.traceback-wrapper pre.traceback { max-height: 600px; overflow: auto; } /** * Primary styles * * Author: Jupyter Development Team */ body { background-color: #fff; /* This makes sure that the body covers the entire window and needs to be in a different element than the display: box in wrapper below */ position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; overflow: visible; } body > #header { /* Initially hidden to prevent FLOUC */ display: none; background-color: #fff; /* Display over codemirror */ position: relative; z-index: 100; } body > #header #header-container { display: flex; flex-direction: row; justify-content: space-between; padding: 5px; padding-bottom: 5px; padding-top: 5px; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; } body > #header .header-bar { width: 100%; height: 1px; background: #e7e7e7; margin-bottom: -1px; } @media print { body > #header { display: none !important; } } #header-spacer { width: 100%; visibility: hidden; } @media print { #header-spacer { display: none; } } #ipython_notebook { padding-left: 0px; padding-top: 1px; padding-bottom: 1px; } [dir="rtl"] #ipython_notebook { margin-right: 10px; margin-left: 0; } [dir="rtl"] #ipython_notebook.pull-left { float: right !important; float: right; } .flex-spacer { flex: 1; } #noscript { width: auto; padding-top: 16px; padding-bottom: 16px; text-align: center; font-size: 22px; color: red; font-weight: bold; } #ipython_notebook img { height: 28px; } #site { width: 100%; display: none; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; overflow: auto; } @media print { #site { height: auto !important; } } /* Smaller buttons */ .ui-button .ui-button-text { padding: 0.2em 0.8em; font-size: 77%; } input.ui-button { padding: 0.3em 0.9em; } span#kernel_logo_widget { margin: 0 10px; } span#login_widget { float: right; } [dir="rtl"] span#login_widget { float: left; } span#login_widget > .button, #logout { color: #333; background-color: #fff; border-color: #ccc; } span#login_widget > .button:focus, #logout:focus, span#login_widget > .button.focus, #logout.focus { color: #333; background-color: #e6e6e6; border-color: #8c8c8c; } span#login_widget > .button:hover, #logout:hover { color: #333; background-color: #e6e6e6; border-color: #adadad; } span#login_widget > .button:active, #logout:active, span#login_widget > .button.active, #logout.active, .open > .dropdown-togglespan#login_widget > .button, .open > .dropdown-toggle#logout { color: #333; background-color: #e6e6e6; border-color: #adadad; } span#login_widget > .button:active:hover, #logout:active:hover, span#login_widget > .button.active:hover, #logout.active:hover, .open > .dropdown-togglespan#login_widget > .button:hover, .open > .dropdown-toggle#logout:hover, span#login_widget > .button:active:focus, #logout:active:focus, span#login_widget > .button.active:focus, #logout.active:focus, .open > .dropdown-togglespan#login_widget > .button:focus, .open > .dropdown-toggle#logout:focus, span#login_widget > .button:active.focus, #logout:active.focus, span#login_widget > .button.active.focus, #logout.active.focus, .open > .dropdown-togglespan#login_widget > .button.focus, .open > .dropdown-toggle#logout.focus { color: #333; background-color: #d4d4d4; border-color: #8c8c8c; } span#login_widget > .button:active, #logout:active, span#login_widget > .button.active, #logout.active, .open > .dropdown-togglespan#login_widget > .button, .open > .dropdown-toggle#logout { background-image: none; } span#login_widget > .button.disabled:hover, #logout.disabled:hover, span#login_widget > .button[disabled]:hover, #logout[disabled]:hover, fieldset[disabled] span#login_widget > .button:hover, fieldset[disabled] #logout:hover, span#login_widget > .button.disabled:focus, #logout.disabled:focus, span#login_widget > .button[disabled]:focus, #logout[disabled]:focus, fieldset[disabled] span#login_widget > .button:focus, fieldset[disabled] #logout:focus, span#login_widget > .button.disabled.focus, #logout.disabled.focus, span#login_widget > .button[disabled].focus, #logout[disabled].focus, fieldset[disabled] span#login_widget > .button.focus, fieldset[disabled] #logout.focus { background-color: #fff; border-color: #ccc; } span#login_widget > .button .badge, #logout .badge { color: #fff; background-color: #333; } .nav-header { text-transform: none; } #header > span { margin-top: 10px; } .modal_stretch .modal-dialog { /* Old browsers */ display: -webkit-box; -webkit-box-orient: vertical; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: vertical; -moz-box-align: stretch; display: box; box-orient: vertical; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: column; align-items: stretch; min-height: 80vh; } .modal_stretch .modal-dialog .modal-body { max-height: calc(100vh - 200px); overflow: auto; flex: 1; } .modal-header { cursor: move; } @media (min-width: 768px) { .modal .modal-dialog { width: 700px; } } @media (min-width: 768px) { select.form-control { margin-left: 12px; margin-right: 12px; } } /*! * * IPython auth * */ .center-nav { display: inline-block; margin-bottom: -4px; } [dir="rtl"] .center-nav form.pull-left { float: right !important; float: right; } [dir="rtl"] .center-nav .navbar-text { float: right; } [dir="rtl"] .navbar-inner { text-align: right; } [dir="rtl"] div.text-left { text-align: right; } /*! * * IPython tree view * */ /* We need an invisible input field on top of the sentense*/ /* "Drag file onto the list ..." */ .alternate_upload { background-color: none; display: inline; } .alternate_upload.form { padding: 0; margin: 0; } .alternate_upload input.fileinput { position: absolute; display: block; width: 100%; height: 100%; overflow: hidden; cursor: pointer; opacity: 0; z-index: 2; } .alternate_upload .btn-xs > input.fileinput { margin: -1px -5px; } .alternate_upload .btn-upload { position: relative; height: 22px; } ::-webkit-file-upload-button { cursor: pointer; } /** * Primary styles * * Author: Jupyter Development Team */ ul#tabs { margin-bottom: 4px; } ul#tabs a { padding-top: 6px; padding-bottom: 4px; } [dir="rtl"] ul#tabs.nav-tabs > li { float: right; } [dir="rtl"] ul#tabs.nav.nav-tabs { padding-right: 0; } ul.breadcrumb a:focus, ul.breadcrumb a:hover { text-decoration: none; } ul.breadcrumb i.icon-home { font-size: 16px; margin-right: 4px; } ul.breadcrumb span { color: #5e5e5e; } .list_toolbar { padding: 4px 0 4px 0; vertical-align: middle; } .list_toolbar .tree-buttons { padding-top: 1px; } [dir="rtl"] .list_toolbar .tree-buttons .pull-right { float: left !important; float: left; } [dir="rtl"] .list_toolbar .col-sm-4, [dir="rtl"] .list_toolbar .col-sm-8 { float: right; } .dynamic-buttons { padding-top: 3px; display: inline-block; } .list_toolbar [class*="span"] { min-height: 24px; } .list_header { font-weight: bold; background-color: #eee; } .list_placeholder { font-weight: bold; padding-top: 4px; padding-bottom: 4px; padding-left: 7px; padding-right: 7px; } .list_container { margin-top: 4px; margin-bottom: 20px; border: 1px solid #ddd; border-radius: 2px; } .list_container > div { border-bottom: 1px solid #ddd; } .list_container > div:hover .list-item { background-color: red; } .list_container > div:last-child { border: none; } .list_item:hover .list_item { background-color: #ddd; } .list_item a { text-decoration: none; } .list_item:hover { background-color: #fafafa; } .list_header > div, .list_item > div { padding-top: 4px; padding-bottom: 4px; padding-left: 7px; padding-right: 7px; line-height: 22px; } .list_header > div input, .list_item > div input { margin-right: 7px; margin-left: 14px; vertical-align: text-bottom; line-height: 22px; position: relative; top: -1px; } .list_header > div .item_link, .list_item > div .item_link { margin-left: -1px; vertical-align: baseline; line-height: 22px; } [dir="rtl"] .list_item > div input { margin-right: 0; } .new-file input[type="checkbox"] { visibility: hidden; } .item_name { line-height: 22px; height: 24px; } .item_icon { font-size: 14px; color: #5e5e5e; margin-right: 7px; margin-left: 7px; line-height: 22px; vertical-align: baseline; } .item_modified { margin-right: 7px; margin-left: 7px; } [dir="rtl"] .item_modified.pull-right { float: left !important; float: left; } .item_buttons { line-height: 1em; margin-left: -5px; } .item_buttons .btn, .item_buttons .btn-group, .item_buttons .input-group { float: left; } .item_buttons > .btn, .item_buttons > .btn-group, .item_buttons > .input-group { margin-left: 5px; } .item_buttons .btn { min-width: 13ex; } .item_buttons .running-indicator { padding-top: 4px; color: #5cb85c; } .item_buttons .kernel-name { padding-top: 4px; color: #5bc0de; margin-right: 7px; float: left; } [dir="rtl"] .item_buttons.pull-right { float: left !important; float: left; } [dir="rtl"] .item_buttons .kernel-name { margin-left: 7px; float: right; } .toolbar_info { height: 24px; line-height: 24px; } .list_item input:not([type="checkbox"]) { padding-top: 3px; padding-bottom: 3px; height: 22px; line-height: 14px; margin: 0px; } .highlight_text { color: blue; } #project_name { display: inline-block; padding-left: 7px; margin-left: -2px; } #project_name > .breadcrumb { padding: 0px; margin-bottom: 0px; background-color: transparent; font-weight: bold; } .sort_button { display: inline-block; padding-left: 7px; } [dir="rtl"] .sort_button.pull-right { float: left !important; float: left; } #tree-selector { padding-right: 0px; } #button-select-all { min-width: 50px; } [dir="rtl"] #button-select-all.btn { float: right; } #select-all { margin-left: 7px; margin-right: 2px; margin-top: 2px; height: 16px; } [dir="rtl"] #select-all.pull-left { float: right !important; float: right; } .menu_icon { margin-right: 2px; } .tab-content .row { margin-left: 0px; margin-right: 0px; } .folder_icon:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: "\f114"; } .folder_icon:before.fa-pull-left { margin-right: 0.3em; } .folder_icon:before.fa-pull-right { margin-left: 0.3em; } .folder_icon:before.pull-left { margin-right: 0.3em; } .folder_icon:before.pull-right { margin-left: 0.3em; } .notebook_icon:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: "\f02d"; position: relative; top: -1px; } .notebook_icon:before.fa-pull-left { margin-right: 0.3em; } .notebook_icon:before.fa-pull-right { margin-left: 0.3em; } .notebook_icon:before.pull-left { margin-right: 0.3em; } .notebook_icon:before.pull-right { margin-left: 0.3em; } .running_notebook_icon:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: "\f02d"; position: relative; top: -1px; color: #5cb85c; } .running_notebook_icon:before.fa-pull-left { margin-right: 0.3em; } .running_notebook_icon:before.fa-pull-right { margin-left: 0.3em; } .running_notebook_icon:before.pull-left { margin-right: 0.3em; } .running_notebook_icon:before.pull-right { margin-left: 0.3em; } .file_icon:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: "\f016"; position: relative; top: -2px; } .file_icon:before.fa-pull-left { margin-right: 0.3em; } .file_icon:before.fa-pull-right { margin-left: 0.3em; } .file_icon:before.pull-left { margin-right: 0.3em; } .file_icon:before.pull-right { margin-left: 0.3em; } #notebook_toolbar .pull-right { padding-top: 0px; margin-right: -1px; } ul#new-menu { left: auto; right: 0; } #new-menu .dropdown-header { font-size: 10px; border-bottom: 1px solid #e5e5e5; padding: 0 0 3px; margin: -3px 20px 0; } .kernel-menu-icon { padding-right: 12px; width: 24px; content: "\f096"; } .kernel-menu-icon:before { content: "\f096"; } .kernel-menu-icon-current:before { content: "\f00c"; } #tab_content { padding-top: 20px; } #running .panel-group .panel { margin-top: 3px; margin-bottom: 1em; } #running .panel-group .panel .panel-heading { background-color: #eee; padding-top: 4px; padding-bottom: 4px; padding-left: 7px; padding-right: 7px; line-height: 22px; } #running .panel-group .panel .panel-heading a:focus, #running .panel-group .panel .panel-heading a:hover { text-decoration: none; } #running .panel-group .panel .panel-body { padding: 0px; } #running .panel-group .panel .panel-body .list_container { margin-top: 0px; margin-bottom: 0px; border: 0px; border-radius: 0px; } #running .panel-group .panel .panel-body .list_container .list_item { border-bottom: 1px solid #ddd; } #running .panel-group .panel .panel-body .list_container .list_item:last-child { border-bottom: 0px; } .delete-button { display: none; } .duplicate-button { display: none; } .rename-button { display: none; } .move-button { display: none; } .download-button { display: none; } .shutdown-button { display: none; } .dynamic-instructions { display: inline-block; padding-top: 4px; } /*! * * IPython text editor webapp * */ .selected-keymap i.fa { padding: 0px 5px; } .selected-keymap i.fa:before { content: "\f00c"; } #mode-menu { overflow: auto; max-height: 20em; } .edit_app #header { -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); } .edit_app #menubar .navbar { /* Use a negative 1 bottom margin, so the border overlaps the border of the header */ margin-bottom: -1px; } .dirty-indicator { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; width: 20px; } .dirty-indicator.fa-pull-left { margin-right: 0.3em; } .dirty-indicator.fa-pull-right { margin-left: 0.3em; } .dirty-indicator.pull-left { margin-right: 0.3em; } .dirty-indicator.pull-right { margin-left: 0.3em; } .dirty-indicator-dirty { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; width: 20px; } .dirty-indicator-dirty.fa-pull-left { margin-right: 0.3em; } .dirty-indicator-dirty.fa-pull-right { margin-left: 0.3em; } .dirty-indicator-dirty.pull-left { margin-right: 0.3em; } .dirty-indicator-dirty.pull-right { margin-left: 0.3em; } .dirty-indicator-clean { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; width: 20px; } .dirty-indicator-clean.fa-pull-left { margin-right: 0.3em; } .dirty-indicator-clean.fa-pull-right { margin-left: 0.3em; } .dirty-indicator-clean.pull-left { margin-right: 0.3em; } .dirty-indicator-clean.pull-right { margin-left: 0.3em; } .dirty-indicator-clean:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: "\f00c"; } .dirty-indicator-clean:before.fa-pull-left { margin-right: 0.3em; } .dirty-indicator-clean:before.fa-pull-right { margin-left: 0.3em; } .dirty-indicator-clean:before.pull-left { margin-right: 0.3em; } .dirty-indicator-clean:before.pull-right { margin-left: 0.3em; } #filename { font-size: 16pt; display: table; padding: 0px 5px; } #current-mode { padding-left: 5px; padding-right: 5px; } #texteditor-backdrop { padding-top: 20px; padding-bottom: 20px; } @media not print { #texteditor-backdrop { background-color: #eee; } } @media print { #texteditor-backdrop #texteditor-container .CodeMirror-gutter, #texteditor-backdrop #texteditor-container .CodeMirror-gutters { background-color: #fff; } } @media not print { #texteditor-backdrop #texteditor-container .CodeMirror-gutter, #texteditor-backdrop #texteditor-container .CodeMirror-gutters { background-color: #fff; } } @media not print { #texteditor-backdrop #texteditor-container { padding: 0px; background-color: #fff; -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); } } .CodeMirror-dialog { background-color: #fff; } /*! * * IPython notebook * */ /* CSS font colors for translated ANSI escape sequences */ /* The color values are a mix of http://www.xcolors.net/dl/baskerville-ivorylight and http://www.xcolors.net/dl/euphrasia */ .ansi-black-fg { color: #3e424d; } .ansi-black-bg { background-color: #3e424d; } .ansi-black-intense-fg { color: #282c36; } .ansi-black-intense-bg { background-color: #282c36; } .ansi-red-fg { color: #e75c58; } .ansi-red-bg { background-color: #e75c58; } .ansi-red-intense-fg { color: #b22b31; } .ansi-red-intense-bg { background-color: #b22b31; } .ansi-green-fg { color: #00a250; } .ansi-green-bg { background-color: #00a250; } .ansi-green-intense-fg { color: #007427; } .ansi-green-intense-bg { background-color: #007427; } .ansi-yellow-fg { color: #ddb62b; } .ansi-yellow-bg { background-color: #ddb62b; } .ansi-yellow-intense-fg { color: #b27d12; } .ansi-yellow-intense-bg { background-color: #b27d12; } .ansi-blue-fg { color: #208ffb; } .ansi-blue-bg { background-color: #208ffb; } .ansi-blue-intense-fg { color: #0065ca; } .ansi-blue-intense-bg { background-color: #0065ca; } .ansi-magenta-fg { color: #d160c4; } .ansi-magenta-bg { background-color: #d160c4; } .ansi-magenta-intense-fg { color: #a03196; } .ansi-magenta-intense-bg { background-color: #a03196; } .ansi-cyan-fg { color: #60c6c8; } .ansi-cyan-bg { background-color: #60c6c8; } .ansi-cyan-intense-fg { color: #258f8f; } .ansi-cyan-intense-bg { background-color: #258f8f; } .ansi-white-fg { color: #c5c1b4; } .ansi-white-bg { background-color: #c5c1b4; } .ansi-white-intense-fg { color: #a1a6b2; } .ansi-white-intense-bg { background-color: #a1a6b2; } .ansi-default-inverse-fg { color: #ffffff; } .ansi-default-inverse-bg { background-color: #000000; } .ansi-bold { font-weight: bold; } .ansi-underline { text-decoration: underline; } /* The following styles are deprecated an will be removed in a future version */ .ansibold { font-weight: bold; } .ansi-inverse { outline: 0.5px dotted; } /* use dark versions for foreground, to improve visibility */ .ansiblack { color: black; } .ansired { color: darkred; } .ansigreen { color: darkgreen; } .ansiyellow { color: #c4a000; } .ansiblue { color: darkblue; } .ansipurple { color: darkviolet; } .ansicyan { color: steelblue; } .ansigray { color: gray; } /* and light for background, for the same reason */ .ansibgblack { background-color: black; } .ansibgred { background-color: red; } .ansibggreen { background-color: green; } .ansibgyellow { background-color: yellow; } .ansibgblue { background-color: blue; } .ansibgpurple { background-color: magenta; } .ansibgcyan { background-color: cyan; } .ansibggray { background-color: gray; } div.cell { /* Old browsers */ display: -webkit-box; -webkit-box-orient: vertical; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: vertical; -moz-box-align: stretch; display: box; box-orient: vertical; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: column; align-items: stretch; border-radius: 2px; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; border-width: 1px; border-style: solid; border-color: transparent; width: 100%; padding: 5px; /* This acts as a spacer between cells, that is outside the border */ margin: 0px; outline: none; position: relative; overflow: visible; } div.cell:before { position: absolute; display: block; top: -1px; left: -1px; width: 5px; height: calc(100% + 2px); content: ""; background: transparent; } div.cell.jupyter-soft-selected { border-left-color: #e3f2fd; border-left-width: 1px; padding-left: 5px; border-right-color: #e3f2fd; border-right-width: 1px; background: #e3f2fd; } @media print { div.cell.jupyter-soft-selected { border-color: transparent; } } div.cell.selected, div.cell.selected.jupyter-soft-selected { border-color: #ababab; } div.cell.selected:before, div.cell.selected.jupyter-soft-selected:before { position: absolute; display: block; top: -1px; left: -1px; width: 5px; height: calc(100% + 2px); content: ""; background: #42a5f5; } @media print { div.cell.selected, div.cell.selected.jupyter-soft-selected { border-color: transparent; } } .edit_mode div.cell.selected { border-color: #66bb6a; } .edit_mode div.cell.selected:before { position: absolute; display: block; top: -1px; left: -1px; width: 5px; height: calc(100% + 2px); content: ""; background: #66bb6a; } @media print { .edit_mode div.cell.selected { border-color: transparent; } } .prompt { /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */ min-width: 14ex; /* This padding is tuned to match the padding on the CodeMirror editor. */ padding: 0.4em; margin: 0px; font-family: monospace; text-align: right; /* This has to match that of the the CodeMirror class line-height below */ line-height: 1.21429em; /* Don't highlight prompt number selection */ -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; /* Use default cursor */ cursor: default; } @media (max-width: 540px) { .prompt { text-align: left; } } div.inner_cell { min-width: 0; /* Old browsers */ display: -webkit-box; -webkit-box-orient: vertical; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: vertical; -moz-box-align: stretch; display: box; box-orient: vertical; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: column; align-items: stretch; /* Old browsers */ -webkit-box-flex: 1; -moz-box-flex: 1; box-flex: 1; /* Modern browsers */ flex: 1; } /* input_area and input_prompt must match in top border and margin for alignment */ div.input_area { border: 1px solid #cfcfcf; border-radius: 2px; background: #f7f7f7; line-height: 1.21429em; } /* This is needed so that empty prompt areas can collapse to zero height when there is no content in the output_subarea and the prompt. The main purpose of this is to make sure that empty JavaScript output_subareas have no height. */ div.prompt:empty { padding-top: 0; padding-bottom: 0; } div.unrecognized_cell { padding: 5px 5px 5px 0px; /* Old browsers */ display: -webkit-box; -webkit-box-orient: horizontal; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: horizontal; -moz-box-align: stretch; display: box; box-orient: horizontal; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: row; align-items: stretch; } div.unrecognized_cell .inner_cell { border-radius: 2px; padding: 5px; font-weight: bold; color: red; border: 1px solid #cfcfcf; background: #eaeaea; } div.unrecognized_cell .inner_cell a { color: inherit; text-decoration: none; } div.unrecognized_cell .inner_cell a:hover { color: inherit; text-decoration: none; } @media (max-width: 540px) { div.unrecognized_cell > div.prompt { display: none; } } div.code_cell { /* avoid page breaking on code cells when printing */ } @media print { div.code_cell { page-break-inside: avoid; } } /* any special styling for code cells that are currently running goes here */ div.input { page-break-inside: avoid; /* Old browsers */ display: -webkit-box; -webkit-box-orient: horizontal; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: horizontal; -moz-box-align: stretch; display: box; box-orient: horizontal; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: row; align-items: stretch; } @media (max-width: 540px) { div.input { /* Old browsers */ display: -webkit-box; -webkit-box-orient: vertical; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: vertical; -moz-box-align: stretch; display: box; box-orient: vertical; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: column; align-items: stretch; } } /* input_area and input_prompt must match in top border and margin for alignment */ div.input_prompt { color: #303f9f; border-top: 1px solid transparent; } div.input_area > div.highlight { margin: 0.4em; border: none; padding: 0px; background-color: transparent; } div.input_area > div.highlight > pre { margin: 0px; border: none; padding: 0px; background-color: transparent; } /* The following gets added to the if it is detected that the user has a * monospace font with inconsistent normal/bold/italic height. See * notebookmain.js. Such fonts will have keywords vertically offset with * respect to the rest of the text. The user should select a better font. * See: https://github.com/ipython/ipython/issues/1503 * * .CodeMirror span { * vertical-align: bottom; * } */ .CodeMirror { line-height: 1.21429em; /* Changed from 1em to our global default */ font-size: 14px; height: auto; /* Changed to auto to autogrow */ background: none; /* Changed from white to allow our bg to show through */ } .CodeMirror-scroll { /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/ /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/ overflow-y: hidden; overflow-x: auto; } .CodeMirror-lines { /* In CM2, this used to be 0.4em, but in CM3 it went to 4px. We need the em value because */ /* we have set a different line-height and want this to scale with that. */ /* Note that this should set vertical padding only, since CodeMirror assumes that horizontal padding will be set on CodeMirror pre */ padding: 0.4em 0; } .CodeMirror-linenumber { padding: 0 8px 0 4px; } .CodeMirror-gutters { border-bottom-left-radius: 2px; border-top-left-radius: 2px; } .CodeMirror pre { /* In CM3 this went to 4px from 0 in CM2. This sets horizontal padding only, use .CodeMirror-lines for vertical */ padding: 0 0.4em; border: 0; border-radius: 0; } .CodeMirror-cursor { border-left: 1.4px solid black; } @media screen and (min-width: 2138px) and (max-width: 4319px) { .CodeMirror-cursor { border-left: 2px solid black; } } @media screen and (min-width: 4320px) { .CodeMirror-cursor { border-left: 4px solid black; } } /* Original style from softwaremaniacs.org (c) Ivan Sagalaev Adapted from GitHub theme */ .highlight-base { color: #000; } .highlight-variable { color: #000; } .highlight-variable-2 { color: #1a1a1a; } .highlight-variable-3 { color: #333333; } .highlight-string { color: #ba2121; } .highlight-comment { color: #408080; font-style: italic; } .highlight-number { color: #080; } .highlight-atom { color: #88f; } .highlight-keyword { color: #008000; font-weight: bold; } .highlight-builtin { color: #008000; } .highlight-error { color: #f00; } .highlight-operator { color: #aa22ff; font-weight: bold; } .highlight-meta { color: #aa22ff; } /* previously not defined, copying from default codemirror */ .highlight-def { color: #00f; } .highlight-string-2 { color: #f50; } .highlight-qualifier { color: #555; } .highlight-bracket { color: #997; } .highlight-tag { color: #170; } .highlight-attribute { color: #00c; } .highlight-header { color: blue; } .highlight-quote { color: #090; } .highlight-link { color: #00c; } /* apply the same style to codemirror */ .cm-s-ipython span.cm-keyword { color: #008000; font-weight: bold; } .cm-s-ipython span.cm-atom { color: #88f; } .cm-s-ipython span.cm-number { color: #080; } .cm-s-ipython span.cm-def { color: #00f; } .cm-s-ipython span.cm-variable { color: #000; } .cm-s-ipython span.cm-operator { color: #aa22ff; font-weight: bold; } .cm-s-ipython span.cm-variable-2 { color: #1a1a1a; } .cm-s-ipython span.cm-variable-3 { color: #333333; } .cm-s-ipython span.cm-comment { color: #408080; font-style: italic; } .cm-s-ipython span.cm-string { color: #ba2121; } .cm-s-ipython span.cm-string-2 { color: #f50; } .cm-s-ipython span.cm-meta { color: #aa22ff; } .cm-s-ipython span.cm-qualifier { color: #555; } .cm-s-ipython span.cm-builtin { color: #008000; } .cm-s-ipython span.cm-bracket { color: #997; } .cm-s-ipython span.cm-tag { color: #170; } .cm-s-ipython span.cm-attribute { color: #00c; } .cm-s-ipython span.cm-header { color: blue; } .cm-s-ipython span.cm-quote { color: #090; } .cm-s-ipython span.cm-link { color: #00c; } .cm-s-ipython span.cm-error { color: #f00; } .cm-s-ipython span.cm-tab { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=); background-position: right; background-repeat: no-repeat; } div.output_wrapper { /* this position must be relative to enable descendents to be absolute within it */ position: relative; /* Old browsers */ display: -webkit-box; -webkit-box-orient: vertical; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: vertical; -moz-box-align: stretch; display: box; box-orient: vertical; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: column; align-items: stretch; z-index: 1; } /* class for the output area when it should be height-limited */ div.output_scroll { /* ideally, this would be max-height, but FF barfs all over that */ height: 24em; /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */ width: 100%; overflow: auto; border-radius: 2px; -webkit-box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8); box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8); display: block; } /* output div while it is collapsed */ div.output_collapsed { margin: 0px; padding: 0px; /* Old browsers */ display: -webkit-box; -webkit-box-orient: vertical; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: vertical; -moz-box-align: stretch; display: box; box-orient: vertical; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: column; align-items: stretch; } div.out_prompt_overlay { height: 100%; padding: 0px 0.4em; position: absolute; border-radius: 2px; } div.out_prompt_overlay:hover { /* use inner shadow to get border that is computed the same on WebKit/FF */ -webkit-box-shadow: inset 0 0 1px #000; box-shadow: inset 0 0 1px #000; background: rgba(240, 240, 240, 0.5); } div.output_prompt { color: #d84315; } /* This class is the outer container of all output sections. */ div.output_area { padding: 0px; page-break-inside: avoid; /* Old browsers */ display: -webkit-box; -webkit-box-orient: horizontal; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: horizontal; -moz-box-align: stretch; display: box; box-orient: horizontal; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: row; align-items: stretch; } div.output_area .MathJax_Display { text-align: left !important; } div.output_area .rendered_html table { margin-left: 0; margin-right: 0; } div.output_area .rendered_html img { margin-left: 0; margin-right: 0; } div.output_area img, div.output_area svg { max-width: 100%; height: auto; } div.output_area img.unconfined, div.output_area svg.unconfined { max-width: none; } div.output_area .mglyph > img { max-width: none; } /* This is needed to protect the pre formating from global settings such as that of bootstrap */ .output { /* Old browsers */ display: -webkit-box; -webkit-box-orient: vertical; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: vertical; -moz-box-align: stretch; display: box; box-orient: vertical; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: column; align-items: stretch; } @media (max-width: 540px) { div.output_area { /* Old browsers */ display: -webkit-box; -webkit-box-orient: vertical; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: vertical; -moz-box-align: stretch; display: box; box-orient: vertical; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: column; align-items: stretch; } } div.output_area pre { margin: 0; padding: 1px 0 1px 0; border: 0; vertical-align: baseline; color: black; background-color: transparent; border-radius: 0; } /* This class is for the output subarea inside the output_area and after the prompt div. */ div.output_subarea { overflow-x: auto; padding: 0.4em; /* Old browsers */ -webkit-box-flex: 1; -moz-box-flex: 1; box-flex: 1; /* Modern browsers */ flex: 1; max-width: calc(100% - 14ex); } div.output_scroll div.output_subarea { overflow-x: visible; } /* The rest of the output_* classes are for special styling of the different output types */ /* all text output has this class: */ div.output_text { text-align: left; color: #000; /* This has to match that of the the CodeMirror class line-height below */ line-height: 1.21429em; } /* stdout/stderr are 'text' as well as 'stream', but execute_result/error are *not* streams */ div.output_stderr { background: #fdd; /* very light red background for stderr */ } div.output_latex { text-align: left; } /* Empty output_javascript divs should have no height */ div.output_javascript:empty { padding: 0; } .js-error { color: darkred; } /* raw_input styles */ div.raw_input_container { line-height: 1.21429em; padding-top: 5px; } pre.raw_input_prompt { /* nothing needed here. */ } input.raw_input { font-family: monospace; font-size: inherit; color: inherit; width: auto; /* make sure input baseline aligns with prompt */ vertical-align: baseline; /* padding + margin = 0.5em between prompt and cursor */ padding: 0em 0.25em; margin: 0em 0.25em; } input.raw_input:focus { box-shadow: none; } p.p-space { margin-bottom: 10px; } div.output_unrecognized { padding: 5px; font-weight: bold; color: red; } div.output_unrecognized a { color: inherit; text-decoration: none; } div.output_unrecognized a:hover { color: inherit; text-decoration: none; } .rendered_html { color: #000; /* any extras will just be numbers: */ } .rendered_html em { font-style: italic; } .rendered_html strong { font-weight: bold; } .rendered_html u { text-decoration: underline; } .rendered_html :link { text-decoration: underline; } .rendered_html :visited { text-decoration: underline; } .rendered_html h1 { font-size: 185.7%; margin: 1.08em 0 0 0; font-weight: bold; line-height: 1; } .rendered_html h2 { font-size: 157.1%; margin: 1.27em 0 0 0; font-weight: bold; line-height: 1; } .rendered_html h3 { font-size: 128.6%; margin: 1.55em 0 0 0; font-weight: bold; line-height: 1; } .rendered_html h4 { font-size: 100%; margin: 2em 0 0 0; font-weight: bold; line-height: 1; } .rendered_html h5 { font-size: 100%; margin: 2em 0 0 0; font-weight: bold; line-height: 1; font-style: italic; } .rendered_html h6 { font-size: 100%; margin: 2em 0 0 0; font-weight: bold; line-height: 1; font-style: italic; } .rendered_html h1:first-child { margin-top: 0.538em; } .rendered_html h2:first-child { margin-top: 0.636em; } .rendered_html h3:first-child { margin-top: 0.777em; } .rendered_html h4:first-child { margin-top: 1em; } .rendered_html h5:first-child { margin-top: 1em; } .rendered_html h6:first-child { margin-top: 1em; } .rendered_html ul:not(.list-inline), .rendered_html ol:not(.list-inline) { padding-left: 2em; } .rendered_html ul { list-style: disc; } .rendered_html ul ul { list-style: square; margin-top: 0; } .rendered_html ul ul ul { list-style: circle; } .rendered_html ol { list-style: decimal; } .rendered_html ol ol { list-style: upper-alpha; margin-top: 0; } .rendered_html ol ol ol { list-style: lower-alpha; } .rendered_html ol ol ol ol { list-style: lower-roman; } .rendered_html ol ol ol ol ol { list-style: decimal; } .rendered_html * + ul { margin-top: 1em; } .rendered_html * + ol { margin-top: 1em; } .rendered_html hr { color: black; background-color: black; } .rendered_html pre { margin: 1em 2em; padding: 0px; background-color: #fff; } .rendered_html code { background-color: #eff0f1; } .rendered_html p code { padding: 1px 5px; } .rendered_html pre code { background-color: #fff; } .rendered_html pre, .rendered_html code { border: 0; color: #000; font-size: 100%; } .rendered_html blockquote { margin: 1em 2em; } .rendered_html table { margin-left: auto; margin-right: auto; border: none; border-collapse: collapse; border-spacing: 0; color: black; font-size: 12px; table-layout: fixed; } .rendered_html thead { border-bottom: 1px solid black; vertical-align: bottom; } .rendered_html tr, .rendered_html th, .rendered_html td { text-align: right; vertical-align: middle; padding: 0.5em 0.5em; line-height: normal; white-space: normal; max-width: none; border: none; } .rendered_html th { font-weight: bold; } .rendered_html tbody tr:nth-child(odd) { background: #f5f5f5; } .rendered_html tbody tr:hover { background: rgba(66, 165, 245, 0.2); } .rendered_html * + table { margin-top: 1em; } .rendered_html p { text-align: left; } .rendered_html * + p { margin-top: 1em; } .rendered_html img { display: block; margin-left: auto; margin-right: auto; } .rendered_html * + img { margin-top: 1em; } .rendered_html img, .rendered_html svg { max-width: 100%; height: auto; } .rendered_html img.unconfined, .rendered_html svg.unconfined { max-width: none; } .rendered_html .alert { margin-bottom: initial; } .rendered_html * + .alert { margin-top: 1em; } [dir="rtl"] .rendered_html p { text-align: right; } div.text_cell { /* Old browsers */ display: -webkit-box; -webkit-box-orient: horizontal; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: horizontal; -moz-box-align: stretch; display: box; box-orient: horizontal; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: row; align-items: stretch; } @media (max-width: 540px) { div.text_cell > div.prompt { display: none; } } div.text_cell_render { /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/ outline: none; resize: none; width: inherit; border-style: none; padding: 0.5em 0.5em 0.5em 0.4em; color: #000; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; } a.anchor-link:link { text-decoration: none; padding: 0px 20px; visibility: hidden; } h1:hover .anchor-link, h2:hover .anchor-link, h3:hover .anchor-link, h4:hover .anchor-link, h5:hover .anchor-link, h6:hover .anchor-link { visibility: visible; } .text_cell.rendered .input_area { display: none; } .text_cell.rendered .rendered_html { overflow-x: auto; overflow-y: hidden; } .text_cell.rendered .rendered_html tr, .text_cell.rendered .rendered_html th, .text_cell.rendered .rendered_html td { max-width: none; } .text_cell.unrendered .text_cell_render { display: none; } .text_cell .dropzone .input_area { border: 2px dashed #bababa; margin: -1px; } .cm-header-1, .cm-header-2, .cm-header-3, .cm-header-4, .cm-header-5, .cm-header-6 { font-weight: bold; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } .cm-header-1 { font-size: 185.7%; } .cm-header-2 { font-size: 157.1%; } .cm-header-3 { font-size: 128.6%; } .cm-header-4 { font-size: 110%; } .cm-header-5 { font-size: 100%; font-style: italic; } .cm-header-6 { font-size: 100%; font-style: italic; } /*! * * IPython notebook webapp * */ @media (max-width: 767px) { .notebook_app { padding-left: 0px; padding-right: 0px; } } #ipython-main-app { box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; height: 100%; } div#notebook_panel { margin: 0px; padding: 0px; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; height: 100%; } div#notebook { font-size: 14px; line-height: 20px; overflow-y: hidden; overflow-x: auto; width: 100%; /* This spaces the page away from the edge of the notebook area */ padding-top: 20px; margin: 0px; outline: none; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; min-height: 100%; } @media not print { #notebook-container { padding: 15px; background-color: #fff; min-height: 0; -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); } } @media print { #notebook-container { width: 100%; } } div.ui-widget-content { border: 1px solid #ababab; outline: none; } pre.dialog { background-color: #f7f7f7; border: 1px solid #ddd; border-radius: 2px; padding: 0.4em; padding-left: 2em; } p.dialog { padding: 0.2em; } /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do. */ pre, code, kbd, samp { white-space: pre-wrap; } #fonttest { font-family: monospace; } p { margin-bottom: 0; } .end_space { min-height: 100px; transition: height 0.2s ease; } .notebook_app > #header { -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); } @media not print { .notebook_app { background-color: #eee; } } kbd { border-style: solid; border-width: 1px; box-shadow: none; margin: 2px; padding-left: 2px; padding-right: 2px; padding-top: 1px; padding-bottom: 1px; } .jupyter-keybindings { padding: 1px; line-height: 24px; border-bottom: 1px solid gray; } .jupyter-keybindings input { margin: 0; padding: 0; border: none; } .jupyter-keybindings i { padding: 6px; } .well code { background-color: #ffffff; border-color: #ababab; border-width: 1px; border-style: solid; padding: 2px; padding-top: 1px; padding-bottom: 1px; } /* CSS for the cell toolbar */ .celltoolbar { border: thin solid #cfcfcf; border-bottom: none; background: #eee; border-radius: 2px 2px 0px 0px; width: 100%; height: 29px; padding-right: 4px; /* Old browsers */ display: -webkit-box; -webkit-box-orient: horizontal; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: horizontal; -moz-box-align: stretch; display: box; box-orient: horizontal; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: row; align-items: stretch; /* Old browsers */ -webkit-box-pack: end; -moz-box-pack: end; box-pack: end; /* Modern browsers */ justify-content: flex-end; display: -webkit-flex; } @media print { .celltoolbar { display: none; } } .ctb_hideshow { display: none; vertical-align: bottom; } /* ctb_show is added to the ctb_hideshow div to show the cell toolbar. Cell toolbars are only shown when the ctb_global_show class is also set. */ .ctb_global_show .ctb_show.ctb_hideshow { display: block; } .ctb_global_show .ctb_show + .input_area, .ctb_global_show .ctb_show + div.text_cell_input, .ctb_global_show .ctb_show ~ div.text_cell_render { border-top-right-radius: 0px; border-top-left-radius: 0px; } .ctb_global_show .ctb_show ~ div.text_cell_render { border: 1px solid #cfcfcf; } .celltoolbar { font-size: 87%; padding-top: 3px; } .celltoolbar select { display: block; width: 100%; height: 32px; padding: 6px 12px; font-size: 13px; line-height: 1.42857143; color: #555555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 2px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; height: 30px; padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 1px; width: inherit; font-size: inherit; height: 22px; padding: 0px; display: inline-block; } .celltoolbar select:focus { border-color: #66afe9; outline: 0; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); } .celltoolbar select::-moz-placeholder { color: #999; opacity: 1; } .celltoolbar select:-ms-input-placeholder { color: #999; } .celltoolbar select::-webkit-input-placeholder { color: #999; } .celltoolbar select::-ms-expand { border: 0; background-color: transparent; } .celltoolbar select[disabled], .celltoolbar select[readonly], fieldset[disabled] .celltoolbar select { background-color: #eeeeee; opacity: 1; } .celltoolbar select[disabled], fieldset[disabled] .celltoolbar select { cursor: not-allowed; } textarea.celltoolbar select { height: auto; } select.celltoolbar select { height: 30px; line-height: 30px; } textarea.celltoolbar select, select[multiple].celltoolbar select { height: auto; } .celltoolbar label { margin-left: 5px; margin-right: 5px; } .tags_button_container { width: 100%; display: flex; } .tag-container { display: flex; flex-direction: row; flex-grow: 1; overflow: hidden; position: relative; } .tag-container > * { margin: 0 4px; } .remove-tag-btn { margin-left: 4px; } .tags-input { display: flex; } .cell-tag:last-child:after { content: ""; position: absolute; right: 0; width: 40px; height: 100%; /* Fade to background color of cell toolbar */ background: linear-gradient(to right, rgba(0, 0, 0, 0), #eee); } .tags-input > * { margin-left: 4px; } .cell-tag, .tags-input input, .tags-input button { display: block; width: 100%; height: 32px; padding: 6px 12px; font-size: 13px; line-height: 1.42857143; color: #555555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 2px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; height: 30px; padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 1px; box-shadow: none; width: inherit; font-size: inherit; height: 22px; line-height: 22px; padding: 0px 4px; display: inline-block; } .cell-tag:focus, .tags-input input:focus, .tags-input button:focus { border-color: #66afe9; outline: 0; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); } .cell-tag::-moz-placeholder, .tags-input input::-moz-placeholder, .tags-input button::-moz-placeholder { color: #999; opacity: 1; } .cell-tag:-ms-input-placeholder, .tags-input input:-ms-input-placeholder, .tags-input button:-ms-input-placeholder { color: #999; } .cell-tag::-webkit-input-placeholder, .tags-input input::-webkit-input-placeholder, .tags-input button::-webkit-input-placeholder { color: #999; } .cell-tag::-ms-expand, .tags-input input::-ms-expand, .tags-input button::-ms-expand { border: 0; background-color: transparent; } .cell-tag[disabled], .tags-input input[disabled], .tags-input button[disabled], .cell-tag[readonly], .tags-input input[readonly], .tags-input button[readonly], fieldset[disabled] .cell-tag, fieldset[disabled] .tags-input input, fieldset[disabled] .tags-input button { background-color: #eeeeee; opacity: 1; } .cell-tag[disabled], .tags-input input[disabled], .tags-input button[disabled], fieldset[disabled] .cell-tag, fieldset[disabled] .tags-input input, fieldset[disabled] .tags-input button { cursor: not-allowed; } textarea.cell-tag, textarea.tags-input input, textarea.tags-input button { height: auto; } select.cell-tag, select.tags-input input, select.tags-input button { height: 30px; line-height: 30px; } textarea.cell-tag, textarea.tags-input input, textarea.tags-input button, select[multiple].cell-tag, select[multiple].tags-input input, select[multiple].tags-input button { height: auto; } .cell-tag, .tags-input button { padding: 0px 4px; } .cell-tag { background-color: #fff; white-space: nowrap; } .tags-input input[type="text"]:focus { outline: none; box-shadow: none; border-color: #ccc; } .completions { position: absolute; z-index: 110; overflow: hidden; border: 1px solid #ababab; border-radius: 2px; -webkit-box-shadow: 0px 6px 10px -1px #adadad; box-shadow: 0px 6px 10px -1px #adadad; line-height: 1; } .completions select { background: white; outline: none; border: none; padding: 0px; margin: 0px; overflow: auto; font-family: monospace; font-size: 110%; color: #000; width: auto; } .completions select option.context { color: #286090; } #kernel_logo_widget .current_kernel_logo { display: none; margin-top: -1px; margin-bottom: -1px; width: 32px; height: 32px; } [dir="rtl"] #kernel_logo_widget { float: left !important; float: left; } .modal .modal-body .move-path { display: flex; flex-direction: row; justify-content: space; align-items: center; } .modal .modal-body .move-path .server-root { padding-right: 20px; } .modal .modal-body .move-path .path-input { flex: 1; } #menubar { box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; margin-top: 1px; } #menubar .navbar { border-top: 1px; border-radius: 0px 0px 2px 2px; margin-bottom: 0px; } #menubar .navbar-toggle { float: left; padding-top: 7px; padding-bottom: 7px; border: none; } #menubar .navbar-collapse { clear: left; } [dir="rtl"] #menubar .navbar-toggle { float: right; } [dir="rtl"] #menubar .navbar-collapse { clear: right; } [dir="rtl"] #menubar .navbar-nav { float: right; } [dir="rtl"] #menubar .nav { padding-right: 0px; } [dir="rtl"] #menubar .navbar-nav > li { float: right; } [dir="rtl"] #menubar .navbar-right { float: left !important; } [dir="rtl"] ul.dropdown-menu { text-align: right; left: auto; } [dir="rtl"] ul#new-menu.dropdown-menu { right: auto; left: 0; } .nav-wrapper { border-bottom: 1px solid #e7e7e7; } i.menu-icon { padding-top: 4px; } [dir="rtl"] i.menu-icon.pull-right { float: left !important; float: left; } ul#help_menu li a { overflow: hidden; padding-right: 2.2em; } ul#help_menu li a i { margin-right: -1.2em; } [dir="rtl"] ul#help_menu li a { padding-left: 2.2em; } [dir="rtl"] ul#help_menu li a i { margin-right: 0; margin-left: -1.2em; } [dir="rtl"] ul#help_menu li a i.pull-right { float: left !important; float: left; } .dropdown-submenu { position: relative; } .dropdown-submenu > .dropdown-menu { top: 0; left: 100%; margin-top: -6px; margin-left: -1px; } [dir="rtl"] .dropdown-submenu > .dropdown-menu { right: 100%; margin-right: -1px; } .dropdown-submenu:hover > .dropdown-menu { display: block; } .dropdown-submenu > a:after { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; display: block; content: "\f0da"; float: right; color: #333333; margin-top: 2px; margin-right: -10px; } .dropdown-submenu > a:after.fa-pull-left { margin-right: 0.3em; } .dropdown-submenu > a:after.fa-pull-right { margin-left: 0.3em; } .dropdown-submenu > a:after.pull-left { margin-right: 0.3em; } .dropdown-submenu > a:after.pull-right { margin-left: 0.3em; } [dir="rtl"] .dropdown-submenu > a:after { float: left; content: "\f0d9"; margin-right: 0; margin-left: -10px; } .dropdown-submenu:hover > a:after { color: #262626; } .dropdown-submenu.pull-left { float: none; } .dropdown-submenu.pull-left > .dropdown-menu { left: -100%; margin-left: 10px; } #notification_area { float: right !important; float: right; z-index: 10; } [dir="rtl"] #notification_area { float: left !important; float: left; } .indicator_area { float: right !important; float: right; color: #777; margin-left: 5px; margin-right: 5px; width: 11px; z-index: 10; text-align: center; width: auto; } [dir="rtl"] .indicator_area { float: left !important; float: left; } #kernel_indicator { float: right !important; float: right; color: #777; margin-left: 5px; margin-right: 5px; width: 11px; z-index: 10; text-align: center; width: auto; border-left: 1px solid; } #kernel_indicator .kernel_indicator_name { padding-left: 5px; padding-right: 5px; } [dir="rtl"] #kernel_indicator { float: left !important; float: left; border-left: 0; border-right: 1px solid; } #modal_indicator { float: right !important; float: right; color: #777; margin-left: 5px; margin-right: 5px; width: 11px; z-index: 10; text-align: center; width: auto; } [dir="rtl"] #modal_indicator { float: left !important; float: left; } #readonly-indicator { float: right !important; float: right; color: #777; margin-left: 5px; margin-right: 5px; width: 11px; z-index: 10; text-align: center; width: auto; margin-top: 2px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; display: none; } .modal_indicator:before { width: 1.28571429em; text-align: center; } .edit_mode .modal_indicator:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: "\f040"; } .edit_mode .modal_indicator:before.fa-pull-left { margin-right: 0.3em; } .edit_mode .modal_indicator:before.fa-pull-right { margin-left: 0.3em; } .edit_mode .modal_indicator:before.pull-left { margin-right: 0.3em; } .edit_mode .modal_indicator:before.pull-right { margin-left: 0.3em; } .command_mode .modal_indicator:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: " "; } .command_mode .modal_indicator:before.fa-pull-left { margin-right: 0.3em; } .command_mode .modal_indicator:before.fa-pull-right { margin-left: 0.3em; } .command_mode .modal_indicator:before.pull-left { margin-right: 0.3em; } .command_mode .modal_indicator:before.pull-right { margin-left: 0.3em; } .kernel_idle_icon:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: "\f10c"; } .kernel_idle_icon:before.fa-pull-left { margin-right: 0.3em; } .kernel_idle_icon:before.fa-pull-right { margin-left: 0.3em; } .kernel_idle_icon:before.pull-left { margin-right: 0.3em; } .kernel_idle_icon:before.pull-right { margin-left: 0.3em; } .kernel_busy_icon:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: "\f111"; } .kernel_busy_icon:before.fa-pull-left { margin-right: 0.3em; } .kernel_busy_icon:before.fa-pull-right { margin-left: 0.3em; } .kernel_busy_icon:before.pull-left { margin-right: 0.3em; } .kernel_busy_icon:before.pull-right { margin-left: 0.3em; } .kernel_dead_icon:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: "\f1e2"; } .kernel_dead_icon:before.fa-pull-left { margin-right: 0.3em; } .kernel_dead_icon:before.fa-pull-right { margin-left: 0.3em; } .kernel_dead_icon:before.pull-left { margin-right: 0.3em; } .kernel_dead_icon:before.pull-right { margin-left: 0.3em; } .kernel_disconnected_icon:before { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; content: "\f127"; } .kernel_disconnected_icon:before.fa-pull-left { margin-right: 0.3em; } .kernel_disconnected_icon:before.fa-pull-right { margin-left: 0.3em; } .kernel_disconnected_icon:before.pull-left { margin-right: 0.3em; } .kernel_disconnected_icon:before.pull-right { margin-left: 0.3em; } .notification_widget { color: #777; z-index: 10; background: rgba(240, 240, 240, 0.5); margin-right: 4px; color: #333; background-color: #fff; border-color: #ccc; } .notification_widget:focus, .notification_widget.focus { color: #333; background-color: #e6e6e6; border-color: #8c8c8c; } .notification_widget:hover { color: #333; background-color: #e6e6e6; border-color: #adadad; } .notification_widget:active, .notification_widget.active, .open > .dropdown-toggle.notification_widget { color: #333; background-color: #e6e6e6; border-color: #adadad; } .notification_widget:active:hover, .notification_widget.active:hover, .open > .dropdown-toggle.notification_widget:hover, .notification_widget:active:focus, .notification_widget.active:focus, .open > .dropdown-toggle.notification_widget:focus, .notification_widget:active.focus, .notification_widget.active.focus, .open > .dropdown-toggle.notification_widget.focus { color: #333; background-color: #d4d4d4; border-color: #8c8c8c; } .notification_widget:active, .notification_widget.active, .open > .dropdown-toggle.notification_widget { background-image: none; } .notification_widget.disabled:hover, .notification_widget[disabled]:hover, fieldset[disabled] .notification_widget:hover, .notification_widget.disabled:focus, .notification_widget[disabled]:focus, fieldset[disabled] .notification_widget:focus, .notification_widget.disabled.focus, .notification_widget[disabled].focus, fieldset[disabled] .notification_widget.focus { background-color: #fff; border-color: #ccc; } .notification_widget .badge { color: #fff; background-color: #333; } .notification_widget.warning { color: #fff; background-color: #f0ad4e; border-color: #eea236; } .notification_widget.warning:focus, .notification_widget.warning.focus { color: #fff; background-color: #ec971f; border-color: #985f0d; } .notification_widget.warning:hover { color: #fff; background-color: #ec971f; border-color: #d58512; } .notification_widget.warning:active, .notification_widget.warning.active, .open > .dropdown-toggle.notification_widget.warning { color: #fff; background-color: #ec971f; border-color: #d58512; } .notification_widget.warning:active:hover, .notification_widget.warning.active:hover, .open > .dropdown-toggle.notification_widget.warning:hover, .notification_widget.warning:active:focus, .notification_widget.warning.active:focus, .open > .dropdown-toggle.notification_widget.warning:focus, .notification_widget.warning:active.focus, .notification_widget.warning.active.focus, .open > .dropdown-toggle.notification_widget.warning.focus { color: #fff; background-color: #d58512; border-color: #985f0d; } .notification_widget.warning:active, .notification_widget.warning.active, .open > .dropdown-toggle.notification_widget.warning { background-image: none; } .notification_widget.warning.disabled:hover, .notification_widget.warning[disabled]:hover, fieldset[disabled] .notification_widget.warning:hover, .notification_widget.warning.disabled:focus, .notification_widget.warning[disabled]:focus, fieldset[disabled] .notification_widget.warning:focus, .notification_widget.warning.disabled.focus, .notification_widget.warning[disabled].focus, fieldset[disabled] .notification_widget.warning.focus { background-color: #f0ad4e; border-color: #eea236; } .notification_widget.warning .badge { color: #f0ad4e; background-color: #fff; } .notification_widget.success { color: #fff; background-color: #5cb85c; border-color: #4cae4c; } .notification_widget.success:focus, .notification_widget.success.focus { color: #fff; background-color: #449d44; border-color: #255625; } .notification_widget.success:hover { color: #fff; background-color: #449d44; border-color: #398439; } .notification_widget.success:active, .notification_widget.success.active, .open > .dropdown-toggle.notification_widget.success { color: #fff; background-color: #449d44; border-color: #398439; } .notification_widget.success:active:hover, .notification_widget.success.active:hover, .open > .dropdown-toggle.notification_widget.success:hover, .notification_widget.success:active:focus, .notification_widget.success.active:focus, .open > .dropdown-toggle.notification_widget.success:focus, .notification_widget.success:active.focus, .notification_widget.success.active.focus, .open > .dropdown-toggle.notification_widget.success.focus { color: #fff; background-color: #398439; border-color: #255625; } .notification_widget.success:active, .notification_widget.success.active, .open > .dropdown-toggle.notification_widget.success { background-image: none; } .notification_widget.success.disabled:hover, .notification_widget.success[disabled]:hover, fieldset[disabled] .notification_widget.success:hover, .notification_widget.success.disabled:focus, .notification_widget.success[disabled]:focus, fieldset[disabled] .notification_widget.success:focus, .notification_widget.success.disabled.focus, .notification_widget.success[disabled].focus, fieldset[disabled] .notification_widget.success.focus { background-color: #5cb85c; border-color: #4cae4c; } .notification_widget.success .badge { color: #5cb85c; background-color: #fff; } .notification_widget.info { color: #fff; background-color: #5bc0de; border-color: #46b8da; } .notification_widget.info:focus, .notification_widget.info.focus { color: #fff; background-color: #31b0d5; border-color: #1b6d85; } .notification_widget.info:hover { color: #fff; background-color: #31b0d5; border-color: #269abc; } .notification_widget.info:active, .notification_widget.info.active, .open > .dropdown-toggle.notification_widget.info { color: #fff; background-color: #31b0d5; border-color: #269abc; } .notification_widget.info:active:hover, .notification_widget.info.active:hover, .open > .dropdown-toggle.notification_widget.info:hover, .notification_widget.info:active:focus, .notification_widget.info.active:focus, .open > .dropdown-toggle.notification_widget.info:focus, .notification_widget.info:active.focus, .notification_widget.info.active.focus, .open > .dropdown-toggle.notification_widget.info.focus { color: #fff; background-color: #269abc; border-color: #1b6d85; } .notification_widget.info:active, .notification_widget.info.active, .open > .dropdown-toggle.notification_widget.info { background-image: none; } .notification_widget.info.disabled:hover, .notification_widget.info[disabled]:hover, fieldset[disabled] .notification_widget.info:hover, .notification_widget.info.disabled:focus, .notification_widget.info[disabled]:focus, fieldset[disabled] .notification_widget.info:focus, .notification_widget.info.disabled.focus, .notification_widget.info[disabled].focus, fieldset[disabled] .notification_widget.info.focus { background-color: #5bc0de; border-color: #46b8da; } .notification_widget.info .badge { color: #5bc0de; background-color: #fff; } .notification_widget.danger { color: #fff; background-color: #d9534f; border-color: #d43f3a; } .notification_widget.danger:focus, .notification_widget.danger.focus { color: #fff; background-color: #c9302c; border-color: #761c19; } .notification_widget.danger:hover { color: #fff; background-color: #c9302c; border-color: #ac2925; } .notification_widget.danger:active, .notification_widget.danger.active, .open > .dropdown-toggle.notification_widget.danger { color: #fff; background-color: #c9302c; border-color: #ac2925; } .notification_widget.danger:active:hover, .notification_widget.danger.active:hover, .open > .dropdown-toggle.notification_widget.danger:hover, .notification_widget.danger:active:focus, .notification_widget.danger.active:focus, .open > .dropdown-toggle.notification_widget.danger:focus, .notification_widget.danger:active.focus, .notification_widget.danger.active.focus, .open > .dropdown-toggle.notification_widget.danger.focus { color: #fff; background-color: #ac2925; border-color: #761c19; } .notification_widget.danger:active, .notification_widget.danger.active, .open > .dropdown-toggle.notification_widget.danger { background-image: none; } .notification_widget.danger.disabled:hover, .notification_widget.danger[disabled]:hover, fieldset[disabled] .notification_widget.danger:hover, .notification_widget.danger.disabled:focus, .notification_widget.danger[disabled]:focus, fieldset[disabled] .notification_widget.danger:focus, .notification_widget.danger.disabled.focus, .notification_widget.danger[disabled].focus, fieldset[disabled] .notification_widget.danger.focus { background-color: #d9534f; border-color: #d43f3a; } .notification_widget.danger .badge { color: #d9534f; background-color: #fff; } div#pager { background-color: #fff; font-size: 14px; line-height: 20px; overflow: hidden; display: none; position: fixed; bottom: 0px; width: 100%; max-height: 50%; padding-top: 8px; -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); /* Display over codemirror */ z-index: 100; /* Hack which prevents jquery ui resizable from changing top. */ top: auto !important; } div#pager pre { line-height: 1.21429em; color: #000; background-color: #f7f7f7; padding: 0.4em; } div#pager #pager-button-area { position: absolute; top: 8px; right: 20px; } div#pager #pager-contents { position: relative; overflow: auto; width: 100%; height: 100%; } div#pager #pager-contents #pager-container { position: relative; padding: 15px 0px; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; } div#pager .ui-resizable-handle { top: 0px; height: 8px; background: #f7f7f7; border-top: 1px solid #cfcfcf; border-bottom: 1px solid #cfcfcf; /* This injects handle bars (a short, wide = symbol) for the resize handle. */ } div#pager .ui-resizable-handle::after { content: ""; top: 2px; left: 50%; height: 3px; width: 30px; margin-left: -15px; position: absolute; border-top: 1px solid #cfcfcf; } .quickhelp { /* Old browsers */ display: -webkit-box; -webkit-box-orient: horizontal; -webkit-box-align: stretch; display: -moz-box; -moz-box-orient: horizontal; -moz-box-align: stretch; display: box; box-orient: horizontal; box-align: stretch; /* Modern browsers */ display: flex; flex-direction: row; align-items: stretch; line-height: 1.8em; } .shortcut_key { display: inline-block; width: 21ex; text-align: right; font-family: monospace; } .shortcut_descr { display: inline-block; /* Old browsers */ -webkit-box-flex: 1; -moz-box-flex: 1; box-flex: 1; /* Modern browsers */ flex: 1; } span.save_widget { height: 30px; margin-top: 4px; display: flex; justify-content: flex-start; align-items: baseline; width: 50%; flex: 1; } span.save_widget span.filename { height: 100%; line-height: 1em; margin-left: 16px; border: none; font-size: 146.5%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; border-radius: 2px; } span.save_widget span.filename:hover { background-color: #e6e6e6; } [dir="rtl"] span.save_widget.pull-left { float: right !important; float: right; } [dir="rtl"] span.save_widget span.filename { margin-left: 0; margin-right: 16px; } span.checkpoint_status, span.autosave_status { font-size: small; white-space: nowrap; padding: 0 5px; } @media (max-width: 767px) { span.save_widget { font-size: small; padding: 0 0 0 5px; } span.checkpoint_status, span.autosave_status { display: none; } } @media (min-width: 768px) and (max-width: 991px) { span.checkpoint_status { display: none; } span.autosave_status { font-size: x-small; } } .toolbar { padding: 0px; margin-left: -5px; margin-top: 2px; margin-bottom: 5px; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; } .toolbar select, .toolbar label { width: auto; vertical-align: middle; margin-right: 2px; margin-bottom: 0px; display: inline; font-size: 92%; margin-left: 0.3em; margin-right: 0.3em; padding: 0px; padding-top: 3px; } .toolbar .btn { padding: 2px 8px; } .toolbar .btn-group { margin-top: 0px; margin-left: 5px; } .toolbar-btn-label { margin-left: 6px; } #maintoolbar { margin-bottom: -3px; margin-top: -8px; border: 0px; min-height: 27px; margin-left: 0px; padding-top: 11px; padding-bottom: 3px; } #maintoolbar .navbar-text { float: none; vertical-align: middle; text-align: right; margin-left: 5px; margin-right: 0px; margin-top: 0px; } .select-xs { height: 24px; } [dir="rtl"] .btn-group > .btn, .btn-group-vertical > .btn { float: right; } .pulse, .dropdown-menu > li > a.pulse, li.pulse > a.dropdown-toggle, li.pulse.open > a.dropdown-toggle { background-color: #f37626; color: white; } /** * Primary styles * * Author: Jupyter Development Team */ /** WARNING IF YOU ARE EDITTING THIS FILE, if this is a .css file, It has a lot * of chance of beeing generated from the ../less/[samename].less file, you can * try to get back the less file by reverting somme commit in history **/ /* * We'll try to get something pretty, so we * have some strange css to have the scroll bar on * the left with fix button on the top right of the tooltip */ @-moz-keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } @-webkit-keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } @-moz-keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @-webkit-keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } /*properties of tooltip after "expand"*/ .bigtooltip { overflow: auto; height: 200px; -webkit-transition-property: height; -webkit-transition-duration: 500ms; -moz-transition-property: height; -moz-transition-duration: 500ms; transition-property: height; transition-duration: 500ms; } /*properties of tooltip before "expand"*/ .smalltooltip { -webkit-transition-property: height; -webkit-transition-duration: 500ms; -moz-transition-property: height; -moz-transition-duration: 500ms; transition-property: height; transition-duration: 500ms; text-overflow: ellipsis; overflow: hidden; height: 80px; } .tooltipbuttons { position: absolute; padding-right: 15px; top: 0px; right: 0px; } .tooltiptext { /*avoid the button to overlap on some docstring*/ padding-right: 30px; } .ipython_tooltip { max-width: 700px; /*fade-in animation when inserted*/ -webkit-animation: fadeOut 400ms; -moz-animation: fadeOut 400ms; animation: fadeOut 400ms; -webkit-animation: fadeIn 400ms; -moz-animation: fadeIn 400ms; animation: fadeIn 400ms; vertical-align: middle; background-color: #f7f7f7; overflow: visible; border: #ababab 1px solid; outline: none; padding: 3px; margin: 0px; padding-left: 7px; font-family: monospace; min-height: 50px; -moz-box-shadow: 0px 6px 10px -1px #adadad; -webkit-box-shadow: 0px 6px 10px -1px #adadad; box-shadow: 0px 6px 10px -1px #adadad; border-radius: 2px; position: absolute; z-index: 1000; } .ipython_tooltip a { float: right; } .ipython_tooltip .tooltiptext pre { border: 0; border-radius: 0; font-size: 100%; background-color: #f7f7f7; } .pretooltiparrow { left: 0px; margin: 0px; top: -16px; width: 40px; height: 16px; overflow: hidden; position: absolute; } .pretooltiparrow:before { background-color: #f7f7f7; border: 1px #ababab solid; z-index: 11; content: ""; position: absolute; left: 15px; top: 10px; width: 25px; height: 25px; -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); -ms-transform: rotate(45deg); -o-transform: rotate(45deg); } ul.typeahead-list i { margin-left: -10px; width: 18px; } [dir="rtl"] ul.typeahead-list i { margin-left: 0; margin-right: -10px; } ul.typeahead-list { max-height: 80vh; overflow: auto; } ul.typeahead-list > li > a { /** Firefox bug **/ /* see https://github.com/jupyter/notebook/issues/559 */ white-space: normal; } ul.typeahead-list > li > a.pull-right { float: left !important; float: left; } [dir="rtl"] .typeahead-list { text-align: right; } .cmd-palette .modal-body { padding: 7px; } .cmd-palette form { background: white; } .cmd-palette input { outline: none; } .no-shortcut { min-width: 20px; color: transparent; } [dir="rtl"] .no-shortcut.pull-right { float: left !important; float: left; } [dir="rtl"] .command-shortcut.pull-right { float: left !important; float: left; } .command-shortcut:before { content: "(command mode)"; padding-right: 3px; color: #777777; } .edit-shortcut:before { content: "(edit)"; padding-right: 3px; color: #777777; } [dir="rtl"] .edit-shortcut.pull-right { float: left !important; float: left; } #find-and-replace #replace-preview .match, #find-and-replace #replace-preview .insert { background-color: #bbdefb; border-color: #90caf9; border-style: solid; border-width: 1px; border-radius: 0px; } [dir="ltr"] #find-and-replace .input-group-btn + .form-control { border-left: none; } [dir="rtl"] #find-and-replace .input-group-btn + .form-control { border-right: none; } #find-and-replace #replace-preview .replace .match { background-color: #ffcdd2; border-color: #ef9a9a; border-radius: 0px; } #find-and-replace #replace-preview .replace .insert { background-color: #c8e6c9; border-color: #a5d6a7; border-radius: 0px; } #find-and-replace #replace-preview { max-height: 60vh; overflow: auto; } #find-and-replace #replace-preview pre { padding: 5px 10px; } .terminal-app { background: #eee; } .terminal-app #header { background: #fff; -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2); } .terminal-app .terminal { width: 100%; float: left; font-family: monospace; color: white; background: black; padding: 0.4em; border-radius: 2px; -webkit-box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.4); box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.4); } .terminal-app .terminal, .terminal-app .terminal dummy-screen { line-height: 1em; font-size: 14px; } .terminal-app .terminal .xterm-rows { padding: 10px; } .terminal-app .terminal-cursor { color: black; background: white; } .terminal-app #terminado-container { margin-top: 20px; } /*# sourceMappingURL=style.min.css.map */ nbconvert-7.16.4/docs/api_examples/template_path/quiz_notebook.py000066400000000000000000000041751461373220400253120ustar00rootroot00000000000000# --- # jupyter: # jupytext: # cell_metadata_filter: all # formats: ipynb,py:percent # notebook_metadata_filter: all,-language_info,-toc,-latex_envs # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.3.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # latex_metadata: # chead: Quiz questions, January 18, 2020 # lhead: E340 Day 5 # pdf_metadata: # text1: html header success # --- # %% [markdown] ctype="question" qnum="1" # 1. Suppose we have a one layer atmosphere with ε=1 above a black # surface as in Dessler Fig. 4.6. Does adding a second opaque (ε=1) # layer (Dessler Figure 4.7) increase the greenhouse effect, decrease # the greenhouse effect, or leave the greenhouse effect unchanged? # # A. increase # # B. decrease # # C. no change # %% [markdown] ctype="question" qnum="2" # 2. Suppose a planet's average surface temperature is about 320 K. In the one-layer # semi-transparent atmosphere shown below (and seen in your reading), # what would the approximate long-wave atmospheric emissivity ε need to be in # order for $T_g$=320 K, if the average shorwave flux was $I_0=400\ W\,m^{-2}$. (Hint, look at equations 5-6 in the reading). # # A. 0.54 # # B. 0.65 # # C. 0.77 # # D. 0.88 # # E. 0.95 # %% [markdown] ctype="question" qnum="2" # ![fig1](media/image1.png) # %% [markdown] ctype="question" qnum="3" # 3. Given a one-layer atmosphere like problem 2, but with $\epsilon=0.8$, $T_G$=306 K, $T_1$=258 K, $I_0$ = 300 $W\,m^{-2}$, calculate the greenouse effect. (choose the closest number) # # A. -121 $W\,m^2$ # # B. +121 $W\,m^2$ # # C. +197 $W\,m^2$ # # D. +221 $W\,m^2$ # # E. +324 $W\,m^2$ # %% [markdown] ctype="question" qnum="4" # 4. According to the figure in Trenberth et al. 2009 below, how big is the Earth's greenhouse effect? # # A. 85 $W\,m^{-2}$ # # B. 157 $W\,m^{-2}$ # # C. 254 $W\,m^{-2}$ # # D. 285 $W\,m^{-2}$ # # E. 333 $W\,m^{-2}$ # %% [markdown] ctype="question" qnum="3" # ![fig2](media/image2.png) nbconvert-7.16.4/docs/autogen_config.py000066400000000000000000000042631461373220400201110ustar00rootroot00000000000000""" autogen_config.py Create config_options.rst, a Sphinx documentation source file. Documents the options that may be set in nbconvert's configuration file, jupyter_nbconvert_config.py. """ import os.path from nbconvert.nbconvertapp import NbConvertApp header = """\ .. This is an automatically generated file. .. do not modify by hand. Configuration options ===================== Configuration options may be set in a file, ``~/.jupyter/jupyter_nbconvert_config.py``, or at the command line when starting nbconvert, i.e. ``jupyter nbconvert --Application.log_level=10``. The most specific setting will always be used. For example, the LatexExporter and the HTMLExporter both inherit from TemplateExporter. With the following config .. code-block:: python c.TemplateExporter.exclude_input_prompt = False # The default c.PDFExporter.exclude_input_prompt = True input prompts will not appear when converting to PDF, but they will appear when exporting to HTML. CLI Flags and Aliases --------------------- The dynamic loading of exporters can be disabled by setting the environment variable ``NBCONVERT_DISABLE_CONFIG_EXPORTERS``. This causes all exporters to be loaded regardless of the value of their ``enabled`` attribute. When using Nbconvert from the command line, a number of aliases and flags are defined as shortcuts to configuration options for convenience. """ try: indir = os.path.dirname(__file__) except NameError: indir = os.path.dirname(os.getcwd()) destination = os.path.join(indir, "source/config_options.rst") with open(destination, "w") as f: app = NbConvertApp() f.write(header) f.write(app.document_flag_help()) f.write(app.document_alias_help()) f.write(app.document_config_options()) # Workaround until https://github.com/jupyter/nbclient/pull/216 is released with open(destination) as f: data = f.read() data = data.replace("`CellExecutionError`", "``CellExecutionError``") data = data.replace("`cell`", "``cell``") data = data.replace("`cell_index`", "``cell_index``") data = data.replace("`cell_allows_errors`", "``cell_allows_errors``") data = data.replace("`notebook`", "``notebook``") with open(destination, "w") as f: f.write(data) nbconvert-7.16.4/docs/make.bat000066400000000000000000000161331461373220400161540ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source set I18NSPHINXOPTS=%SPHINXOPTS% source if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled echo. coverage to run coverage check of the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 2> nul if errorlevel 9009 goto sphinx_python goto sphinx_ok :sphinx_python set SPHINXBUILD=python -m sphinx.__init__ %SPHINXBUILD% 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.http://sphinx-doc.org/ exit /b 1 ) :sphinx_ok if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\nbconvert.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\nbconvert.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "coverage" ( %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage if errorlevel 1 exit /b 1 echo. echo.Testing of coverage in the sources finished, look at the ^ results in %BUILDDIR%/coverage/python.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end nbconvert-7.16.4/docs/source/000077500000000000000000000000001461373220400160435ustar00rootroot00000000000000nbconvert-7.16.4/docs/source/_static/000077500000000000000000000000001461373220400174715ustar00rootroot00000000000000nbconvert-7.16.4/docs/source/_static/empty.txt000066400000000000000000000000001461373220400213560ustar00rootroot00000000000000nbconvert-7.16.4/docs/source/_static/exporter_inheritance.png000066400000000000000000001101531461373220400244210ustar00rootroot00000000000000PNG  IHDRgAMA a pHYsodtEXtSoftwarepaint.net 4.1.6N IDATx^{,g}zyGLrxOp `|e#,K/>XL;WӧOz)`|Mm~G2]ӾFV6"r#|7?P:wHuOՕn_msnX]h{2}wWo7;lEܷU6"M*`&pqvFX} `\e#,B0!pnwWo7;lEܷU6" ܿ_}_맞|ez7M*`_FX؁TU `M-~y>>?g?qo~Cݽ=MGkUc]#siӲ^>ϣwQwW- V'#￿a~k^U?Y$pe=|wpO'|^/:lOWo֞[Н[{ 3-?'oӫs^=[_V~\VhC* oj U6"6}vU0z^> ۼU3-yQ>0p/{ wWtޮYWk2m-kA*`S}Ǭ}W[pcFX&wCO?o^fZ [@U6->Vɼw=AH0ޟޮwC5O~N[Q{ ^}ߖ駅 - `FX؁< G?phWWWQ{?Tk-+9 `FX&*85Ӫ+2 3wGIWݔ=} C<6Wgׯzq `\e#,b$0!pnwWo7;lEܷU6"!pg6;lEܷU6"M*`&pqvFX} `\e#,B0!pnwWo7;lE9sFp+`rKwet_2e]>0S`ue#,;.]et>VW6ï v{]{5ݽ{ ,lE;we;^f_ӝ;{W[oww})qJ..g_]& OJWs>lU;s#na2.{ӯëȫٔ\kd䔍+Μ9]~x[- 춲vEwהزO]k[`Kn?w!X=+N~pW6.w_~ٳ[eP>[7&w}e#욫_y?.qcROe#[o2,?;?pY*챲v}7O=՝~ϖqW,ܹsme#Û^o,(`={g~|U,n {l]uWwW=28_/x~w5t_/e#o}ԛ,?7KFU׾e,+fsS/>SsFe.nzk }Q,>^?Fuǽy>f{T7KFuy/~qw (~,5 S̙3+<,57_ 쯲ANeK+/<}Ss矺{O=Aُ`rP6 ڛ\]y[%O{L_Z>>?춲v׾3 ȇx#+{I_:} 쾲vW"/^]u ݳ/x|w[>Fn)`U>K^1ӝ~>(p5:Yk͒f=즲2WyuwǫֽnwuSsw\^>~{>p얲e]IW<{ ѡS~/Yj~3d?ͫ*zj 쎲Y*|Az[~a.7O,z`?;{(WWa{\.o?}]9_,z?z 솲?2Wz'{~f-|}sts/"_GD$߷~wu𛺳9}w^z{C{ygxAw9X}m 0T6'?}v'w0~ @FWw`Ue#+;XUJl}%pVU6*`_ UFWw`Ue#+;XUJl}%pVU6*`_ UFWw`Ue#+;XUJl}%pVU6*`_ UFWw`Ue#+;XUJl}%pVU6*`_ UFWw`Ue#+;XUJl}%pVU6*`_ UFWw`Ue#+;XUJl}%pVU6*`_ UFWw`Ue#+;XUJl}%pVU6*`_ UFWw`Ue#+;XUJl}%pVU6*`_ UFWw`Ue#+;XUJl}%pVU6*`_ UFWw`Ue#+;XUJl}%pVU6*`_ UFWw`Ue#+;XUJl}%pVU6*`_ ULٳg[o;sLwM7qnx<ڗ_U2_LU{ 7Нz=;DZ=Q%O\/g\?ݩK.讽ܹsPLMf%d:r]On_o'v7 @(ج+/|Bw)Iӧʢw4)H7^}6(؜02a?~G>¾9V`jF6禛n:ylkl`sZ^llllllllll[?98sk4mP69 W_qN/'/}Bϔ7podemئCY{U5}lO~p|e#s_)3f S ܧLJW693>'r6{~{܏<k_|8O_~o/>~-6\N̝oJ?\^v;K[vN6ɴZYYw(#yۺdnǾ~׿y -+yTsQwA;pOԡy[0ԡYm~?-O>*Zh6X$pP Ek?jy=܆m;f~ljzd=J[{~(;۠l`s'M(:R9W_`uz f]B?io]l!mDgz6Զ0@o}k<֖Җ~w~n۰晖6N>HȺdޞ[yU F6g{ rvcZ < k¶U;/mӲn-?,U߳ .ylyxz{mZ SB2 MI{>w\wA3pg, ӞV:k7rћ~߳ uWywڼ@$2Ok͏ޮ_lYgByiG3iAnj]N=Ǫ۠Zy1*y6m6oȴzGMOQ6=;۠l`s67e wu.}-KW1kng=XuT> ļu>6:pue_mP69 [y³Bֶ煻-tJY?njgz<|oC=ZֻzN}zϛ֫y2o5C6(؜u9ɴyL [ۼ@xVڂ[[oU٭=W.6_O܂~pni+WU0]Iy>mo}?TǷo߶O~n߹۶6mgYm=A_1e#=Z:K1-?I{Okexp z[<ڇC*k ϟ=[^yczng-jӗ^ F6g݁{+[X\ܿy| Y[_vkK(@:?G֡ڒjG~NP?+XJrZvӞk_~_!ߴ|Wd}vס/a~~`K߰OzϺe?_ F6$Y$G-̮;;۠l`sK>mP69%pM6(&p`l>,;۠l`sp>;۠l`sp>;۠l`sp>;۠l`sp>;۠l`sp>;۠l`sp>;۠l`sp>;۠l`sp>;۠l`sΜ9#p|5͹[/zJ a|t jX+05e#swv.;/G77KŰV`jF6k=Z/-e =ok^{Q LEf;wg嵾^O~7\]uw}AYԵSR6ygϞtzbwꙏ|X%OnהIua!`ܟ]`X0Ue#ӑ΍ToVpՕ﮼e0~R{ɩ+h﹪mFgΜ.ݟ2[+me#\%*e9.W*`tM߁f/w+/}ע }e#|K./t_.߻?\`k~+/yB嚟~V'짲vͭ]~S~5eX~\_>9*`g{>ﹾ S3Y?݇}o3;^_FE_}7OKOg>+鏜y,ӽEo=XD\`?k;yyA{s[.z⿛yw'p_}iHWF_ʗe@>t3Ǖ5?yOuc}e#삯|S=E >˙_*~5 ?=)n~sU_كը =e#l\ٞл g<滻^r_Ûヲ|,jcnn*`-se{|8E?w{yj~#o|, ݇즲e]IW={ߋѡ=tOorYj~ód?}Uesժe#l\U^Cw^MӾouϻGzBw^*we#l/2U? ~_~w{㿮/`uvC{{xګ==mw?=/>p7}^n(`[}n.*<{>{|R}~ke&uvKk_rۮ/Upޗgrz\W.ݗ?_խFٻ|w+/,|L-ru^вzt#F ?7u|˻;w^} ?RCiܫ~YeCikEW~`; W Juno3Cgs >Ǖ!ߡO~?sFV6Ij_ և^-JP_en{7-|e{O-|߸T A<l^c%LBiW!u퓿wM~ϲH~ΗV}TYj _m4 ֫leU72]8XI^`sca}EZ/az]~H_x<\<\/[<8F'ly"_U/~_W{s/|Ow?2 ?igTW|a~/'?A7nM VW6@3j=l.l51boW?pE5_`m'2?)Y04z }~o-.kop:F)kj'_{FG7?XW&!*9xA{s{sR{3v$cK?Yk]籋IMCܓ ܛuͺoğr!`le#iWudyUZ jZ6h_G~Dެ;olZP4qu 00+N{k݆_-wyY27ޛ5l?J,j}f=F 2rΠRެkZq,7xl7 u%\U-r.ry[|ckH`>eGu+67Yj67ٟXS˄؂x6le0.Aܺ,#_LK0me#T%0N@G zzP-aX#a} O:`o,s8{fۂfXEl j%PZUjXW~|e/}>}A{slslk޴0 `}Fu^>V}YV±Sc}3}0`Dxe9-|2_rBdWeͶM?ϲl8) Zgz-rMCO"`K 'eYYeYMYvBE?٦٥>,S ޛu,XNP #t^D [ XiW\fy$ZW2_ʇح,I bmM5k&$TiaV–u]ëݮboY-j_o3\eul{d?Wo&zl[޴׬دW m!U$i( mm~>FH>&Ӣ^>!g=9/K^8X%x#0A<F`Zp%!X"-zȓvll<)~e} |ˎؗ|m A<F`}$4_~M%t |P0"kmծ"MKAsUDde'>%vEo(g 6%\a>6K uZH-bQy>ٮ~}9>3Gۦl/o`]ze%6-J1vKP>pص~_te=V!p_}uᲷU X\M XGYN,wNXbm WzEC'AlCA<ie#Pkpʼ^WedYd޼'˶L(2vvjr>ٲ=m'p_}\]jgقxme#컄 Z1f |,'ۅևle>0F2ķs A<LO.d ~}z7Ynޔryny7c}m@}81\Y6h~P.ڮqe;/'4W'?Y9V (`$Lp6ogYV?h`cl"}v6Ytgԁw<leI8]6gmd 䔍0E Ƶ.¹ʸ]uOfk{kWk{`F>.f,3_rlqϗmsA<얲6-aޘ'D\W ZO>\]׶AG>HM66+OI9ֆwS `qe#KUzs2A;^>}0ևپٯmlО ĕ'C> ނ EcF8 M\,A8?"_3}MRf$p,d ާ')_ luLe7}y.O#%h;Go!rR# OSBtt#W럇A|q }P6SDm&WԲMNkbڕ͖ څ'p6vHO_C:A<* D tuYFտj=oWWsYC2YLMˢ5}~ou^3W3 Ob?-bx0ue#-oV7^yӵ`=ƹ<OmO"Wоy"xN3 `ye##oDۛ޼9+]DSӋ>˛߼k_7‰d\/ߪ}$p6vk"'f\%FvO`Z_4<YVސʹm7oc쓌郎-',5I!pn>~;`'6oT}z rYjڕ~c }1=ݰlz}Nq⯼N }R6=o`e]ze7-yM&4۵>JWOl|h ڧM[V #OmN ]T60=y× o6yz|Bf.oڗm?Oh= ڳ'pM |X=N2OF6yc׮xc%ȲƓ7c_ |lО5#TGnH-Vwv:cnZ| A|EF04oXW5/"ɛvp}=f$b.~ΛjU pow"/5bO 1/o xNgYV@6'܂jMX<4o|P2=y};j"xm>j ~,lgyC7;9n_ `=,D c7#<7ٷyaL6/=|]-uD˷k猛yfAye#IrNHIr0+\ϲڛ7TAXc }MW{e 4dߤﹺ,SD5.fcfzx짲`7gN|f%''}W;NCAǘ7;m9ofkc`ׂo>;sܨ,9.OƊJE눼'YU;3O ?ķq<``jrBsul5͕~ɛ+#c~^ycXJj_-/;3<LWI9IZ+\2otq>Wv>Ly]Ƈh|M9o0 'e#:$,M3`=Z}}6xIX7n~\6h9Mq֧l[9AiPdMWK;mTxY{yau-5/w%x$  `|e#Ze X!QeY9Qsj{X̤i\o3&"pglwAϘ+тM\,7'B}L523>2Fݖ}{v1U;%xgAI 4dd -M7c,"cGw"xgN:o: ~} lvKɼD#XvrN]8c'up쇌,:2fMY6xba?0u^W1x A|-VU6۫ s#'Cëօ-8c-'cvߖ hp\yƘ`u3Ey l}8<u_GYNJ$'2o98\4KNBUNW3uwv}Oja<$i)arv@$N* / Ug> ''%ck2.t ev} (aJr"㜬vep1d ebECA;Nξ[6xO("xg׵!$̲"u6}?ָ^>\&lJ{N80)؉)J-|^xeA|E=%`^T}z !ۧu6@X?v㚩Y6hxN ]"pxP,wx0<'g[,E+/ ׳,w&Z;c8χGv*c3Ëg3il{8sLT * FrUmhr\YN^x\d z냦6ӧqe|昐4<-hga5w#g*FS  ˺ZU n"ctȘOe "%Gj%7(RՅsfw8Ip/[n*ET<81/e2&sJ},.۸.l٠=c]>|,BUKa9x8ć ~LG ['0IRZHΔe|}I9ئOcmG^ǫ1^ɘaL9za9vM-Om Gf?qiȱ=J,+EXBflOrbhm<@˱Iu|RW Z?V,AB+u_1% 4L0CtU/ uE)#wd_M1mNٸ{キ;[n馛X ]ļICwͅ{ũN)˻lƪū/ݯxCm1je_xɳvc׏'ٳg[o;sLxck_qU9?qvw z,N_e͒c]1cjr\9/βVx~z݇n_va6Z[=W6.o|ޥݩ ۝zu,ಟG}H{c}Gwv,[y#^|xpmηzcMwޝz}uj{qXO"'7pCwꢧtz '|W9?=Xw'v^{mwܹaXͩqٌw^ܐܰ /ƕ˹bVlK~M$qW5mqc:ql\TS||w=Wv^;x{~0'Z1hW>m'ANV?}yu|֏wpiZ `L~]/mxG1m^]q{e"*}7*W C7=pOX_v?r܁lxM˶ZW6.d~ &|֟;өX&ꊱls=6m'y ~1qmql;{I0.;&;L'pg/ wX%p_~EZOr_j:}RSˬG^'iL}|XMc?lMGo/m2/zԿn甏;vz"iYMkE8qO7aJqYɘkfh-.26nUKS6ړρ{WմUmj?;۾]T}]ǜ*Ǧ:.i&z޶dVD<>^_)nϫ6k7ۺgZ2Zsjpm).՘}yl5rieםuz]mE/1}'18ZE5}Q֯*! f2cv@pxmj?;۾]TYe?o,r긜VOOE5z}]dWk=jRxSM[Ɣ^yNZS} }=Oe?kM[VpZulHMM#y/{^џj .ۤ}浾2miǥ6nue?|~xMן7,ܖokyLnm{߶]{۟6oO2-{֥i~m}lLȲcc8V+{61*Mosoc8_ b[۬mXiN>۴JMMޙj?ygsJ[N[nSLjƢ-?ꏛY^i󦞇:]p,ZWy"jHpEM>p%O2;k8hl/<6_~Άv@~n#f ";W/c6EҞC Gbl H6i˭, \UۮQMk/.j-QM6ݷ8> jgðy!LZ!yִ?jYݶpYio,K>{L6^5YeW?P?=?x9ϘUϳkjsekjh1kjc,.c&?٦E{|e[=Tc!\{UG~C;Tcq8l_YY:g]Gٟ=Lmzip_mWDEFBJ˜5qbx UZjβ-٦U7]exΛi*6?xk˟#:uNkͼH]ۦ^{J{eL>p6Dë?ϴ6_#VXm#)jhZ_"%?ۋ`YAϭR_TpOi{Jmp#ϣok-۽m՘]ژE7 ׫6ڋꬃLCic6ciϵ?3o[^S鴧-9ޤV{mYvYmڏC>{LΓ}G5m/:Q?2vྈq~ٿ9ٿa_ϳqmq?߉nTm>swSh'QSluۖ9cgɾl)}}mcv?3Ҟj伲?yfoY~[^ֹ~am矧M{j{۴۩Ve[[駿9mLh!۽gڳϟy#}qR>X"m,s֯yǙhumU}fZ{yL[f5ϩ=>ݟ/6ؖlۦ)mܷim,Xd_yL5o3kLmȴܯٴG?G;ڷ?f6[m޴G}jzZ55ոi?-6%۴[mҞgi~*ݶMUi9v\ˊ=jZe;e _u>pg?dkBӟ/=i[l[<*ݎzk}3m_ͦPg?Zg ۢ~9myc"~_vZM{M뻿U_k=jS8݊FΆA+x;uW즚vDve2O+bzy^ta>jz{a'oYoUk%oZ7&_D;E֧dmz.Lo?4oz;GmU۞Wهm?4};nrQ?#p@۾8i~Q!}1ڇ} ?"ϧ9Z[6h1s} ܳ^mߛvp, cyQMJwVuS[UԼqXM"ۺ b޺}ߖ]ge<îVmm2߫m9pje6\s6NQ۳1[qXm m>|}7oL ͛72OOմ6k]gv޼1G?ozk6=jbmFu7Cy;1\E ?i*ˬgzi'02\m~h'*9:QY}M?ʉ\1rۼ^C?4o,[?ߞ50?VVv,3ƫΣ~GQ!>r^?v1z|eSYmnSlگñ4ԦGKCZi Z_irZ~oix|7i]Ds;~Ŭ6o]ͻhm;Mue_.˶S syjϥ-?z=hmZp.bsue_>ˌ<&܎Ͱ捉mxY:Kj)pļun65>j_YvEdvj@r|y;_m2Z_P%3}VTY6P[!ڎ3۴'dYoUk ۋ*~39Z[aMzs} g|[]eVN-^=i[㞻UϳJk?>ϵ̫Y>M֧Ռo5>6>}-EO_gj!㼵>hmLomS;G;?{B{-꩚c[2㣭w۸=koڲ{ko6혔1ǥ-Ӣ7iv&8ۥK=_mwykڞ<-鳿o_1jޟھ2pߏqR}{MjZ,2ivW{,m̴3OŌ6,Úw޴s)6o׻GӬm dL7z-jٙOдR31oVӖVm̗2}TU}1mz{c}Xǩy26gџ)p?_'1eޘ-3Z}WϩvATjgXކr5gUWi68x&;2k;3J{` Uێi7iGk6IhS:,~9? $1k؜4_߷]?^hWŦjZq5O mWoA;_< K{y<[=mUMk}ezf۶Zm Qpxk=&{־c:Q?"pV'Xu[O|yaW{Mu@9ZFm2>c3?gVz7鼶_sh_v >}H˲22y㰚~mꤪ˶1iHm{pmy{&2_v9p~sZΛ?M~~|+˘|?"j-wj>׶E|֩=ma_moqLoĬiVsyژjS=KeZ[{Z3 mkͼUWyl^S;{I0.;&;L'pg/ wX%p$p%;<@ø0]w߉{a|*ꊱmc=b'͙3gLF±8M/hS<:=Wt;?S.6+s0<1 czPl.O[nN=Qݽ|.v džct*w`5<^:|S>:98}twKW=kg=fb,\MۅIy睇W`|卯xv8S1qmql\wݝݝ~eN/N=~3u ȶփ:`~rB?{_^>_8iysk_]|8>q7cԦ~ue-{+0$|gvW+'k2é~7صzPӮO"/x9/\]tgyc=SG1m^]q{e2nԳ/N]S~?}pyNJW˾x~oߕϻ8SڋR3zY>DxI⩧>;勺.SOku8WɩIRaKǸխ^94W6.+,~7dȧT(7})]ړrݕ>Z}Mo䖱ufƵ5>~5QOYjZiPۯldy1ƗD9xǖ&~5K|jƣ` l Ӡ_jθsKg?ol5zR*LZne#eryxS|Op`OxlVav+Y/z݄A5QOYjZiP۫ldu{g<{./q}M?q+ ̧F`< 6K vP0 jq{.]~٥uW<u sx#s,^&jS#0a;UFOolȀ]f`>5QOYjZiP۩lxΞ={xc^ u#vG=fAjA-n꫻+^Ջ/wݵ/كe6S30',5A4S6r|~768AndR30',5A4S6r|\^Vndp.u#vG=fAjA-nqi?v|Ww72`OxlVav)G>):uS7'Aswt[/ vG=fAjA-nW{E|jƣ` l ӠGxolpcW F 5zR*LZe#ɍ ~ _`?uWP30',5A4+ .|b{C/72}>P30',5A4+9Or]wȀf`>5QOYjZiPV6r2ko.}vwh2'~w-< G=fAjA-N[xguș^}=w>{A?q}^sgxS|젻zK ̧F`< 6K vP0 jq{׾s'{m~ K3ol\^O}"}#o=XD\VjS#0a;UFVOѝAs[.zwϼ;N?qս`q:6I|w=9GcodzMYpcn0EjS#0a;U;F̧N[xú.~俺9ݕ?w~gIA H|jƣ` l ӠwGb-f%Ekڽѡ]'?Cndw]A5QOYjZiPlh_ʧGU!O?OW)1_W~ uyz:&OxlVa)9?r0廔~N=;~u<~>3W3lG=fAjA-}7q}/|C'=yx#jzߧr}p]a ̧F`< 6K vP0 jqw}ՠ'NW~9וy"+LG=fAjA-*8?Өv"=ZO?n)'(u)Q30',5A4R6{n{}90gY(x >*Y< ̧F`< 6K vP0 jqw,.p?@w/~|Ory~Sf`>5QOYjZiPld9ٻV*1{M :jS#0a;UFPǑԉmf`>5QOYjZiPۯlduۻ^WޱOBpm ̧F`< 6K vP0 jq{g?NR""¶R30',5A4S62/ɻ|rp/"G ̧F`< 6K vP0 jq{|ҹ}7u~n{}wOLϟsF }f`~'Cg?tݗwtgk,@=f9Vaⴕv'?}o;;\?'`Ue#]0lƣUvx.BzVU6E@QOF`a< XUl!G=*" '`Ue#]0lƣUvx.BzVU6E@QOF`a< XUl!G=*" '`Ue#]0lƣUvx.BzVU6E@QOF`a< XUl!G=*" '`Ue#]0lƣUvx.BzVU6E@QOF`a< XUl!G=*" '`Ue#]0lƣUvx.BzVU6E@QOF`a< XUl!G=*" '`Ue#]0lƣUvx.BzVU6E@QOF`a< XUl!G=*" '`Ue#]0lƣUvx.BzVU6E@QOF{キ;[n馛 |y^MIKp,gvzkw̙rp>4`cvQSvwW^~Iw?ڝzûS?{%?Osُ~[9y/ya8S(.p ݩ ~;_oJi'@wܹsòKF\|꩏nݽg߸ }`|.zՏñKn^SݕO֟}l>pTNuWumӝ>}`xcvES+~ s`7^v6wk;{~-x緯~f˘1ד$p?Zw?A1?~c_ֶn˨iW뮽ƵחFܛyWA"a}%lc}!p*`jAZ\B~PGyaf]H̼ۤ=jˇO ݇;c55i1yqu'p*`jN2po.v޴Z(+_/sR{7apZ ϣnY׬g~6i_\f3J,=v<(|mQci577c?&[= |?W> h},+}yں.Rw9|?M?q2Z[$ꮿ=i˭d ue#L:jZ~|C-2a2&0L ݂aȖP ?Z.Z{%P[FVq?|Ee}Uq3#{N?н}pV鏗>r۸=77]wwv]SQi-`7Ԯ,[2a޼Sº%p-~s´֖Ǧ->A]=s>ӞeEsx|Y}jZ(q;iw֣m_|1u6_u_w黍Vgmڊw̴?)ԝ]W6ԜdG Ӣ+ 2OBvT7-L{yE{ޟւj4 2m{0N%뇎}mYm cϗZʹeTl۸j3>{?8rswR=a-:m?kpڪu??S;;l;pe~PB8*Zm* %Ae_żo̵y84Y^Uϱ?_߼ [3ma_I0ퟰ>W߇{*|hȲ*oLE-qnyӧPwwv]Ss{BU@@>.-3o_"5@1ZմYp&Qϛd=j22Zxq/}T5[i'oїIgٺk_27[w͛K~/{ wv]Spִ  󖙷Ipؿ}xq 6:pue_xZp>kfZ1U?KmS7ϧͻ+܇}e!p`ו05S [En!"a26-:??'Zh!d mv5}MoX%1մU ܏/>oBa4#ﳾf>0ZuPeKSmu7ܞCd ue#L͔e [xpk0oycxƄziwJܬ aZӖ~}~n_~j˘$euy~ 1#u  ge?'1O՘6_s;ca- [ed:鏡';Ϲ~ zUwkdYm鳿6=캲fӁ, T L杧o?M~_U7fm}]½ G%n1՘~0Gߟ6FQMouDj+[=ki^ycg_mN+`j'0KqxiYX2_BsZy|J8߿x(}[Ny*  ?ܴ˴o;.|c_O51jn8~oFe6":;cz֘.*Zm ?`îIݬ7+ӟɺF}BjھsRlwv]S#p_o6;'E&p`ו05fsRlwv]S#p_o6;'E&p`ו05w&pF;c ue#L a캲F~wv]S#pglwX?;l36;]W6O+`jM'p`ו05w&pF{0p[[8 g8ֶݙ3gLV>Y%e#LU^7^T8tIwsO zm[n;6oB1 l):}twsQ9#k`Xcmy睇WUO,;l_.s8f`0Ew}ww§tw~J"䗞qHr2_zөrO}K|=p.)`rýSO}T<7_^;0߸pO:?=n/yaW>˰>ӳxc)*욲[oN]ԓ;wW>wϣڽO(C ~{/2~*۳g~mN>`8c>POq8WxQEe#L]owMn{# Nu~Ulsr#j wOF`ztw0olYNFM@6\v Xج\~?TzcrrCZ_.ROƞ2Kn&z~u]u(wzc{c`o,x#o@ CL/zAwZ{ce9nlȮSOI+i[SO_2;_ÛI#@='lf=q]ܹsvzNZLGcssGzNRLٳgo+Q}:An>QOI*i꫻+eз?;k_҃e®ROI)iGssGzNJLK5O/qsGzNJLǾ'Yݩ};pF`zr ~{?T:A?w}A`ש'$4fzV6tx'7{<0{ZGwW=T~}þQOF`Μ9sa0\M{g,}G7w'`Le#0mO>W掙?N=c)i;KSC/7w}SOXF`r+-e 8t݅0zP6_}cwKO/C&/n喃}SOF`'u[_}w.>fG>[^}ϾM_Aw2`_'`le#0_>'μᄊ{~~v>_ͼcnxţڽ>q>,^."/'涛.yw?owK[^ݝ;WSIxuv[lR\zCW<[ˀeOx7,^fv_lW}f9꫺K~'<(uO>hhw-WwYكը z֩l6#W&»Yr? [)7Knl[l2W|uwNjֽ{nw7{Sww#///?a'`F`x{˰`C?}Co{?{˕8 ssGzUesw`uSO&**gu]M=0 |c{Ʒϛ':Ul3lBח2U8wx]?u|蕹>΃իJ=R6;^tC~*w_ c;=[Xx7}gV^g*lJg{s Ua_ !ݓoXMᄊ\F_n:9\W:lJg2KW}} ov_N;{ur7^0U ؔX|D +oq?-Jp9\W:lJzo UחYeCYԩ'`SF`2? We}vV^_2lB߹;Uu\Qav7-|%nk9B=P6qϭ/úY xM">*YWne# *>o0 qM97u~r{n}}wO#}0XN,lS6)唍rF`9e#XN,l?)IENDB`nbconvert-7.16.4/docs/source/_static/preprocessor_inheritance.png000066400000000000000000002002761461373220400253050ustar00rootroot00000000000000PNG  IHDR6!@gAMA a pHYsodtEXtSoftwarepaint.net 4.1.6N IDATx^ \E{]y~3lΨϨ 6n"n nbPY B dc aY$!d!Y#[n HqFsBu~tz]tWYnS9 `f!`f!`f!`f!`f!`f!`f!`f!`f!`f!b7ntVr}}}2iӦeY`'tOq7oX37~;agu{f5/w< is7zߟ|!2 7Lz{7 $0޴hzWh/uXu݅ɏ٪?n27ÏKvw@{@[fo4d+ݘ֭[}>f!_7hUE B)(?jFP,zAh"_f!@2 ^GPZY:":E B!(eA/u #~us!(e8;埋aA=v߹hfY}tyuW^xzɺrt, xV]9gUW^Vǁ2 ^WoPT[+r7 ᦕA+g%71ku;Ehu V]9b֕m};}.7MX"_f! IT S^ ߚ‘󴮰>PUG}PzARB_={EѶP*-} r 7l:uMHuǟM:܇-qok><.Q֧굵r@~@'(w˪ Ł '7?^V۴ܷяoXp7':2 86>rS|;܉GKַg/G귵ei׿i]}Զu^1F υS+뵖5WQ3'mC0~t? ڴ rm_ɯG=Z6<ڟ]>BR΋s}3O;^.ð{uڿ;AP,z]=AQ!`Y̺PX>?a x ! j ra;ZEWRxG0ݶrEgzD{>jZ<}g,>''^KM,}< ]P8aHm<(iPSp ׯ֋- K}F ls0xzm>i?n|Z><_G;iu~ΟTxܞ=B=޿Z2 ^WOP% ,!׏z+):jׇO!$|AчG!AQN}:|(+}9cÛ+\O|^Kgp9m/OVW΃©}P9S~~FEeA1\NIe &WIf&<7~\<|6:8,7Bm^{RҲ}W 8>#k[/Rι;ut|VY~ӿL%!>S߷1C~:y|z!(,z]AQê@XQ q>SpPx{OUӾRMX班>JxnT :\m|yXuJb*:úx[>#;nυ?Ruz% ~nVϨVE B5{|PPA/uEԂ"_f!tCeE B!(eA/uEu@~@#(CP,zAh"_f!@2 ^qF_OaA/{Æ_.2dƟ2*CepoXp #wMw+&CepoغE袙_-+ˏeNu='AgktΝ:m a(험_>-YI6TL.{+fYyb 7efث׫O&>iR=vf!C܋hz\>M|ۦ?&zY'fO;~@3 nbK]XG !g,Zuꅴ£ɦ 2. ',dCA/\E@7P CnA[Be)7EErzZK}A],2&O6xVS}guk)7=v-r,)@`3 nxVhQ=y$zzKyiET-sؔ¡nS. >zk){Bө0 />1nX49!QI|kMѥ mPx8_Qׂ6{Xˆ`gzh]ڎ(f.'ScrH`zDYtύQ=lrEnf  gA6 ,:]|3~:[Nꘅ@ CBc\*3 N!0(j:n*3 N?;M4dN@}B>a,̣Yt*@vBSz0(2@}d,: ;f!Щxt1 ND&D<l@''0Ƙ@'}d,: [f!Љxt2 NOdy!IT,:  {f!ixt3 NOdyuIT,:M辸,:Myt0 Na0(qP;$Dg()ꙅ@'}4Yt\; <l@'|H,:yBS ,aP}d,:f8AG@vBS>,:Eyt2 Nh.>ngG\f! ,x [f! xteyǣh>;@@ŏc" 3 }4Y]8YZz83<0 <ݪU\__֬Y'w=ȳ}i}!/YM;͘<͛6ySwc-kc5#v3N7L}}!~B ,>[=# ?{|xu2Kx~s υ?9>69?H|n$u ctުAPDӣzku8GZIS E;%zz,Q{ą!SBٕNN~Tko(}鷣rn_b/RX:~[j=~ U[w;/O~ Ƈ? fK_Dmsar}vaXk} Mx, g_) { n ž^~uC-oea?0,ص/gщAQ=w]2@mܒ~^h;B+(.>s#M*)g 9}܇B֣p6?Yc~T(Ӷ 2 tEIҺp~:Dyb۾LaOMMt :^_sA-wimq6Ph_}ٹI>xδos4_Mga۪ϯ֯:(vXaX,wުEPDӣz~ĭPzvNS08`= A{Io4$e!-3cExهpJAQ =*(<c-υvw VkY\^}mm^yA=#O JAQ {.VO>qHz~s'*}/u~ǞxhQMg?_m|i MǦmvnF} >\B//+ZFpv{ﶔN *~O3>h+(?\F6)'_XO8mcήzrqBZ@^pt.27zWS[=ji+\NǠ6~o;|)~{>c O.;9}^VQpʥ2uV "zB<+$vV'(s儁) ÃRϗC8O?8iAQ? ,ᐨzηIICߋס ۄ|b-A1,1{=sWB_oaM'{Kzj :!- TB^m.B#NJ?^j*S^:o ('}^=AQC:j\)Ȩ+lÓqp)d a̐GGoA^=Oz +},mW[#A1^6T*ijg߰LL=* 7+ 2 uڞzU׾g?]^mz)(xX7aW=~ekZPQMP1*4!Y BaW) <Zp 1Xmkx8,мz:izJ|`Η:}ov25ARO~G?PT@cp=ǿ;NÌ| _;}Ҳ0= A'b--m?m 7(*,i& }/u~oǢyg̿i? <vhQ;_wW u,~y߽?ᄐ' :f}ڮ/S^ @0*A{eLqo+e?wU؞zޞ?vL8]?{5ų'M_Wo#K>*'^u8}/h=G=W_vRenq }~t 1>˳sn_ gx>y ڞ^=ܶ^*Y^yf]RlmzF? B¹-ơGC'x[aO=P`Sᣚ(Рk~yOLͷ>j#Fe>l21j~9΍8Ɵ  ?/8rgQ zz_)(z,w x{ C 2SMP'ޑS{^χ0x:N-V7' jEU G¯[t ScP+(jeu :1ܫW3\m¦Pի/ -L?wm @GRoP8?@և!DZe|>^}ZO6~mFe>l1Jxn~mڗY|ಎI'}/w~qmuq[.^!Piի,[Uރ~*²>5 1qy SX9xewIPx{Jm[T*Sh DOUur :BuX2O.sm*ժ ?Sێ+jGy^ÖUwyXh 5RA]OaPԍ6BP AwucPlxH4D!(Ynjlyzr.:yʅ#UGK +2"^tcP:A]O7b (q}>$js\NE:E=jy}tGPCPڃ'A1/@u@{49 yytGPCPڃ?/OYd9ܟa]igY?zA]-V\{{j#mZs[fM򕱿GYXj-!nw, yzti&7o#epWeAŹgXH=fw,-Ϗ ]unمgzkϬt{wۛ]ݵn錡;28^$ AW֯7jߗZ@ŏM^[{[|EnIڴ@҈[&2T C~0ߛfX^x7nCӎww%A$K}H?dPg.8=+aOjeGVXᦌ; {z݄ǹ7& `;8GfVp,7~Ovhx"Kf޲WGd[d[zW'`0 vz0&^y3|ۺukj{{;8~a*>pnf!NytcI鐱jp֩ U`r鐱j#%_,)~tY ?h3U+2fuH J' ;`1 v>Ԣc+V㖥3܌iSUP&h ոe nƙUG@;35%GjtR˔q'p=ЀF'L,Eaob݇ѣ ;I-H.kRz"ǟtc)CLrF]Zdc$d?O36mk֬qGcR[7$^ڤhR[cW5E=ܔ|ed|;Y!y2Ö: z)ԲtD7̶o?+ٌm 6]|({eswzC~T4eYG95ۆ`ޙ@W,E r_]GPܹwq<, 2k&h1 dS+-g\UGP'ސ|IMC&9lẅ́;xm4 w0Bxt_gW,GҺzJ~fgvr|餖an*Jn}d~y_X>|`) |OK~N'y7{HT~f+1ye,'L:lwM7Z}u{Զ\XԶcL=V0,/~fE=MMItR˙CuKAږ V}YR3Wz:O/l:pse~;\ߩ;W>_3\nTif%[N4DY|||ۦ?&zY'fOo\#fb~JF`>7Ž!Lk3 Vj֣46\/C^Cѥԣh@ѐz:BZ6C t '|+(Z!P4䬞ENWi!1 z<`} Ϫçnm;Xf{;-r,f'MِRO/hf=O=,; vSQycS N(ɦy'(ZP=,ےbnȒ;P8pDQGYJ3գf97GGz{._= yRO ^l.W&(V҈;wf!*unY='#> Rl* vVે֥x;@%*4jrJӿ'2,JvYJ;+^oO=lG \N^mjw;@`zc_#{zz}a3j-rW5`= Ҷyo^.;DLBUw<{wLw3@+7 ٸM=tc^Ol\އ_~oVS?aI4=O|wy,Z!pުM=zYB' hM:i:>@+7mV/`\_JA1Ef!l䬞fuozY4[f&7c8^e֬pY gЫBGe_mm@B[{)uƸ Y4[貺M3z)ef!Lzt_x@mBGe1DnhY4S3׬FB,Ĭ @/3 fjƣd,kuf!,xt_|}bVי@7ZBO9BYqSfLEX֓Nz (ӗuk5`hf<7ۘ@3ij'O5B Kxz}fY}z R_`3 d=$>1'Yd%`Yd%Ge}#(,6>2 d辬o 3 ,=]9$)V#alPYd!@OB Y?/\'|f!x"+ϬKĽd߭Zh5k8}_lܸ5:ڦM?eB Y>jٻ/*ZWG뒅 ܄܌#ݼic4ݘaǺe˖%_?;'Ɵ0s7#c7~p`Y]CYftNrl.,-nSyslBS~s ܟ:SanG7,a05:T[u5zrrwG칄 9^陕#2vք?@7P`~qnɟwhTVBPڋTk [y}"(#(#eys,R "^EzEt]|}bOwAh/"P=":z wY^X-"^EzEt,ݗMEPڋTRM!FuV#Ae3^_ڵO6F ;gqy/ם@YX^y _9rՏO܀/zG8`}O=mY6q_[:ڃU/`Cص7(*x9SkQpďQdwvw@rMY$_w^_ڥpws Aݧ?8 WG퓶;5 ɬ1[n˝̭Sp/~h}O>ؽޚN{ԾhϾ?Y}?;,GߓG;-n>)j+떝W=A'^@p=>Q ^1ӽf1֢ܽGZ ] >l?긟=zۨ׫F/_οp%Eۉ{ Es'˅mt.i=jR__X[6_^SYxN{|x9x]%<q wqc{x\t(FmWxsi;qyús+CP~s;=u˔$#׷y ,ls]߈M_Nt.TWu:0~ȑzau;o:^Emvny nz;̺ BaXnhx^ao[7ȦREঠv}i“/'({IkP_XGӗnOm?gZΗ(Tɷ~ m 2Wðka9QϮW8>mk_z89ԇw(Iwm}X,wުEPDGog)mp]>Q Hl~X}>Q? jOP߿B)C+_0}tQPO\GBo(i>zV%{ 䃕t@t::z&>dJ|gSI}PT@mD3HQ/^]o6 :'>j߰T7TşG5sն^k:{n8P5Λ1\qi:-cA"AǧH<\+ j֝|ԾiX񽂫/;)='w/]hS -`0^>_e( ŏ(WP=kO6u^ }2z9iʷz~\zrF~0~ۖS[: NnwBᵶ}ZVLiyA%لigVŸ7G;,¿#9 ?2^C+6\PTDqOQ>N)<:i$(=^Wpyqzi}P~ˍŠt;~9Omtt>6~IWOk6RoDaT6zQSgՅ=RvQpyRk-(Hĩ~}A{xۅ |Y<\ZjQ0W/RRAQPkyJGŁ[Tvְmtl~֧]hthX*k+N 9*Lu F3\[)mjz]Ղգ陬U=AQ?>CCޫܿ/P0eԋ@.uoSOP= JYEά{U uTPԹQO`\|5_*(;^._Ek|S8|X%;o~¿Rk-C CzzBV=T>0>\g<+ZBBR|:$ m jDrZW*h ZrVW*(ZǨ*k+tu\Yu>,Q@Rֹ7A='GŁS=qf'(o- +G?^w֩^ԬP/~:7uXEefE{)qPh {vjT~vՅđG?R dvolz6n>S7LƾaV];7=7Λ?߹.yn *9N:eOrFZvC|*nMOAN7CXĴOVPԺUer+x~?zbVKEW3ڇt3;௺?Y[p29}?ڶAOYcvUfm[GjzMPD g*;ۻ CبÿnG RoPTֺ@fE?`rUkB_xQ.՛пB֣뿷_4, ? Tu)u z~o|u;v}ÙӍzӓ۽Ӱp( 2q`$F?zzdڠ)-T֧ -}mJu} ~?NAQ;cXpzFtaX0clh}J)])0eE{U֯N=d~zh=E ׯp?G֯TPoD뉏=C|E}}xE}tt޵߾^ %(8wH+O? ۵CpPd;?M|<[*HYmPTd`+6+(}w~(MmW.yZtĕRAQg?'ZO|};zt:-M=.;Gګem )Y=/^O+Oz(G3ޗq(DU©@nG|`-)\1&N>./ZgpYq}xQV\{{f5ڼnS`lC7L5dNʽcNL@zt_v](6mr;<_~,ߟ|gdC t/V,:b6q6t׹t[6^oȎKv˾7Q~ K&ngOu3|Ing%|BZY ?{EE먷W2K+_=-3mtɜKܟWejs1`{h./]W>fk+Op D-nsRn6alh3\IY3 j!c=/\OOD>XMwUWM}Dx{?2{{gCw@5zt_PC܋hz\>VHvFxfǝpS&2 jdlz&۲M21yKVmo@eKg }qvF>O cU|𗗹17c@7wp2U|S[r?d,ţu̺n6ut X8Tw*M9t XxƑf!P,ݧ]zƏ< J'@q?0_I,;ABx"f.m*j2 z&h ոe 7cdUI-:B`5nqdU?f!PI'p}"*itR˔q'p=ЀF'L,*}LAo# ;I-H.kRz"ǟtcd1 %k{N9I-Lb1uMjaKg2 JG'T5kָ1`)-q@m?4`)-qvѐͺѻ4徛.4CEXfN?3Y^hR˽ǘВNb9{r>Ya0qJ>Xl7m c%ùPp c%ΔGPf!PNzn֍ޥ᫝ԒNb9eT.wI-$1'&B@9>MjV9ymu4FZUzu[xyt(G7^N<'^OY¡yr&MNjvgn$g儏r\_I=!rZ4eIS{yѐrI-26,J}\ytj=7Uo%OqL{5eCvF{;P~dDMb9﹕7df!PJ\9Yϼk-뗸ԍ8 sRzGQ:dz{xI|;YA3Ù(-^3{fܽ|^)'R5E=2\F6:/YM ~)akf/_Jw'(y}Mv'󽢐I,i|;h,#; BFhDşaHuޑ|?GEZu3Xm[YXa s}a8cZztb)׍jտt'sNyX5e1uL;c.ɦyW,E[;tw0B?,W*:lwM7Z}u{Զ\XԶcL=V0,/~fE=MMItR˙CuKAږ V}YXQv|m[ײRz:O/l:pse~;\ߩ;W>_3\nTif%[N4DY||V ;֡V_Ȱ31 OהA֡pf__Kɰ31 G'6;1 @Bk̖d,k YV ;=(ҵaggͲ㧹4aggOFe"K<6Ya0 i} f0 i$5rmc}d옅T&ݏ]9$)6ag,$ `Ld[-6֊ag,yt_+[ȖY4+XuvBG= Y׊ag,Vmn.0 @BYVNWmަU'j0 @B60[.׬gP3 @smn6Y`0 ,X5̰3a'2 @똅ma:p9͸> ;:f!z+Ϭ+ b^g_ج0 @똅]q;XS h-f$Z0 @k]NHQ_Y=} ;Zf!zW?ɥ'`3 ћ}t_5ւagZ,DozX|}b3vBzޠC ;f!zS=3YTϣZv=Bf>'2 @=>/F ;>f!zO>n{텬E<@azoS8V{p !z ]v= ;Zf!zO=k ;^f!zK<[e>ag,DoZC 3T;KZ ;~f!zK=Q،4ag,Do}qD%RO/Y?-ag,DPO`ʪ?ť/js[jk֬qnWewġI)S\W+G蒅 ܄܌#ݼicݘaǺe*?% @qfRJ|Mc=~v9Lwٜ9]r.GnNBnWh.#}xnA Yjyh+_'_~'WמYN6mڔ|u31 ;j}J7F+/BK{ BZY3Ola+[k61 gZv62kW61 yt_h_;uRZq Yj{km_v ;KAǸQ7qn@15ms׊n/uPQCǝ>u}nȧ?@û&:Sz]߂uMot^zwo_G;i_^RԶR,ֳ+3}CP,DwZG'j:nSv ;K=AQo}s:5koEm]yzമ8\wYEVcN!29($53( vQ?,^uuԌP`胀z:lr. -]XB :>΅zr_&>>m+HFhSpˉAu jzrXðzzzw֨º׉Ω_Vk]aX߇Λ>F (a:1'TROPT;u+.8- DžO?amPRH y* C]L XUTPcAEw4k9p6M2aX>AQmr6}H_ (߫,z\蒀ʹǧǧ@mǰǭN_ƴjTkZF}Se}YiYE)i9>(W "f![OOmmyK59,R+qk0H(8jSY#AQV?cKeŰSP)ƽaz)ËAQm\m߷:{Jὧ(<崿 M/u>tpW^xzF"zq.HYǭ*kQG xc2l7kU]<.ݸhZ8t+8:aZ0 !JO@WzjsY rf])IQ?V0`5*Uî}RظiޠhՇBu_t"f!O-DT( fag!(YS5>毒 ; A,E=Btx5Fކe9kW?HY4饒&yvM6N6z[2'_] yBtZ&''2nS<;{7pd@hWovnzzv1 ]jyt_4 &nS<;_ƭRw™ȡ.J2uM+/>&s7]}{&_U Bt}zjw2/,+VpSo:'nwF6nܘl.jyJxSnkagt# }X|-.;lļ;s,[-? }1yKVmoYR!FzvF4D\c%Z6\JZ;I,Pݣ,Od͢G/vl]Z9Lb ha`+7Uc6uuMja ,Dw};lk֬qGcR[G2^4!sk] hMj Ph$L^wX#al27oX3tK3`;TۻU/ hMHvRK:Qbah+׻WmJvF+iRK5Qϣn/,D}pq /)= +ԢXۼ~9Xf!:_T'RI|#h )ԢI,N3 G.fع)fZrwDWQX =ԭagYW6 {q}5v ~UzW6opϯ]䶬_➾R7☃I-i=xPFm_xdU d=|ߐހRa97i Mu9e'h|'NVioY_XocعwĽ^3{fܽ|^)'R5E=2\F6:/YM6f!:[c^j"KqJv=MHu꩎<0^hC&,798mJ6co@PJ>OCҾMJvMzRTxZ.#(i| GDMbsw5vc.ɦ@3 fx>0ܛQv=տ 3y kg|3cni;ctRsܰwJT~^{%>~GI{?lՄױNv#{P%N~3-)] M9餖3Gf:-xbW KMdױxY 5fMY>"*M~Ѭd+Љ(~=qNq@zy4:!jnSIxoO}Z/>|ۦ?&zY'fO;~@3 ѹ@ks&K: Sg |J]XG !g,Zuꅴ£ɦ 2GU&+sdLN=A\4EV4A :_|-:{XJgknc0MِROY_{^Jm>1I۰sۙtzJ|C SQycS N(ɦ@3 љ>k6!A4 hL#-;й̐($&]%nn\dr<쬐tea MVhfcaˆ`gzh]ڎ(f3?VN'ۨ5h6z}S?DtFGژLq%ļ;=ڷf *nۼz=gYjg3A q0tܦ<;Ƿé(-O=ǖǽϬwpReT,DQOa,'Mڙ1apn@s,qކcs0 N֣yt)yv7~/YM;͘<͛6ȍㇻ1Îu˖$ȧrj&[1k~;t7>gW9]@noŇorsϛY|{}a*ԵcؙP'?m3AN~Wm/*gV3N6mڔY| gLhK+NyEt"ЛBK|nr3cvv8i@o2 /Ce(U:Et"ЛBKGr}bNu4E7ȗ8I!REZ5pGPD!(,DC_' dX@pJ'("7Mizi향3̶h-"ЛBG +uay׊ag3܆mN{J}8Rsv~jr}g>X8~C.u}FPzY(әayf ;s;4:OjҨ#ʖΟBڨ ۋz9SG߽,}KU:׺_㳅㶞_x} _|48~¦Rm.SW|NxU:^^އa]xJ@o2 f^tX^v BNzO T_)}N:ynrV^Rh*Sޟ{l߆V~oz0EQ?na_vVZW&&un_=;kQ`Ҷ_VJcxN_âC~97Us?8gz}9c:}&_' u񏼯Au:vݣN-W&lV |_)*+w}b?vEXX0X{0>$'?ڹz{{.#>TTEygL/4i㠨}RK~xTs\ ƿ+j+*齶? wN_WoTşJǮj9~?N< uO\ղ:Xr:Vw?xjAPzY{z@X+!ׯ4bf^U֝,8hjW/8)t(\-xjaP#AQ=b vj냚 KRE3魽eA澛.L+(j6u`ZaT6^cWTSžF9m/ϗQ (8Պ&T^N5)m;cV*lV E4Y!G!-"a-+XA1RA:(_^5Ǯ: %:թGPRu.Y3AMf!ģ΄奮OqKlbfE 7*hv>aI'mj ۇ^|t.{@dNINX ÍT t\bE$j}~HTP|Ͽq Eezr{&cwy܄G9^F:6HSOaۏyk"zȇGPu}q_YO0v8iVPTXu+iއn4]h' N }{$]pZ !F#C}fkXտ7(Vs\VPU:vՇK߷#ޯm9`=)$^o_|Ne"[ĽZ3N %NA#~(Ӈ ppƬ(,ZS ~@f~Cj;zc ;.Et>s:3AMf!bp}9pQOPDcgT&ׇB^m'#(6&g=Dxl#\w!(s܌I3Q="ЛB_+,\a86qNCPzYYkְ3A&x~ZĴw0*\m՛i@o2 ^ CY)8iS2^EPD!(,D{œF4Ӹ67cؙ4A&BjOŰ3i": AMf! 5Df ;s;y42GE7h8yC{+6cؙ4ϊkq?x ͖_֬YY ÙBa|k+e=pkӦMng?@+O{нB:f ;s;]_~4NN+-]DWh}Ozؙs7-ݴl^b.,Kgg^ܟ mdsmtGz0S~t?E,fŊnʸ^znƍMs'ˋ+Hvv8ȣ# }X|-hpY={0pܻ7r-!A^-[-? }1yKVmoYаo;0'N 4DzAg9Ov8ț'CVYK.HVioY׿jN{.vv8; yNb3I,P%3?yqxj9yI-:B`5nY:͘65Y~@1ǮZ> Y ;s;tF'LwXf!# k ~apOjؙ᠓чc[פD?y$Xf!Z/!|.ag-4uuMja ,DYYvlV5Y ;s;t5kָ1`)-q#PY֋Ztd{:Ƿb96grMТI,3,j`3 z/ؿ}6vVcX_x^òeܼicP-q$Y Q¡,Im;n&T;%rʨd1{]BV6.QF&Ts<:BV辍*z^s|-dShRbCoLbhxbsY?sagnn!rZ4eIS{y@yf!Z+ȲnWܺ_.`Z/QXrwDWQX =ԭagYJz8U_qs25؝~~f;ʅE)犹-;Ϲo\aaޤ`^vxeEn%/u#9ȜԢуmN?Y^@fa+(N87a7snnsM(z?3vf]T>g*%Ɯ;s>fp7a8^ az[˸- ^QZNO*3 M!쩧ǹ?"^pwܼ܍9i劉f2{/'SN<($jzel^u^z{mfz7˜nQnCr<f vHѤ&9g =}YfmuŢ_^:NݘF$Y{KQfժuAQO7Opŝ>4$j˘c뮙tsPO6eozYLSot?\sFwW,GΨ8Rn{욡[X6'mS6$&f6A#(чxdGT{XwL,nǦu;rQT[M^g6A:(Vf ճzq4gF'M6ao!A\ƌ<ȂmZ QsRˍQD{MN)wO,lpUWKCvf'(N:u{1߉u{L͢+6jc6SAqWQOͽX^Kwo|%EOhP~=ǝThƎش|?;u~z+_ڽ(,*i>B=BwfK_ح(|_:/:v*cbVfr!w=Y.'q/fu:1E3݋M+ދ/;P$$i],|PzŅ6j`ۈ֡uOB/|6}[φ$)qB^*k~;EuZVl٧ʬV," _f7(*05@' n < }rtMZ.'v±iTKVPrw)*[tY=U5-Ծn[ɠxZ2\>),aCu{|i{m+>o"(jH͛503g6S#YN~|Aܻg孠(JE !~Ee ײw|M밍e^k|/z^؇B"C?$ݎ Kxh4(r,lcV=aO[ Z*z_jtPzcXW*= lQb _}Av|2xIuڷ#( YL KZN=ma M.J›ˎői`){C5Զ!e;?t)ư7gom[mu9gV(kuPv7tZEC n:>QxRSa)}I j}~Yօ⚜׫P᭨Kz$:`}SncemmX/ f0 @TOPuvSNgy߽}qHP![bXws/}'\А׺p[q]7(:C@w1 ]Fx a@g0 ]-w/ 3f"(vYzJc6AutEAq£ ],l7?:yF9Y@g2 7C:M8u\ڟ3lfaݸ ,#?gf֭n~^xa3 _[9ns . 8t>UVݭeZNo3qJwۍW۸% ~~d綛ݍKm )v9iۓ\@w0 a[bzI{_[q';i޴ZyM+ϬK{n36(mI#gfz:7ađ^Hf^Wu T f!J[t[vf/M{°=,nSz5zY4D7ᔓW-Mb9}_=7Q03!JBTI-:B`5M:}ztz%z 3jI-=-~p*],jxbf!*۴is҈&'r!{{/<({;@3)SԢI,SGQSȫuk"Ln@#BTg͚5n¸f,E=nũZon@&Y} -2'u3Rvn4n@BToٲenf(8fcQv8\zYmݺI-rAq~ f6Rͭrf}z yn8e;C}hYl2 ^otUw^pf!j7qe'h)?[; iS'd@T9UBnS9S'!QXƜp[grP7}^|&7笱nW?=wwdwʈcB&Ȧ# a|P9rl)N~ʉN͏w,@xa/gA/4aEZ^:͙|6iv7 3%_޲И;^Y*#(i| _&t?qLmZ1\.ԿdSS&Op/=v#1[6@Ι(ۍ+`) = s+'gI-n ?iګbH6iZOAOϬ44OW3 QlvM7H'5~u{Զ\XԶ}8 (fb t8$>N~t}8^-&EPY^}13ybrps]k%oE@(ғYԫXKXTH,7|">ڇ4A7 ?{]=pˆmʆĵ>1g@s|3 1ӷO3]LT-sYzlJP)E/<<ٔ}Ah."of!l!Qݻz~sMGZs;Lwk.c9a5oɬ|bvug\h#(f-rYӷ4$<󠞠xo!~EnYzewMuY5Ϗ^2NS@qw ~qrm' u.? >_q?wb|3 QH`#*!{x_ߐl4_#A\RR/WX0Mbƿw{}i̗R˅pʸ{}>r+qFQ%&aq1?*i1)i}z]i;z}2^k{w:|CcZos#=8}_Lϭ}^3>J=ZOXχgmmڇuVUUYi暁5O:mZ>mduOaEy!Nme ~@W𗗥!|mx}7s1m+*~̠By?B֣i~Wm~%]tZN>|v[aNCYfṧrQO{a?+=7/9'=z[ :wVeKW՝>(w-wlvymt>; ^Wն96r䏿=GrNVoꎫKN}h[~۳krZE B'q/f{~2aw[{'ܺ_IßS{6n\pЀqb5P> oƒ_G\=d֣tZM_ߋj~qU1鄢2O!LˬeARPRQ`'}wt{rAzRZn?Mߗ:>{tYx=H?w^ڝ7ymh[~Y|o[+W(odRw*AyA7Xsn3>-rNN- }WPѪpt4}YH?Ҿ~ crAT CVar6RU^X橭구7wEgm} k4(*s`TRϝBWx^}WBچ ]WO=ZOڅ%{鵯 " aBz2Qc@sIáb*y}ߔOeBA b[YCϞƒ!Bj BT ézz+Szs'-*|oYŸ+Ɨ~i] rFmBQ/ >ihQ"2g?rD#)k}R~*j^ө:&_c9 C(6ޠqVMթM5^*(t\;)l|~?E~oCa>/߲tƀ:SoE}^_t^U @3 ӿ}YAm=7pWKDiEx֢h>0& *ķޯ۷ m.a^._n9 pŇ?G~YW 2*;۬fe^|-۲e\DtުAP,DvmA1~xڛ=EpbQ;gtA7Ͳs0m2_. u6B&/6A5Y(MN|ګF/[By@P,DvSгNQ푥Gs"(f"[=Lbju m najXa0^wH@s|3 -{|^)*m}o@2iGPYliB)jyu j&MVMkQEmܸ1ل]A 5Y? q]i8Ax/^=b{W8(YАrx^):f݄ZEòWGdۘh>_N_%wb܋^F_Nnp4! cU|𗗹1[&,Ds -񬠨=ky9_,xٗ{; w- GvL<)2_-:]pAJ{;B4ST`sxb8, w*]:_D4T<~fV:e&@B4“Nq͙aV^<j~ͦI-:B`5nY:͘65Y~@1MxOMd w-~褖)N` ,DJ^h7/H1ÎkRz"ǟ>kGR{4l.weѤjnGV'^PYma<\=](wz~1MjSVpm^I,ͥbt"ϯYTx-vz;I\Mj$sg'M噅h>~֜ -wiᵔ vj)0r;|V{u?ŝ3U$qCu+ode|) -z{J@wMkx=ptkGQ+7.r[/qO}qA4<(m/ r^(V.5,rm;cQ8 Ͻ.h/OC_hI-spW=y@/?ywJ{;B4}Sw.LhWxᵔ~pWΛkf/_잻|;CB&[U% ,D?NqY)אk 7ᮖ&qb{o!ey_?ly8Lg y)ԲtD7̶o?+ٌmAS6~¶M7)w;?|/씻Y^Q\W4>qw]#KC&9I{M׏1 dSיh ?QC)3URxCqz6ݨpJ'>+^z_0v=S>V;L'\> ;pLugUWrw$zYdczOu3RxZ%l[MnRn8TQmtNrZ'witR˙uxOQږ V}AټN1ТTs8AF*Bvr/"?*M~Ѭd+Љ(~=qNq@zy4:NhukVx^Z%Jҫ X/>|ۦ?&zY'fO;~@3 :S){=<BZbh/]j(Եz(rVϢU^Hk}ޫ/:Ȯ zŷ rH smZY Rp,79!QI|kMs!];}`dz%\F;_ҠШ);vˆ`gzh]ڎ(f4(ܣ^?jSMDb#6f!Z+Т -a e/pQyUϯ[6kBO{mFjg^9;NzQ_~:[NꘅhxX[_XĽ;h0?E_(mIDM@B^w}]s?rxj-=hFuxMa#܄,D3 (zzpjh~pYVf!# o-:(̅Cq԰F|;]0 ᐲ^KZg0snPY' ?Kܫޯ,D{ M[4:oOu{h0=~pwkqЛBO uð,b9B"çoV>53'=N}BO<ٻS3,:DqO|3}|b<\#MY0ih ,%^7h0rV܄BWܳ2ƷyuE?Kmn @2 ^ ߿ӗsJ-n@o2 ^ %W Y ?K|n @o2 ^qB`&eX_W_xh]B",D!M3+](Y ?+#~f!Oׯ+EͺN1g %굌e -{ e!F%~_,DY$VNQ~gS 7,D$j&t|ClY?kp}֐7Nf!! hLRus.&_%gn @o2 գO0f"g=,܄c"PXu d1M=f!!HunpnzY| |==Toa3JQOct2?1,ubt!kY%ez 1,:E=qBG܃jSlA5J/f!DaU)6kYJ@1 _rHQyI%~oC",DLQ:xٺb 7,D0a.˞?Ͷ-YX3 /0caYجg&t/Rjrk[ 7,D>r]O 7,DArb3%\pn:Y1&a8+S>}ܦ,{-@뙅ȟV4GT%l׌ 7wVr}}}l͚5N{ BO#[XSls'ބ[?F,\&fLM ͦ ;-[VYC\gh3a3s/?zs]hByϛ|U/3 ?ͭ@Wūm=*Y\fECN;_%/ݤCܦM=\f!) _aȫeHϢn# ݽ7^h@ȇ[^Y|C/:xvr3Bg ML~-|x\Y|*5%¶͚p߄[O۴b:l8ȇ?%Q">f!) {JnCvnE @1 Of8Z1,vqv"(Y*aJ76kYp@P,D~)Y[5p@P,D~iRH€W d1l߬gCi^nMP:AhUV8q 奄mvj[A E}BW޹R)%7EGm="(Y| W89o+ՃnKݫǠxܪs̺J?$دuxvÊt/qr Ah[!0/9, }zb0dD֋ $lSY)HZ}Cu^x)k_+gxt^zurmG~霔kFBodY|qÞZS7Zr z8N:*zà |խw:Q۰\U޿{Y( 0j~oNY{CP,D1ta<\kSP۴Jk)t\0mtvE6:mg?2_E >>0;oq}|~6WBP,DRuoĽ wbnP+I6j 8zO m z`|5b^?{~ar?#,ԫMЯc>~H˵ ǥCB~_=m mKᷣj0H| KsE{ uG ڦ%~uLRXT;ʵ0j:8&\6gp6 ejDu~Y}*mtlgN^e^o[ߵb^Z_ia^a:Qj1 oXQ 'H:KrFz|7lP^*}^8L^)dֶp_g_D!Vz'>7gօa/ÍpK}T _E!̗kuδ>;A1@+?osq6 c ًڄ7ZoNu Ke*jyzwm }߉ߏro;,Ze~{U@ȿrAKk a~8&܍Űwk+.8P/b^ٳ_oHU*(*I`0/ZJ=c ( $* m+ =7_L0-zԣmãu)Q[P>(˩wM?DϛNp|7[mJi^kж=i_}])[mLuzm]ՊYVX?E=a%lߊx\lrZ9\*` z_*(Zb[ߥ# T@Rv}]n-)K9O=]ڎz|aKu~$e+~z&\YmJo?kCò y+s)YւY+7Esa]Rԭp2(.=P/q8B뽧`W}b[Tk}W?և}vG΋q^nZׇ{KѰ̧vLuJ}oxPxl)Ópmt~]O}$}Lƴ3m/k=smN}gEP,D ac9Oieb'gMS+,Q *:%'3c&(8('1RÎ|wu{o}1 z2ߔɅziKO**WP M ޵x&Ck{R}ً& ӹg?&y^Zn_ ?{CpQ7xz2ߛJP:Yn0XuϢ[MJFS A 6a8B0*.m/X %Ç8(ƴ1L:ixb Q`må.2ڎ_Ft Ͻh2zJ+V*(ܪ-<~Nm:<<W&Ez_#qpY:j} (Fًo_밞t6! Xq:xVݶ&ܦ4ӡz~ |1ES0Tp 轖j|ύr2z-6{:6Puu@0Ĵ1u=f!:C<95 }5~־mEHmuPTOYU!Qlm?k۬ԼE+VN'y?yFP,Dg{ V=(n&ܭCP,DU<\DZpV?&E31 9JzSl&E31 9* /us7&(Y/ǽq]+\hVZ+"@&{b|oV?+̆ۖjn^+"@q{N1~nV^)qPUhܦQ3ϙܿaE}Bt0PYĕKw޸M#V\{M|x>f͚+k4Y_':v?K¬Muf?NO=+[=\f!:K|+ϬKKW=,q:|uỖW6jPh??דw\6_U,Dg{ +u&\qXm>`Z,DgfJX_Kj&ȟ+V)7{ s7nL6ao@Pa`<חg ͺ 7i!Ňn4C_=V.t{x;bf!:O Xu.׎gQ@ lbt$3c䑮/Y=6f!:OTW1w9y~nMO"0&^y3|ۺukj{{mBtJZ$g0f܄5ut X8Tw*3 y\u.׮g C 7KCGmjX a T,Dg cWI~aY}n&h ոe 7cdUBt&r*B:jn*; 7I-SƝ$YΤ^0@Y k {׷JxUza5E=O$YǚRױ ?KܫXK(:)g5I,P;[4rb}Q&ܽa͚5nc0Xz uKHfs rFpY[)jfz;iR}7]hB&̜~f>,D SMy~&ܽkٲen޴f(8Sg ,DMK#)iYjGRԒNb9eT.@if!:W<ź1. k}ٸ &Ts<:Bt.]s&FS{j]>khFtGZ+z/g 4,DRbF6,܄7iHܤMb?wv^PYj&zmp7zm?ŝ3U$qCu+odeŽkqTr6,܄D)]y{~on{K݈c2'qAi}ၫOVa0Y8kJ5Oq)'~lxԫns_}e/OC_hI-spW=y@/?ywJ{;Btj&dqaކ%=Bsnf2{/'SN<($jzel^u^z{mBtjC`ئk8p^l)>Ǟjy,d%pBg y)ԲtD7̶o?+ٌmAk?e%}5PqY &NLYáuAQO7Opŝ>4$j˘c뮙tsPO6eozY -l:E$ qOs|KY=VW u!ĵ311d:e9n؁;e[?{[#٤Btjf5gqb%/͈9@vY縒Z'witR˙uxOQږ V}AkU[:8lnQif%[N4DY<;h7whӤx?י|q+uOރ~Kb߄^lkXŇo6Ü\E&lS*PVg4bPYkOs,U%,*$vZ]-.u#,B^=}m?:C]ϭq5C ȱlOڦlHL)',Dw's oqȫ :4l/k{XwL+ u螊e#WR8pDQGoM6eozY\Cq:Ea7XMNiDyfkz_xdvŮ^a%*4jrJQeUi_=. m3 =ޟޫ]9A KTz6ͦ+6jc{T;%% ?wf /Jϯ[6kBO{miBtpp<ԓ\*a;/?y{7Ӊ)YnYOT)5Ev^OaeTa㸾Z ?Bt0)mq€WzJ~;.3yK]ԟusBtZzvgg:YOh)S?߮@|f!Ofu"t>ݧڞjX lf!O<\h 5r"t6'm垴u 6~>Lhv:`eĽ{冔Ng:Yr<\f!Ë( mq}(lhcd;X,Jh@Zf!S-f}ma. f!S-fy0 @1 ѽ°Vgۻx:^26=jh"vG[m6q $$ـhXCh:!_\!Ĥ !JO3{2OnթsNU}x;yN-7ޯrgYDGxKa_L?P~fKSa`w3)2 @w1]lh{b<8n,woc8@q"z[tx(bfM#y>6O|Ƥlmt̷S՛g%em~"z[a<tv뼃]:QJ?n{:E cr2}fo(?=_|<cg,{Kv[GY1 @E>}u_Ffe#Y{@EfYXnDV~\"C ۏ,3b]wX:Ÿ<@>"zÐ6}g,?ķmCK%g,?Z N1~3a@M1y#L?444V^\lڴ)ղ3'T}~ 'Ov'}͛1]<@.0 :ĿwE8ͮkl#)$>m{ΟW ~n[~:iN~C,߸2ZkFݍby3OsYAa8y~nάɯ{E85u>~~ϥߺo(D7?S7ɯE052Btug2mڵkݣw/9znnډǹ]v%z#e_!,j")(yv;'Zb_t[06BX:E gE:P"Z"K i~~&(j1/o#S͎B6}h'"Z"FpTriFoN?NEEfYWw?N?NEE4qK>ϑ? h/"Z"O -qk3ADPPYDro")3ADPPYDɲ0>')~~l]{goĚ/v?}yUK/e5f[A@-f) fV[s".]sU/En9VuZ?ރ֗ %@PPYD 6̊\EE??wMptRms_oW?VP<}7+~e/{1cF55|{_N9ZGmķA5Feþ% sxTֿPx<m _w|<~o (,?ߊwƤluyx9[]AQ_җ}_I0b_s*}3PuzAi_>~s6k ۜx쑕6zj/~R{ϻޚ_?|S6z?:}BzL^5?rmT{n·vx\?{EPPYDʲ9uOEEIJUM% % CԳ!}g$}MA+P}kZYH|{UScxץ3OVzVp$O_w&GF!?Vjw–^ϫ_4?}s*턎Xss a2\E yaSǭҙi0 hK#]SH_ <9 ^[U_,mc=N;.}FASm,8~?}1z z^K_qpiПZVMsEE05:՛fݍ碦FF T0)NO1ZG}y[;jS=pZ<!ևB?"B{Vum{LPP$A,r}sAQ#s \a8SpR0ủiӼ]SȡB^n,ϗ>^-֨F8QSpX:H~G&c_8AO[:>cHfkU]_S֍"6D层_<6q(m`Oo{۲nߺ_?r>+_fLNUAsNJ?sÂ5aT]_TfEJGc/'vWn[o9|<аwqpu=Y5c""ExtP6Gqⲳ(n5xYmb|&տO()Dp}g sT W\x+ZAQUݟoׯ7~?. :~̉#-~_ϥ׫um'((YDʺuYTJ0|M?+;n%ۄ1M/|zCDQ{ްy熯 ; AȿVXxn:^;>>"Z"FG=[%em6%(3%k!(,ѻ)3A9b߲N#{}؜Ω1b -N#+iv"(,i8 d|N h'"Z"[@5`6#_㽂v"(,akf9<~~&(j1@ -ES:mh'"Z"q@+m,YkFؿ{ADPPY7l:~~ruGA@-fxu˜S2}h,E-)S_9@3aLSZX(ZHynlVwߺg[7ȭW=" Y7qsSܝ;~~{ی?@vv.}W+^ٿ`ov)"̭]}5~3āM# q0 +V٧~j+6 gv4mj +jb?L?c&䷹gյ3']c/ b͌ nX<*1f6ܠ,]r[ 3e1od788tm_Y0532؎usi*>t7d/ҮuL?93H׌E.[0Ҿ`?x-뒲6W:E& J7L&hYVohᘪsfhS؈[sIT3r)2?Z2M0@( aL!!S.n:ZWAoشiv±6h$rlb&E O! +jk7gLZ3@HaۻccR5͍[v2 hRшd6ZВksѦo mb9g%lfְ]tRw0[8M,Ybakv.W60g!e;"YtOE2ˎM)v8GoK.e_Yi[O֔fmRpT@:zX𚋫]^4KAP6N{=*}i_KSu"00,d zSD*m+Y1h5jYކc+ Mahk曁S0v´m7tՠ:҉f~^פSg<ݾ!9d4,^AuYFo< ^Z$>x-n:,Gu hY@E,iuT,7S"Ш0e:fbEQyLN0@6.P|.('4*lmq>3@5 qu fhF|<2@3ŇQ,͈7<{[R:E,eS ȗYM>X@Ej#Nr1@ 5qn4kU!/>MY}N2@ -Yv-kY@gEYyN0@ 㞌 f" xYGY@yE cB^|S<"B]&utYk8 dOoķa"a€FNr0@Vy1 S3"U^AwPN3@Vy/d"g iD^c@vfhEZو:E,+N2@+avNq7&e-ȟYZ=[%em=S" P^+;~:Nqhhȭ^ hMR3bV*:x;(< ]7o$whƹS9r1@pH`)*$z (fhz8pU:VbXGxnӽ˪F ju ShSRMq{][}P|tU6=)ya~d2QU=4~ f^&|QP..z:?a|6ߟ}&~G_[Wx,~8<}[|h@E Oyaw>YGA(zO/J=Z7u~Nͤ{qZ\ikojs͗KO^o}yTU׎_|ݢc\~c?ʹG?׮ٷH?"Pnf1U.>ތk=ֵ:6ץS_=_B,wGޟ6k^KgV'4Xc}0U?gZ}A1~~ (f<幡[ u>CB6?í6w?TΑ8(\؇FvԷ('> iPÂ(mDƏlY ͪ)dǓ= 6#BBF|FE=F|h4TmEkh=sۈ}U5=V]?^m<}N v GYE=z z_z6 (f<[9uE? Q$zmB~MC$? ?ufAP,y{0{3֓ԳBNMӀjG,^H4eůKo6&h43JH07>X4T+i͏b5 z-S=Ǫxd2O#ֱ~ {_z:3wAt@~&(,y ]ZEho0PQgNHϗ?ȞF&@d9^J5ըsE?ӏV@­…6YGa5(jdP!ܼ %={&<5(jMpsuo5 z-zM}רK<+<s?c>*pc]ϏgZZ ZWP/07|'%cLeΞZ4FТs}HF{$kPt-[x~PAѿW^jE?͟VWWר~_ؿzz_u-s\t,L^\zg{a_ES>C?15TuLDSz>>6qc~ªů?BK|sk+QpcLF`X!y=MxLks4~ (f=]ruYb^4autFs֣}g4YOU~O}U`ܦU S^<%r (YVsତlͪAњJ%$oéh4Y>屮0 ESdPA(7!i.z"A(A(7!^WM3^HPGP,E{CK @@E]7{"A(A(7%`SYa\]NqϖuIn۬!U7 (f촁%u]n1hݿ'Gl)?53@Q`WI_C\fЪn]S<%ީG+rovnw;;?t6߭wmW+OY<68ayS&mfeh?=_%!#G;yےm]yb]ukO<"PG^Zb}ѩ>M:iR|=~f(RU~{wlLvFN7uЗŪk/rgNO,E*bC}yxtɕnɂ3Зż`ҵ}=>f(R_W(%CSӧ3Нs>hY:xD̙yF:elf,:4w٢IuEhyOk1 S=*35*2mXAf(ZmjԱqyn9IWvjf(ZU~MܦYEOKZfz~hw6[4Rx9H77ZΚz;mkQaks6hWDqH+'1rsq>Zy4?wfh"6HNP>?ִ aN6>gD&~#4IӺN<ߙE݊~x"Ag@Sѵ.6h@єFcx4,'+ZGQ+/ޭDAms[a+ ȕǘ}(-0YM@gGa1Ql3Ë́Ez"JB#aP۠<C<˭q񚉕[X/LڦnHL)fNCF|P'BYFkyꎹ#ET-s~ؔ¡nS/ zRߙEAvw69k.6C^4KQ"EmhA~u ڜ.Z: vVB}ij;Y:A# !lh)p]FuCMtV#9fTREL/7KO[춮oBOp۽ Ӷexm")aPT03:1z،O~tc̖ݳ7$ƘESݴ|")}0]@ESlhs")m0@'AtY: -Y:iⱕ(EE -e,Ć,{'A -tY:- lh3"i0,@"i=[%e-(Y:MX W~fx3Zh?A@E @gE 6.PuŸ (Y ̆,eohQpE, 8(YB}Pd3e7<{[R|E, -;1)m@"P}_,e0(U~Y$ lh}"P&UbEL -{Kv[6A="P&g6f(0(0@ -S53@h9 {wlLv[ Zh?Meତl0@AQ7ᎏ|EEv>P<*AQ۽-)m@"PFWyCCCnnpp]jӦMGi7QE;6)< ]7o$wKM;a8uS?gțY* |_cbstۼ/q 8'H~?w0)ğez\6?o禚?^DP9;i(Ko> YZF%(~NnwYE8JM:ʔ(*) ] }KgGV-jCTV/B{nޙǧy4ǢsSzF}y9NICUrMi_qE,`ⱕ(ޖ*KPT#q ` 9 P R aamW YBjKm ;1}_>cڂ^Wi-({v GywW'A@0@77hbܦe !0Q3)|) YBզЪѻpR\ )MWHP~DOO"nan"ZF5Jg?w%M*|3rЧZAQSp[F!]dPhV_qE,@N "ZF|aW~ʴ> [. DY6MXuNV]{`]bh?[+N^~.2(!yGgIP-"- ȆtDLa[|tW!Lm^?JͷvxU ENΘϧ]iʵ=߇^Gc_'ݚF!y(!((Y9 ~uFB>dy q&T g&׏̩o1߇į! zRQݿaG;"E[ZlY,(7"E[hK*jFPP4tRfnE6T#(6"E6bo#((YWFPP4tx3Z#(6"EZ6fnEv>GPmEE3@ngА{~~EE3@7<{[R͐j7pʔ#?wȃYMe7&emYwf@7[^}[q5GltxC/nӯ~k{fJSw߇WdAڟ9,FSaPdCH\{_7vG{Z{m^~&{swukڟ3,( lh+VpOJ7}x>EmX5uЗŪk/rgNO,(вg˺lEwYJdfbnpp0ھ`t#m` "_;4E<}Z>y9E;[<#2_3l¤K:"Э Ȇޢ1_M,&dn5pLըb|MZ4ulFܺd7wNҕ?YàwƤlEiuSSg 4,݊ -mӦMn fԢȁ'`noh<8+)mѝ̞iS XyffaPMnk׮uSƙa@8fn>(7iS7_jB6óS6t'T<{[Rۢ;-]]<f(8sNd d`nZz64%rʔ4/@mff턎۠iSK#ȣnY]*ޤM-+z[M,t0(wiJަmbY0¤}>>t;' lhiw>|c}Sd6:h& +txC˞-뒲[m',v=uOܤqcM-izܑi&{80Yv:AϭS8 S݆i ͜ sS9ܲ'htb$]gn|fCK>+rw_b;GUDmbH/no#[W_to_YzAdВ Xnߐyf pTզ%.1lzjekaC T87 t<5GE#O2ݝw݌HC6LywpnfRߙElU^Вxb=޻ccrW-~x<}[uAn&Բڋ Gt ?>H.i?gfKXX7 /~gE#4zzs嬩GǾ V|}A= th_+ t8$ʕan9Flfj(2zXSw,neǦu;zQt|ף%,@-7hSZ1b3J#;.}]A@u FqtxUfeݟ>@"ȋ[yq /n-E@^"ȋ[yq /n-E6 SvM/ '֡b;_\gs|nh0?tsϡbz{Lg "Fd /? φ͗I(-ms}{5I"F['#Oڋ0[HdyťoNm`>^O:P[ڈ@'(-mD6"@q@DŸEz"Ёb"Fz=@1nh#t(.ccj'n=76@W|_,]81n:P[h@mnH*{˱nR"tѨ0SP JCZRniӺ73Ǝ@q@i*t_4^PK@7q-@c>bZ=^o:P[h@/n F/{yDcm9Uvޚ_\4o:i(-m@Kۂ>I@MoۼM=Mǥ' oo)@q@-$Q(-mD6"@q@DŸEz"Ёb"Fz=@1nh#t^O:P[ڈ@'(-mD6R3n`@1nha7Tg "F +u,ޟ W~{sؿg "FsssaUaϏovˇn:lxivI"V333aatjc'?ponŲu%pȑfcEp߾}s vV|pn(j}ae.zd -}s0Ob~;9 QӾ>4C,qG_A8kYwmn@k-7M/_E_{=ֆݻwwf/ @^"z|J_޸.<-ݯ˽.qKҥ>s1,n@}-7.3+ԛ~eܑas.'ED7.[p@E^pIڵ3?OrVo-?}m~b]v`@3EyLnt1myț[7mq_ڸh6 [''^uF~h8 vqV|{Hg?sW^:Pxa~u;_?;t& on@})ȏ=wuxkqYXbɼ0קU_J{cwMwtԏS@p6OpɟyK}lr8v_9蟰wW'o,_>1/e''}p'zY=ԇ[PpCU3{mmXGM_鬮,>|:?>( =3/QJvy_m4[BAr Mb}zoEș[\42%Dd ~@E` rlv~8γi"P5 ݆AF}կ;Tny1p9s@E!ǣyvH[`= yv- /zŅ!ˣOkis8Mq~||9Ϯo8ώE`!: r.t+^Nqa s Ыyvԅ[R0H 'u9G/u;A AW A^8ώ^ɂ+@γJnHb~h㋇@'γ n0E/t#@7u<;Fn aXO!Q<~Q[D;Ѝ+@ϏѠ7ϜgGn /zA^ozmW鴀EC A 0*XwajMa%uk1jXy²sXz?Ca͒c;\g۴nrէwv+\vi7XWtĪ6 MMkz%uuW'nwC{Ö gOm.b]cw]n ۯCG{%vȑp|<U+;uj7/ y{imJlȯnuS-֕.^6RTXrNSTy8+A߸8n86tT@f Q` :"Q5"l@GQ:FWm3(@GpmE^@(U#+R[:/qC1mpyZq@/N%#+2֚x7.~^{Ekn:qݎRٿ6F}=5~z޴E59Gmmڦ=o7{m{JC^mZv?^OZ='=n}oڢ;Э9lǍht?nfOh:)z5b<-7~ܛ.^w{\,kty {sAeh5FS=e(ݶkqAզѿxL,>kx{f$NzIa%}hr鵏~OJm摎x޽}K|mL|[ 1Wqbc= "1ݶѦv^Ysj֤6Vit[5WZ z!T{XM+A+^zƖil6^>MƥSd m ^8Pz&nt6ϤWM1|l.>V}j55.ӋAWd܁ 7)4]@[^ l;5~̚6ƨf;lzqEvM7h@?v^o4X_5gjl-#ki1`RDS]IL)V>mticmIkǏi| ohB,^4t}S5 " t&qcJ<.}ܦVt:ݏƤ lnӝA4>W x9t m1KkzBzzt~lyq=^AKMt6A+nS{mql6M^_l|7}~u2O{%'rt;nzE^'IcY^QFOw&jZ@_-\dSc4᷆1>@_-\Zjbxe}*ڍ>B|EOĪ;HL]~JG/C U"ʧwt;êS?aݲ&l^y@gR~h'eQ(G~}{8|eaYx {optNB U"K;LuޚY7c.:}'=%\lw۝EEG(},n㡝Mna}OD+Odxl6w|&:fPy"g2<½N;^|r%¹ǽ3ܷa7>BqXmnsprpΩu/=e9v\|D^{Qn"e-bMw '߅V|oyL4/buA#j&5vܻ$\w w~4]>BfrX8?|o8}7=YD*mkCaT޶7U"N 5B6v.ߺ֝_׃w E U3E,mk9'o塭{J? G U3E,ۨ{}|4]>Bfrg6xL_SiHw]e83ڑu@#jyKF{ӸYl4}2W1^_}û:桏P9"O̤&}2WQ=ogG;eGG(}7p:;0oCwn OsEwm:4pk?UG(}'@^"ȋ[yq /n-E@^"ȋ[yq /n-E@^"Ixw̱IIENDB`nbconvert-7.16.4/docs/source/api/000077500000000000000000000000001461373220400166145ustar00rootroot00000000000000nbconvert-7.16.4/docs/source/api/exporters.rst000066400000000000000000000023311461373220400214000ustar00rootroot00000000000000Exporters ========= .. module:: nbconvert.exporters .. seealso:: :doc:`/config_options` Configurable options for the nbconvert application .. autofunction:: export .. autofunction:: get_exporter .. autofunction:: get_export_names Exporter base classes --------------------- .. autoclass:: Exporter .. automethod:: __init__ .. automethod:: from_notebook_node .. automethod:: from_filename .. automethod:: from_file .. automethod:: register_preprocessor .. autoclass:: TemplateExporter .. automethod:: __init__ .. automethod:: from_notebook_node .. automethod:: from_filename .. automethod:: from_file .. automethod:: register_preprocessor .. automethod:: register_filter Specialized exporter classes ---------------------------- The ``NotebookExporter`` inherits directly from ``Exporter``, while the other exporters listed here inherit either directly or indirectly from ``TemplateExporter``. .. autoclass:: NotebookExporter .. autoclass:: HTMLExporter .. autoclass:: SlidesExporter .. autoclass:: LatexExporter .. autoclass:: MarkdownExporter .. autoclass:: PDFExporter .. autoclass:: WebPDFExporter .. autoclass:: PythonExporter .. autoclass:: RSTExporter nbconvert-7.16.4/docs/source/api/filters.rst000066400000000000000000000025231461373220400210200ustar00rootroot00000000000000.. highlight:: none Filters ======= Filters are for use with the ``nbconvert.exporters.templateexporter.TemplateExporter`` exporter. They provide a way for you transform notebook contents to a particular format depending on the template you are using. For example, when converting to HTML, you would want to use the ``ansi2html()`` function to convert ANSI colors (from e.g. a terminal traceback) to HTML colors. .. seealso:: :doc:`/api/exporters` API documentation for the various exporter classes .. module:: nbconvert.filters .. autofunction:: add_anchor .. autofunction:: add_prompts .. autofunction:: ansi2html .. autofunction:: ansi2latex .. autofunction:: ascii_only .. autofunction:: citation2latex .. autofunction:: comment_lines .. autofunction:: escape_latex .. autoclass:: DataTypeFilter .. autofunction:: get_lines .. autofunction:: convert_pandoc .. autoclass:: Highlight2HTML .. autoclass:: Highlight2Latex .. autofunction:: html2text .. autofunction:: indent .. autofunction:: ipython2python .. autofunction:: markdown2html .. autofunction:: markdown2latex .. autofunction:: markdown2rst .. autofunction:: path2url .. autofunction:: posix_path .. autofunction:: prevent_list_blocks .. autofunction:: strip_ansi .. autofunction:: strip_dollars .. autofunction:: strip_files_prefix .. autofunction:: wrap_text nbconvert-7.16.4/docs/source/api/index.rst000066400000000000000000000003431461373220400204550ustar00rootroot00000000000000Python API for working with nbconvert ===================================== .. module:: nbconvert Contents: .. toctree:: :maxdepth: 2 nbconvertapp exporters preprocessors filters writers postprocessors nbconvert-7.16.4/docs/source/api/nbconvertapp.rst000066400000000000000000000007601461373220400220520ustar00rootroot00000000000000NbConvertApp ============ .. module:: nbconvert.nbconvertapp .. seealso:: :doc:`/config_options` Configurable options for the nbconvert application .. autoclass:: NbConvertApp .. automethod:: init_notebooks .. automethod:: convert_notebooks .. automethod:: convert_single_notebook .. automethod:: init_single_notebook_resources .. automethod:: export_single_notebook .. automethod:: write_single_notebook .. automethod:: postprocess_single_notebook nbconvert-7.16.4/docs/source/api/postprocessors.rst000066400000000000000000000005431461373220400224600ustar00rootroot00000000000000Postprocessors ============== .. module:: nbconvert.postprocessors .. seealso:: :doc:`/config_options` Configurable options for the nbconvert application .. autoclass:: PostProcessorBase .. automethod:: postprocess Specialized postprocessors -------------------------- .. autoclass:: ServePostProcessor .. automethod:: postprocess nbconvert-7.16.4/docs/source/api/preprocessors.rst000066400000000000000000000022411461373220400222560ustar00rootroot00000000000000Preprocessors ============= .. module:: nbconvert.preprocessors :noindex: .. seealso:: :doc:`/config_options` Configurable options for the nbconvert application .. autoclass:: Preprocessor .. automethod:: __init__ .. automethod:: preprocess .. automethod:: preprocess_cell Specialized preprocessors ------------------------- Converting and extracting figures ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: ConvertFiguresPreprocessor .. autoclass:: SVG2PDFPreprocessor .. autoclass:: ExtractOutputPreprocessor Converting text ~~~~~~~~~~~~~~~ .. autoclass:: LatexPreprocessor .. autoclass:: HighlightMagicsPreprocessor Metadata and header control ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: ClearMetadataPreprocessor .. autoclass:: CSSHTMLHeaderPreprocessor Removing/Manipulating cells, inputs, and outputs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: ClearOutputPreprocessor .. autoclass:: CoalesceStreamsPreprocessor .. autoclass:: RegexRemovePreprocessor .. autoclass:: TagRemovePreprocessor Executing Notebooks ~~~~~~~~~~~~~~~~~~~ .. autoclass:: ExecutePreprocessor :members: .. autoclass:: CellExecutionError nbconvert-7.16.4/docs/source/api/writers.rst000066400000000000000000000005421461373220400210460ustar00rootroot00000000000000Writers ======= .. module:: nbconvert.writers .. seealso:: :doc:`/config_options` Configurable options for the nbconvert application .. autoclass:: WriterBase .. automethod:: __init__ .. automethod:: write Specialized writers ------------------- .. autoclass:: DebugWriter .. autoclass:: FilesWriter .. autoclass:: StdoutWriter nbconvert-7.16.4/docs/source/architecture.rst000066400000000000000000000207001461373220400212560ustar00rootroot00000000000000.. _architecture: ========================= Architecture of nbconvert ========================= This is a high-level outline of the basic workflow, structures and objects in nbconvert. Specifically, this exposition has a two-fold goal: #. to alert you to the affordances available for customisation or direct contributions #. to provide a map of where and when different events occur, which should aid in tracking down bugs. A detailed pipeline exploration =============================== Nbconvert takes in a notebook, which is a JSON object, and operates on that object. This can include operations that take a notebook and return a notebook. For example, that operation could be to execute the notebook as though it were a continuous script; if it were executed ``--in-place`` then it would overwrite the current notebook. Or it could be that we wish to systematically alter the notebook, for example by clearing all output cells. Format agnostic operations on cell content that do not violate the nbformat spec can be interpreted as a notebook to notebook conversion step; such operations can be performed as part of the preprocessing step. But often we want to have the notebook's structured content in a different format. Importantly, in many cases the structure of the notebook should be reflected in the structure of the output, adapted to the output's format. For that purpose, the original JSON structure of the document is crucial scaffolding needed to support this kind of structured output. In order to maintain structure, it can be useful to apply our conversion programmatically on the structure itself. To do so, when converting to formats other than the notebook, we use the `jinja`_ templating engine. The basic unit of structure in a notebook is the cell. Accordingly, since our templating engine is capable of expressing structure, the basic unit in our templates will often be specified at the cell level. Each cell has a certain type; the three most important cell types for our purposes are code, markdown, and raw NbConvert. Code cells can be split further into their input and their output. Operations can also occur separately on input and output and their respective subcomponents. Markdown cells and raw NbConvert cells do not have analogous substructure. The template's structure then can be seen as a mechanism for selecting content on which to operate. Because the template operates on individual cells, this has some upsides and drawbacks. One upside is that this allows the template to have access to the individual cell's metadata, which enables intelligently transforming the appropriate content. The transformations occur as a series of replacement rules and filters. For many purposes these filters take the form of external calls to `pandoc`_, which is a utility for converting between many different document formats. One downside is that this makes operations that require global coördination (e.g., cross referencing across cells) somewhat challenging to implement as filters inside templates. Note that all that we've described is happening in memory. This is crucial in order to ensure that this functionality is available when writing files is more challenging. Nonetheless, the reason for using nbconvert almost always involves producing some kind of output file. We take the in-memory object and write a file appropriate for the output type. The entirety of heretofore described process can be described as part of an ``Exporter``. ``Exporter``\s often involves ``Preprocessor``\s, ``filters``, ``templates`` and ``Writer``\s. These classes and functions are described in greater detail below. Finally, one can apply a ``Postprocessor`` after the writing has occurred. For example, it is common when converting to slides to start a webserver and open a browser window with the newly created document (``--to slides --post serve``). Classes ======= .. _exporters: Exporters --------- The primary class in nbconvert is the ``nbconvert.exporters.exporter.Exporter``. Exporters encapsulate the operation of turning a notebook into another format. There is one Exporter for each format supported in nbconvert. The first thing an Exporter does is load a notebook, usually from a file via :mod:`nbformat`. Most of what a typical Exporter does is select and configure preprocessors, filters, and templates. If you want to convert notebooks to additional formats, a new Exporter is probably what you are looking for. .. seealso:: :ref:`Writing a custom Exporter ` Once the notebook is loaded, it is preprocessed... .. _preprocessors: Preprocessors ------------- A ``nbconvert.preprocessors.Preprocessor`` is an object that transforms the content of the notebook to be exported. The result of a preprocessor being applied to a notebook is always a notebook. These operations include re-executing the cells, stripping output, removing bundled outputs to separate files, etc. If you want to add operations that modify a notebook before exporting, a preprocessor is the place to start. .. seealso:: `Custom Preprocessors `_ Once a notebook is preprocessed, it's time to convert the notebook into the destination format. .. _templates_and_filters: Templates --------- Most Exporters in nbconvert are a subclass of ``nbconvert.exporters.templateexporter.TemplateExporter``, which make use of `jinja`_ to render a notebook into the destination format. Nbconvert templates can be selected from the command line with the ``--template`` option. For example, to use the ``reveal`` template with the HTML exporter .. sourcecode:: bash jupyter nbconvert --to html --template reveal .. note:: Since version 6.0, The HTML exporter defaults to the ``lab`` template which produces a DOM structure corresponding to the notebook component in JupyterLab. To produce HTML corresponding to the looks of the classic notebook, one can use the ``classic`` template by passing ``--template classic`` to the command line. The nbconvert template system has been completely revamped with nbconvert 6.0 to allow for greater extensibility. Nbconvert templates can now be installed as third-party packages and are automatically picked up by nbconvert. For more details about how to create custom templates, check out the :doc:`customizing` section of the documentation. Filters ------- Filters are Python callables which take something (typically text) as an input, and produce a text output. If you want to perform custom transformations of particular outputs, a filter may be the way to go. The following code snippet is an excerpt from the main default template of the HTML export. The displayed block determines how text output on ``stdout`` is displayed in HTML. .. sourcecode:: html {% block stream_stdout -%}
    {{- output.text | ansi2html -}}
    
{%- endblock stream_stdout %} In the ``{{- output.text | ansi2html -}}`` bit, we invoke the ``ansi2html`` filter to transform the text output. Typically, filters are pure functions. However, filters that require some configuration, may be implemented as Configurable classes. .. seealso:: - :doc:`customizing` - `More on Jinja Filters`_ Once it has passed through the template, an Exporter is done with the notebook, and returns the file data. At this point, we have the file data as text or bytes and we can decide where it should end up. When you are using nbconvert as a library, as opposed to the command-line application, this is typically where you would stop, take your exported data, and go on your way. .. _writers: Writers ------- A *Writer* takes care of writing the resulting file(s) where they should end up. There are two basic Writers in nbconvert: 1. stdout - writes the result to stdout (for pipe-style workflows) 2. Files (default) - writes the result to the filesystem Once the output is written, nbconvert has done its job. .. _postprocessors: Postprocessors -------------- A *Postprocessor* is something that runs after everything is exported and written to the filesystem. The only postprocessor in nbconvert at this point is the ``nbconvert.postprocessors.serve.ServePostProcessor``, which is used for serving `reveal.js`_ HTML slideshows. .. _jinja: https://jinja.palletsprojects.com/en/3.0.x/ .. _More on Jinja Filters: https://jinja.palletsprojects.com/en/3.0.x/templates/#filters .. _reveal.js: http://lab.hakim.se/reveal-js .. _pandoc: https://pandoc.org/ nbconvert-7.16.4/docs/source/conf.py000066400000000000000000000252151461373220400173470ustar00rootroot00000000000000# nbconvert documentation build configuration file, created by # sphinx-quickstart on Tue Jun 9 17:11:30 2015. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import os import shutil from datetime import datetime, timezone HERE = os.path.dirname(__file__) # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) # Automatically generate config_options.rst with open(os.path.join(HERE, "..", "autogen_config.py")) as f: exec(compile(f.read(), "autogen_config.py", "exec"), {}) # noqa: S102 print("Created docs for config options") # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ "myst_parser", "sphinx.ext.autodoc", "sphinx.ext.extlinks", "sphinx.ext.intersphinx", "sphinx.ext.napoleon", "nbsphinx", "IPython.sphinxext.ipython_console_highlighting", ] try: import enchant # noqa: F401 extensions += ["sphinxcontrib.spelling"] except ImportError: pass myst_enable_extensions = ["html_image"] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] source_suffix = [".rst"] # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = "index" # General information about the project. project = "nbconvert" year = datetime.now(tz=timezone.utc).date().year copyright = "2015-%s, Jupyter Development Team" % year author = "Jupyter Development Team" extlinks = {"ghpull": ("https://github.com/jupyter/nbconvert/pull/%s", "PR #%s")} linkcheck_ignore = [ "https://github.com/jupyter/nbconvert/pull/", ] # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # Get information from _version.py and use it to generate version and release _version_py = os.path.join(HERE, "../../nbconvert/_version.py") version_ns = {} exec(compile(open(_version_py).read(), _version_py, "exec"), version_ns) # noqa: SIM115, S102 # The short X.Y version. version = "%i.%i" % version_ns["version_info"][:2] # The full version, including alpha/beta/rc tags. release = version_ns["__version__"] # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = "en" # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The reST default role (used for this markup: `text`) to use for all # documents. default_role = "any" # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. # pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- html_theme = "pydata_sphinx_theme" # otherwise, readthedocs.org uses their default theme, so no need to specify it # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'sphinx_rtd_theme' # 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 = { # prefer browser defaults over custom JS keyboard event handlers "navigation_with_keys": False, } # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # 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"] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' # html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value # html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = "nbconvertdoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = {} # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, "nbconvert.tex", "nbconvert Documentation", "Jupyter Development Team", "manual"), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [(master_doc, "nbconvert", "nbconvert Documentation", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ( master_doc, "nbconvert", "nbconvert Documentation", author, "nbconvert", "One line description of project.", "Miscellaneous", ), ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { "python": ("https://docs.python.org/3.6", None), "jinja": ("http://jinja.pocoo.org/docs", None), "nbformat": ("https://nbformat.readthedocs.io/en/latest", None), } def setup(_): dest = os.path.join(HERE, "changelog.md") shutil.copy(os.path.join(HERE, "..", "..", "CHANGELOG.md"), dest) nbconvert-7.16.4/docs/source/customizing.rst000066400000000000000000000151401461373220400211510ustar00rootroot00000000000000Creating Custom Templates for nbconvert ======================================= Selecting a template -------------------- Most exporters in nbconvert are subclasses of ``TemplateExporter``, and make use of jinja to render notebooks into the destination format. Alternative nbconvert templates can be selected by name from the command line with the ``--template`` option. For example, to use the ``reveal`` template with the HTML exporter, one can type. .. sourcecode:: bash jupyter nbconvert --to html --template reveal Where are nbconvert templates installed? ---------------------------------------- Nbconvert templates are *directories* containing resources for nbconvert template exporters such as jinja templates and associated assets. They are installed in the **data directory** of nbconvert, namely ``/share/jupyter/nbconvert``. Nbconvert includes several templates already. For example, three HTML templates are provided in nbconvert core for the HTML exporter: - ``lab`` (The default HTML template, which produces the same DOM structure as JupyterLab) - ``classic`` (The HTML template styled after the classic notebook) - ``reveal`` (For producing slideshows). .. note:: Running ``jupyter --paths`` will show all Jupyter directories and search paths. For example, on Linux, ``jupyter --paths`` returns: .. code:: $ jupyter --paths config: /home//.jupyter //etc/jupyter /usr/local/etc/jupyter /etc/jupyter data: /home//.local/share/jupyter //share/jupyter /usr/local/share/jupyter /usr/share/jupyter runtime: /home//.local/share/jupyter/runtime Adding Additional Template Paths ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In order to add additional paths to be searched, you need to pass ``TemplateExporter.extra_template_basedirs`` config options indicating the extra directories to search for templates. Be careful not to override ``TemplateExporter.template_paths`` unless you intend to replace ALL paths and don't want the default locations included. When using the commandline the extra template paths are added by calling ``--TemplateExporter.extra_template_basedirs=path/you/want/included``. The content of nbconvert templates ---------------------------------- conf.json ~~~~~~~~~ Nbconvert templates all include a ``conf.json`` file at the root of the directory, which is used to indicate - the base template that it is inheriting from. - the mimetypes of the template. - preprocessors classes to register in the exporter when using that template. Inspecting the configuration of the reveal template we see that it inherits from the lab template, exports text/html, and enables two preprocessors called "100-pygments" and "500-reveal". .. code:: { "base_template": "lab", "mimetypes": { "text/html": true }, "preprocessors": { "100-pygments": { "type": "nbconvert.preprocessors.CSSHTMLHeaderPreprocessor", "enabled": true }, "500-reveal": { "type": "nbconvert.exporters.slides._RevealMetadataPreprocessor", "enabled": true } } } Inheritance ~~~~~~~~~~~ Nbconvert walks up the inheritance structure determined by ``conf.json`` and produces an aggregated configuration, merging the dictionaries of registered preprocessors. The lexical ordering of the preprocessors by name determines the order in which they will be run. Besides the ``conf.json`` file, nbconvert templates most typically include jinja templates files, although any other resource from the base template can be overridden in the derived template. For example, inspecting the content of the ``classic`` template located in ``share/jupyter/nbconvert/templates/classic``, we find the following content: .. code:: share/jupyter/nbconvert/templates/classic ├── static │ └── styles.css ├── conf.json ├── index.html.j2 └── base.html.j2 The ``classic`` template exporter includes a ``index.html.j2`` jinja template (which is the main entry point for HTML exporters) as well as CSS and a base template file in ``base.html.j2``. .. note:: A template inheriting from ``classic`` would specify ``"base_template": "classic"`` and could override any of these files. For example, one could make a "classiker" template merely providing an alternative ``styles.css`` file. Inheritance in Jinja ~~~~~~~~~~~~~~~~~~~~ In nbconvert, jinja templates can inherit from any other jinja template available in its current directory or base template directory by name. Jinja templates of other directories can be addressed by their relative path from the Jupyter data directory. For example, in the reveal template, ``index.html.j2`` extends ``base.html.j2`` which is in the same directory, and ``base.html.j2`` extends ``lab/base.html.j2``. This approach allows using content that is available in other templates or may be overridden in the current template. A practical example ~~~~~~~~~~~~~~~~~~~ Say you would like to modify the existing Markdown template to wrap each output statement in a fenced code block: .. code:: ```output (1, 2, 3) ``` Start by creating a new template directory, say ``mdoutput``. In it, you have the following files:: conf.json index.md.j2 The configuration file, ``conf.json`` states that your template applies to markdown files:: { "mimetypes": { "text/markdown": true } } The ``index.md.j2`` template entrypoint extends the existing markdown template, and redefines how output blocks are rendered: .. code:: {% extends 'markdown/index.md.j2' %} {%- block traceback_line -%} ```output {{ line.rstrip() | strip_ansi }} ``` {%- endblock traceback_line -%} {%- block stream -%} ```output {{ output.text.rstrip() }} ``` {%- endblock stream -%} {%- block data_text scoped -%} ```output {{ output.data['text/plain'].rstrip() }} ``` {%- endblock data_text -%} You can now convert your notebook to markdown using the new template:: jupyter nbconvert --execute notebook.ipynb --to markdown --template=mdoutput (If you put your template folder in a different location than your notebook, remember to add ``--TemplateExporter.extra_template_basedirs=path/to/template/parent``.) To further explore the possibilities of templating, take a look at the root of all templates: ``null.j2``. You can find it in the ``./nbconvert/templates/base`` subfolder of one of the data paths given by ``jupyter --paths``. nbconvert-7.16.4/docs/source/dejavu.rst000066400000000000000000000023471461373220400200610ustar00rootroot00000000000000.. highlight:: none Dejavu ====== Dejavu intends to be a tool to facilitate for Jupyter users to generate static outputs from their notebooks, mimicking the behavior of `voilà `_. Running dejavu -------------- Dejavu works exactly the same as nbconvert and you can use all command line options that you would with nbconvert. To run a default instance:: jupyter dejavu notebook.ipynb In case you want to show code in addition to its output use the flag ``--show-input``. Configuring the Notebook for slides presentations ------------------------------------------------- In case the user intends to do a slide presentation out of their Jupyter notebook it's recommended to use the ``reveal`` template. In orders to obtain a better result from it's advised to use the slides metadatas available in the cells: * In the notebook, select a cell and click on the "Property Inspector menu" .. tip:: The "Property Inspector menu" can be located in the right side bar, its symbol contains two gears. * Select a cell in the notebook * In the Property Inspector menu select the cell's slide type: * Slide * Sub-Slide * Fragment * Skip * Notes * Repeat the process for all cells nbconvert-7.16.4/docs/source/development_release.rst000066400000000000000000000075071461373220400226300ustar00rootroot00000000000000.. _nbconvert_release: Making an ``nbconvert`` release =============================== This document guides a contributor through creating a release of ``nbconvert``. Assign all merged PRs to milestones ----------------------------------- Go to GitHub and assign all PRs that have been merged to milestones. This will be helpful when you update the changelog. If you go to this `GitHub page `_ you will find all the PRs that currently have no milestones. .. _GitHub no milestones: https://github.com/jupyter/nbconvert/pulls?utf8=%E2%9C%93&q=is%3Amerged%20is%3Apr%20no%3Amilestone%20 Gather all PRs related to milestone ----------------------------------- `ghpro `_ can be used to extract the pull requests by call the following from nbconvert directory (will ask for an API token the first time): .. code:: bash github-stats --milestone=$VERSION --since-tag $LAST_VERSION --links .. _ghpro: https://github.com/mpacer/ghpro/tree/alternate_styling Manually categorize tickets --------------------------- Group the tickets by these general categories (or others if they are relevant). This usually a manual processes to evaluate the changes in each PR. #. New Features #. Deprecations #. Fixing Problems #. Testing, Docs, and Builds Collect major changes --------------------- From the tickets write up any major features / changes that deserve a paragraph to describe how they work. Update docs/source/changelog.rst -------------------------------- Copy these changes with the new version to the top of changelog.rst. Prior release changelogs can be used to pick formatting of the message. Check installed tools --------------------- Review ``CONTRIBUTING.md``, particularly the testing and release sections. Clean the repository -------------------- You can remove all non-tracked files with: .. code:: bash git clean -xfdi This would ask you for confirmation before removing all untracked files. Make sure the ``dist/`` and ``build/`` folders are clean and avoid stale builds from previous attempts. Create the release ------------------ #. Update the :doc:`changelog ` to account for all the PRs assigned to this milestone. #. Update version number in ``nbconvert/_version.py`` and remove ``.dev`` from dev_info. Note that the version may already be on the dev version of the number you're releasing. #. Commit and tag the release with the current version number: .. code:: bash git commit -am "release $VERSION" git tag $VERSION #. You are now ready to build the ``sdist`` and ``wheel``: .. code:: bash pip install build python -m build . #. You can now test the ``wheel`` and the ``sdist`` locally before uploading to PyPI. Make sure to use `twine `_ to upload the archives over SSL. .. code:: bash twine upload dist/* #. The conda-forge bot will automatically add a PR on your behalf to the `nbconvert-feedstock repo `_. You may want to review this PR to ensure conda-forge will be updated cleanly. .. _conda-forge-nbconvert: https://github.com/conda-forge/nbconvert-feedstock Release the new version ----------------------- Push directly on main, including --tags separately .. code:: bash git push upstream git push upstream --tags Return to development state --------------------------- If all went well, change the ``nbconvert/_version.py`` back by adding the ``.dev`` suffix and moving the version forward to the next patch release number. Email googlegroup with update letter ------------------------------------ Make sure to email jupyter@googlegroups.com with the subject line of "[ANN] NBConvert $VERSION -- ..." and include at least the significant changes, contributors, and individual PR notes (if not many significant changes). nbconvert-7.16.4/docs/source/execute_api.rst000066400000000000000000000173071461373220400211000ustar00rootroot00000000000000Executing notebooks =================== .. currentmodule:: nbconvert.preprocessors Jupyter notebooks are often saved with output cells that have been cleared. nbconvert provides a convenient way to execute the input cells of an .ipynb notebook file and save the results, both input and output cells, as a .ipynb file. In this section we show how to execute a ``.ipynb`` notebook document saving the result in notebook format. If you need to export notebooks to other formats, such as reStructured Text or Markdown (optionally executing them) see section :doc:`nbconvert_library`. Executing notebooks can be very helpful, for example, to run all notebooks in Python library in one step, or as a way to automate the data analysis in projects involving more than one notebook. Executing notebooks from the command line ----------------------------------------- The same functionality of executing notebooks is exposed through a :doc:`command line interface ` or a Python API interface. As an example, a notebook can be executed from the command line with:: jupyter nbconvert --to notebook --execute mynotebook.ipynb Executing notebooks using the Python API interface -------------------------------------------------- This section will illustrate the Python API interface. Example ~~~~~~~ Let's start with a complete quick example, leaving detailed explanations to the following sections. **Import**: First we import nbconvert and the ``ExecutePreprocessor`` class:: import nbformat from nbconvert.preprocessors import ExecutePreprocessor **Load**: Assuming that ``notebook_filename`` contains the path of a notebook, we can load it with:: with open(notebook_filename) as f: nb = nbformat.read(f, as_version=4) **Configure**: Next, we configure the notebook execution mode:: ep = ExecutePreprocessor(timeout=600, kernel_name='python3') We specified two (optional) arguments ``timeout`` and ``kernel_name``, which define respectively the cell execution timeout and the execution kernel. The option to specify **kernel_name** is new in nbconvert 4.2. When not specified or when using nbconvert <4.2, the default Python kernel is chosen. **Execute/Run (preprocess)**: To actually run the notebook we call the method :meth:`~ExecutePreprocessor.preprocess`:: ep.preprocess(nb, {'metadata': {'path': 'notebooks/'}}) Hopefully, we will not get any errors during the notebook execution (see the last section for error handling). Note that ``path`` specifies in which folder to execute the notebook. **Save**: Finally, save the resulting notebook with:: with open('executed_notebook.ipynb', 'w', encoding='utf-8') as f: nbformat.write(nb, f) That's all. Your executed notebook will be saved in the current folder in the file ``executed_notebook.ipynb``. Execution arguments (traitlets) ------------------------------- The arguments passed to ``ExecutePreprocessor`` are configuration options called `traitlets `_. There are many cool things about traitlets. For example, they enforce the input type, and they can be accessed/modified as class attributes. Moreover, each traitlet is automatically exposed as command-line options. For example, we can pass the timeout from the command-line like this:: jupyter nbconvert --ExecutePreprocessor.timeout=600 --to notebook --execute mynotebook.ipynb Let's now discuss in more detail the two traitlets we used. The ``timeout`` traitlet defines the maximum time (in seconds) each notebook cell is allowed to run, if the execution takes longer an exception will be raised. The default is 30 s, so in cases of long-running cells you may want to specify an higher value. The ``timeout`` option can also be set to ``None`` or ``-1`` to remove any restriction on execution time. The second traitlet, ``kernel_name``, allows specifying the name of the kernel to be used for the execution. By default, the kernel name is obtained from the notebook metadata. The traitlet ``kernel_name`` allows specifying a user-defined kernel, overriding the value in the notebook metadata. A common use case is that of a Python 2/3 library which includes documentation/testing notebooks. These notebooks will specify either a python2 or python3 kernel in their metadata (depending on the kernel used the last time the notebook was saved). In reality, these notebooks will work on both Python 2 and Python 3, and, for testing, it is important to be able to execute them programmatically on both versions. Here the traitlet ``kernel_name`` helps simplify and maintain consistency: we can just run a notebook twice, specifying first "python2" and then "python3" as the kernel name. Handling errors and exceptions ------------------------------ In the previous sections we saw how to save an executed notebook, assuming there are no execution errors. But, what if there are errors? Execution until first error ~~~~~~~~~~~~~~~~~~~~~~~~~~~ An error during the notebook execution, by default, will stop the execution and raise a ``CellExecutionError``. Conveniently, the source cell causing the error and the original error name and message are also printed. After an error, we can still save the notebook as before:: with open('executed_notebook.ipynb', mode='w', encoding='utf-8') as f: nbformat.write(nb, f) The saved notebook contains the output up until the failing cell, and includes a full stack-trace and error (which can help debugging). Handling errors ~~~~~~~~~~~~~~~ A useful pattern to execute notebooks while handling errors is the following:: from nbconvert.preprocessors import CellExecutionError try: out = ep.preprocess(nb, {'metadata': {'path': run_path}}) except CellExecutionError: out = None msg = 'Error executing the notebook "%s".\n\n' % notebook_filename msg += 'See notebook "%s" for the traceback.' % notebook_filename_out print(msg) raise finally: with open(notebook_filename_out, mode='w', encoding='utf-8') as f: nbformat.write(nb, f) This will save the executed notebook regardless of execution errors. In case of errors, however, an additional message is printed and the ``CellExecutionError`` is raised. The message directs the user to the saved notebook for further inspection. Execute and save all errors ~~~~~~~~~~~~~~~~~~~~~~~~~~~ As a last scenario, it is sometimes useful to execute notebooks which raise exceptions, for example to show an error condition. In this case, instead of stopping the execution on the first error, we can keep executing the notebook using the traitlet ``allow_errors`` (default is False). With ``allow_errors=True``, the notebook is executed until the end, regardless of any error encountered during the execution. The output notebook, will contain the stack-traces and error messages for **all** the cells raising exceptions. Widget state ------------ If your notebook contains any `Jupyter Widgets `_, the state of all the widgets can be stored in the notebook's metadata. This allows rendering of the live widgets on for instance nbviewer, or when converting to html. We can tell nbconvert to not store the state using the ``store_widget_state`` argument:: jupyter nbconvert --ExecutePreprocessor.store_widget_state=False --to notebook --execute mynotebook.ipynb This widget rendering is not performed against a browser during execution, so only widget default states or states manipulated via user code will be calculated during execution. ``%%javascript`` cells will execute upon notebook rendering, enabling complex interactions to function as expected when viewed by a UI. If you can't view widget results after execution, you may need to select :menuselection:`File --> Trust Notebook` in the menu. nbconvert-7.16.4/docs/source/external_exporters.rst000066400000000000000000000202561461373220400225370ustar00rootroot00000000000000.. _external_exporters: Customizing exporters ===================== .. versionadded:: 4.2 You can now use the ``--to`` flag to use custom export formats defined outside nbconvert. The command-line syntax to run the ``nbconvert`` script is:: jupyter nbconvert --to FORMAT notebook.ipynb This will convert the Jupyter document file ``notebook.ipynb`` into the output format designated by the ``FORMAT`` string as explained below. Extending the built-in format exporters --------------------------------------- A few built-in formats are available by default: ``html``, ``pdf``, ``webpdf``, ``script``, ``latex``. Each of these has its own *exporter* with many configuration options that can be extended. Having the option to point to a different *exporter* allows authors to create their own fully customized templates or export formats. A custom *exporter* must be an importable Python object. We recommend that these be distributed as Python libraries. .. _entrypoints: Registering a custom exporter as an entry point ----------------------------------------------- Additional exporters may be registered as named entry_points_. nbconvert uses the ``nbconvert.exporters`` entry point to find exporters from any package you may have installed. If you are writing a Python package that provides custom exporters, you can register the custom exporters in your package's :file:`setup.py`. For example, your package may contain two custom exporters, named "simple" and "detail", and can be registered in your package's :file:`setup.py` as follows: .. sourcecode:: python setup( # ... entry_points={ "nbconvert.exporters": [ "simple = mymodule:SimpleExporter", "detail = mymodule:DetailExporter", ], } ) Now people who have installed your Python package containing the two custom exporters can call the entry point name:: jupyter nbconvert --to detail mynotebook.ipynb instead of having to specify the full import name of the custom exporter. .. _entry_points: https://packaging.python.org/guides/ creating-and-discovering-plugins/#using-package-metadata Using a custom exporter without entrypoints ------------------------------------------- We encourage registering custom exporters as entry points as described in the previous section. Registering a custom exporter with an entry point simplifies using the exporter. If a custom exporter has not been registered with an entry point, the exporter can still be used by providing the fully qualified name of this exporter as the argument of the ``--to`` flag when running from the command line:: $ jupyter nbconvert --to notebook.ipynb For example, assuming a library ``tcontrib`` has a custom exporter name ``TExporter``, you would convert to this custom format using the following:: $ jupyter nbconvert --to tcontrib.TExporter notebook.ipynb A library can contain multiple exporters. Creators of custom exporters should make sure that all other flags of the command line behave the same for the custom exporters as for built-in exporters. Parameters controlled by an external exporter ============================================= An external exporter can control almost any parameter of the notebook conversion process, from simple parameters such as the output file extension, to more complex ones such as the execution of the notebook or a custom rendering template. All external exporters can expose custom options using the ``traitlets`` configurable API. Refer to the library that provides these exporters for details on how these configuration options works. You can use the Jupyter configuration files to configure an external exporter. As for any ``nbconvert`` exporters you can use either the configuration file syntax of ``c.MyExporter.config_option=value`` or the command line flag form ``--MyExporter.config_option=value``. Writing a custom ``Exporter`` ============================= Under the hood exporters are python classes that expose a certain interface. Any importable classes that expose this interface can be use as an exporter for nbconvert. For simplicity we expose basic classes that implement all the relevant methods that you have to subclass and overwrite just the relevant methods to provide a custom exporter. Below we show you the step to create a custom exporter that provides a custom file extension, and a custom template that inserts before and after each markdown cell. We will lay out files to be ready for Python packaging and distributing on PyPI, although the exact art of Python packaging is beyond the scope of this explanation. We will use the following layout for our package to expose a custom exporter:: mypackage ├── LICENSE.md ├── setup.py └── mypackage ├── __init__.py └── templates └── test_template.tpl If you wished to create this same directory structure you could use the following commands when you are at the directory under which you wish to build your ``mypackage`` package: .. code-block:: bash mkdir -p mypackage/mypackage/templates touch mypackage/LICENSE.md touch mypackage/setup.py touch mypackage/mypackage/__init__.py touch mypackage/mypackage/templates/test_template.tpl .. important:: You should not publish this package without adding content to your ``LICENSE.md`` file. For example, ``nbconvert`` follows the Jupyter Project convention of using a Modified BSD License (also known as New or Revised or 3-Clause BSD). For a guide on picking the right license for your use case, please see `choose a license `_. If you do not specify the license, your code may be `unusable by many open source projects`_. .. _`unusable by many open source projects`: http://choosealicense.com/no-license/ As you can see the layout is relatively simple, in the case where a template is not needed we would actually have only one file with an Exporter implementation. Of course you can change the layout of your package to have a more fine-grained structure of the subpackage. But lets see what a minimum example looks like. We are going to write an exporter that: - exports to html, so we will reuse the built-in html exporter - changes the file extension to ``.test_ext`` .. code-block:: python # file __init__.py import os import os.path from traitlets.config import Config from nbconvert.exporters.html import HTMLExporter # ----------------------------------------------------------------------------- # Classes # ----------------------------------------------------------------------------- class MyExporter(HTMLExporter): """ My custom exporter """ # If this custom exporter should add an entry to the # "File -> Download as" menu in the notebook, give it a name here in the # `export_from_notebook` class member export_from_notebook = "My format" def _file_extension_default(self): """ The new file extension is ``.test_ext`` """ return ".test_ext" @property def template_paths(self): """ We want to inherit from HTML template, and have template under ``./templates/`` so append it to the search path. (see next section) Note: nbconvert 6.0 changed ``template_path`` to ``template_paths`` """ return super().template_paths + [ os.path.join(os.path.dirname(__file__), "templates") ] def _template_file_default(self): """ We want to use the new template we ship with our library. """ return "test_template" # full And the template file, that inherits from the html ``full`` template and prepend/append text to each markdown cell (see Jinja2 docs for template syntax):: {% extends "full.tpl" %} {% block markdowncell -%} ## this is a markdown cell {{ super() }} ## THIS IS THE END {% endblock markdowncell %} Assuming you install this package locally, or from PyPI, you can now use:: jupyter nbconvert --to mypackage.MyExporter notebook.ipynb nbconvert-7.16.4/docs/source/highlighting.rst000066400000000000000000000035671461373220400212550ustar00rootroot00000000000000Customizing Syntax Highlighting =============================== Under the hood, nbconvert uses pygments to highlight code. pdf, webpdf and html exporting support changing the highlighting style. Using Builtin styles -------------------- Pygments has a number of builtin styles available. To use them, we just need to set the style setting in the relevant preprocessor. To change html and webpdf highlighting export with: .. code-block:: bash jupyter nbconvert --to html notebook.ipynb --CSSHTMLHeaderPreprocessor.style= To change pdf and latex highlighting export with: .. code-block:: bash jupyter nbconvert --to pdf notebook.ipynb --LatexPreprocessor.style= where ```` is the name of the pygments style. Available styles may vary from system to system. You can find all available styles with: .. code-block:: bash pygmentize -L styles from a terminal or .. code-block:: python from pygments.styles import get_all_styles print(list(get_all_styles())) from python. You can preview all the styles from an environment that can display html like jupyter notebook with: .. code-block:: python from pygments.styles import get_all_styles from pygments.formatters import Terminal256Formatter from pygments.lexers import PythonLexer from pygments import highlight code = """ import os def function(test=1): if test in [3,4]: print(test) """ for style in get_all_styles(): highlighted_code = highlight(code, PythonLexer(), Terminal256Formatter(style=style)) print(f"{style}:\n{highlighted_code}") Making your own styles ---------------------- To make your own style you must subclass ``pygments.styles.Style``, and then you must register your new style with Pygments using their plugin system. This is explained in detail in the `Pygments documentation `_. nbconvert-7.16.4/docs/source/index.rst000066400000000000000000000037651461373220400177170ustar00rootroot00000000000000============================================= nbconvert: Convert Notebooks to other formats ============================================= Using ``nbconvert`` enables: - **presentation** of information in familiar formats, such as PDF. - **publishing** of research using LaTeX and opens the door for embedding notebooks in papers. - **collaboration** with others who may not use the notebook in their work. - **sharing** contents with many people via the web using HTML. Overall, notebook conversion and the ``nbconvert`` tool give scientists and researchers the flexibility to deliver information in a timely way across different formats. Primarily, the ``nbconvert`` tool allows you to convert a Jupyter ``.ipynb`` notebook document file into another static format including HTML, LaTeX, PDF, Markdown, reStructuredText, and more. ``nbconvert`` can also add productivity to your workflow when used to execute notebooks programmatically. If used as a Python library (``import nbconvert``), ``nbconvert`` adds notebook conversion within a project. For example, ``nbconvert`` is used to implement the "Download as" feature within the Jupyter Notebook web application. When used as a command line tool (invoked as ``jupyter nbconvert ...``), users can conveniently convert just one or a batch of notebook files to another format. **Contents:** .. toctree:: :maxdepth: 2 :caption: User Documentation install usage nbconvert_library dejavu latex_citations removing_cells execute_api .. toctree:: :maxdepth: 2 :caption: Configuration config_options customizing external_exporters highlighting .. toctree:: :maxdepth: 2 :caption: Developer Documentation architecture api/index development_release .. toctree:: :maxdepth: 2 :caption: About nbconvert changelog .. toctree:: :maxdepth: 2 :caption: Questions? Suggestions? need_help Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` nbconvert-7.16.4/docs/source/install.rst000066400000000000000000000065561461373220400202570ustar00rootroot00000000000000.. highlight:: none Installation ============ .. seealso:: `Installing Jupyter `__ Nbconvert is part of the Jupyter ecosystem. Supported Python versions ------------------------- Currently Python 3.8-3.11 is supported and tested by nbconvert. Installing nbconvert -------------------- Nbconvert is packaged for both pip and conda, so you can install it with:: pip install nbconvert # OR conda install nbconvert The `Miniconda `_ and `Miniforge `_ distributions both provide a minimal conda installation. .. important:: To unlock its full capabilities, nbconvert requires Pandoc, TeX (specifically, XeLaTeX) and playwright. These must be installed separately. Installing Pandoc ----------------- For converting markdown to formats other than HTML, nbconvert uses `Pandoc `_ (1.12.1 or later). To install pandoc on Linux, you can generally use your package manager:: sudo apt-get install pandoc On other platforms, you can get pandoc from `their website `_. Installing TeX -------------- For converting notebooks to PDF (with ``--to pdf``), nbconvert makes use of LaTeX and the XeTeX as the rendering engine. .. versionadded:: 5.0 We use XeTeX as the rendering engine rather than pdfTeX (as in earlier versions). XeTeX can access fonts through native operating system libraries, it has better support for OpenType formatted fonts and Unicode characters. To install a complete TeX environment (including XeLaTeX and the necessary supporting packages) by hand can be tricky. Fortunately, there are packages that make this much easier. These packages are specific to different operating systems: * Linux: `TeX Live `_ * E.g. on Debian or Ubuntu:: sudo apt-get install texlive-xetex texlive-fonts-recommended texlive-plain-generic * macOS (OS X): `MacTeX `_. * Windows: `Latex Project `_. Because nbconvert depends on packages and fonts included in standard TeX distributions, if you do not have a complete installation, you may not be able to use nbconvert's standard tooling to convert notebooks to PDF. Installing Chromium ------------------- For converting notebooks to PDF with ``--to webpdf``, nbconvert requires the `playwright `_ Chromium automation library. Playwright makes use of a specific version of Chromium. If it does not find a suitable installation of the web browser, it can automatically download it if the ``--allow-chromium-download`` flag is passed to the command line. To install a suitable version of playwright, you can pip install ``nbconvert[webpdf]``. PDF conversion on a limited TeX environment ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you are only able to install a limited TeX environment, there are two main routes you could take to convert to PDF: 1. Using TeX by hand a. You could convert to ``.tex`` directly; this requires Pandoc. b. edit the file to accord with your local environment c. run ``xelatex`` directly. 2. Custom exporter a. You could write a :ref:`custom exporter ` that takes your system's limitations into account. nbconvert-7.16.4/docs/source/latex_citations.rst000066400000000000000000000011161461373220400217660ustar00rootroot00000000000000LaTeX citations =============== ``nbconvert`` now has support for LaTeX citations. With this capability you can: * Manage citations using BibTeX. * Cite those citations in Markdown cells using HTML data attributes. * Have ``nbconvert`` generate proper LaTeX citations and run BibTeX. For an example of how this works, please see the `citations example`_ in the nbconvert-examples_ repository. .. _nbconvert-examples: https://github.com/jupyter/nbconvert-examples .. _citations example: https://nbviewer.jupyter.org/github/jupyter/nbconvert-examples/blob/master/citations/Tutorial.ipynb nbconvert-7.16.4/docs/source/nbconvert_library.ipynb000066400000000000000000000427021461373220400226370ustar00rootroot00000000000000{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Using nbconvert as a library\n", "\n", "In this notebook, you will be introduced to the programmatic API of nbconvert and how it can be used in various contexts. \n", "\n", "A great [blog post](http://jakevdp.github.io/blog/2013/04/15/code-golf-in-python-sudoku/) by [\\@jakevdp](https://github.com/jakevdp) will be used to demonstrate. This notebook will not focus on using the command line tool. The attentive reader will point-out that no data is read from or written to disk during the conversion process. This is because nbconvert has been designed to work in memory so that it works well in a database or web-based environment too." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Quick overview" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Credit: Jonathan Frederic (@jdfreder on github)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The main principle of nbconvert is to instantiate an `Exporter` that controls the pipeline through which notebooks are converted.\n", "\n", "First, download @jakevdp's notebook (if you do not have `requests`, install it by running `pip install requests`, or if you don't have pip installed, you can find it on PYPI):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "from urllib.request import urlopen\n", "\n", "url = \"https://jakevdp.github.io/downloads/notebooks/XKCD_plots.ipynb\"\n", "response = urlopen(url).read().decode()\n", "response[0:60] + \" ...\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The response is a JSON string which represents a Jupyter notebook. \n", "\n", "Next, we will read the response using nbformat. Doing this will guarantee that the notebook structure is valid. Note that the in-memory format and on disk format are slightly different. In particular, on disk, multiline strings might be split into a list of strings." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "import nbformat\n", "\n", "jake_notebook = nbformat.reads(response, as_version=4)\n", "jake_notebook.cells[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The nbformat API returns a special type of dictionary. For this example, you don't need to worry about the details of the structure (if you are interested, please see the [nbformat documentation](https://nbformat.readthedocs.io/en/latest/)).\n", "\n", "The nbconvert API exposes some basic exporters for common formats and defaults. You will start by using one of them. First, you will import one of these exporters (specifically, the HTML exporter), then instantiate it using most of the defaults, and then you will use it to process the notebook we downloaded earlier." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "from traitlets.config import Config\n", "\n", "# 1. Import the exporter\n", "from nbconvert import HTMLExporter\n", "\n", "# 2. Instantiate the exporter. We use the `classic` template for now; we'll get into more details\n", "# later about how to customize the exporter further.\n", "html_exporter = HTMLExporter(template_name=\"classic\")\n", "\n", "# 3. Process the notebook we loaded earlier\n", "(body, resources) = html_exporter.from_notebook_node(jake_notebook)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The exporter returns a tuple containing the source of the converted notebook, as well as a resources dict. In this case, the source is just raw HTML:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "print(body[:400] + \"...\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you understand HTML, you'll notice that some common tags are omitted, like the `body` tag. Those tags are included in the default `HtmlExporter`, which is what would have been constructed if we had not modified the `template_file`.\n", "\n", "The resource dict contains (among many things) the extracted `.png`, `.jpg`, etc. from the notebook when applicable. The basic HTML exporter leaves the figures as embedded base64, but you can configure it to extract the figures. So for now, the resource dict should be mostly empty, except for a key containing CSS and a few others whose content will be obvious:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "print(\"Resources:\", resources.keys())\n", "print(\"Metadata:\", resources[\"metadata\"].keys())\n", "print(\"Inlining:\", resources[\"inlining\"].keys())\n", "print(\"Extension:\", resources[\"output_extension\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Exporter`s are stateless, so you won't be able to extract any useful information beyond their configuration. You can re-use an exporter instance to convert another notebook. In addition to the `from_notebook_node` used above, each exporter exposes `from_file` and `from_filename` methods." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Extracting Figures using the RST Exporter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When exporting, you may want to extract the base64 encoded figures as files. While the HTML exporter does not do this by default, the `RstExporter` does:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "# Import the RST exproter\n", "from nbconvert import RSTExporter\n", "\n", "# Instantiate it\n", "rst_exporter = RSTExporter()\n", "# Convert the notebook to RST format\n", "(body, resources) = rst_exporter.from_notebook_node(jake_notebook)\n", "\n", "print(body[:970] + \"...\")\n", "print(\"[.....]\")\n", "print(body[800:1200] + \"...\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that base64 images are not embedded, but instead there are filename-like strings, such as `output_3_0.png`. The strings actually are (configurable) keys that map to the binary data in the resources dict.\n", "\n", "Note, if you write an RST Plugin, you are responsible for writing all the files to the disk (or uploading, etc...) in the right location. Of course, the naming scheme is configurable.\n", "\n", "As an exercise, this notebook will show you how to get one of those images. First, take a look at the `'outputs'` of the returned resources dictionary. This is a dictionary that contains a key for each extracted resource, with values corresponding to the actual base64 encoding:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "sorted(resources[\"outputs\"].keys())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case, there are 5 extracted binary figures, all `png`s. We can use the Image display object to actually display one of the images:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "from IPython.display import Image\n", "\n", "Image(data=resources[\"outputs\"][\"output_3_0.png\"], format=\"png\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that this image is being rendered without ever reading or writing to the disk." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Extracting Figures using the HTML Exporter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As mentioned above, by default, the HTML exporter does not extract images -- it just leaves them as inline base64 encodings. However, this is not always what you might want. For example, here is a use case from @jakevdp:\n", "\n", "> I write an [awesome blog](http://jakevdp.github.io/) using Jupyter notebooks converted to HTML, and I want the images to be cached. Having one html file with all of the images base64 encoded inside it is nice when sharing with a coworker, but for a website, not so much. I need an HTML exporter, and I want it to extract the figures!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Some theory\n", "\n", "Before we get into actually extracting the figures, it will be helpful to give a high-level overview of the process of converting a notebook to a another format:\n", "\n", "1. Retrieve the notebook and it's accompanying resources (you are responsible for this).\n", "2. Feed the notebook into the `Exporter`, which:\n", " 1. Sequentially feeds the notebook into an array of `Preprocessor`s. Preprocessors only act on the **structure** of the notebook, and have unrestricted access to it. \n", " 2. Feeds the notebook into the Jinja templating engine, which converts it to a particular format depending on which template is selected.\n", "3. The exporter returns the converted notebook and other relevant resources as a tuple.\n", "4. You write the data to the disk using the built-in `FilesWriter` (which writes the notebook and any extracted files to disk), or elsewhere using a custom `Writer`.\n", "\n", "### Using different preprocessors\n", "\n", "To extract the figures when using the HTML exporter, we will want to change which `Preprocessor`s we are using. There are several preprocessors that come with nbconvert, including one called the `ExtractOutputPreprocessor`.\n", "\n", "The `ExtractOutputPreprocessor` is responsible for crawling the notebook, finding all of the figures, and putting them into the resources directory, as well as choosing the key (i.e. `filename_xx_y.extension`) that can replace the figure inside the template. To enable the `ExtractOutputPreprocessor`, we must add it to the exporter's list of preprocessors:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "# create a configuration object that changes the preprocessors\n", "from traitlets.config import Config\n", "\n", "c = Config()\n", "c.HTMLExporter.preprocessors = [\"nbconvert.preprocessors.ExtractOutputPreprocessor\"]\n", "\n", "# create the new exporter using the custom config\n", "html_exporter_with_figs = HTMLExporter(config=c)\n", "html_exporter_with_figs.preprocessors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can compare the result of converting the notebook using the original HTML exporter and our new customized one:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "(_, resources) = html_exporter.from_notebook_node(jake_notebook)\n", "(_, resources_with_fig) = html_exporter_with_figs.from_notebook_node(jake_notebook)\n", "\n", "print(\"resources without figures:\")\n", "print(sorted(resources.keys()))\n", "\n", "print(\"\\nresources with extracted figures (notice that there's one more field called 'outputs'):\")\n", "print(sorted(resources_with_fig.keys()))\n", "\n", "print(\"\\nthe actual figures are:\")\n", "print(sorted(resources_with_fig[\"outputs\"].keys()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Custom Preprocessors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are an endless number of transformations that you may want to apply to a notebook. In particularly complicated cases, you may want to actually create your own `Preprocessor`. Above, when we customized the list of preprocessors accepted by the `HTMLExporter`, we passed in a string -- this can be any valid module name. So, if you create your own preprocessor, you can include it in that same list and it will be used by the exporter.\n", "\n", "To create your own preprocessor, you will need to subclass from `nbconvert.preprocessors.Preprocessor` and overwrite either the `preprocess` and/or `preprocess_cell` methods." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following demonstration adds the ability to exclude a cell by index. \n", "\n", "Note: injecting cells is similar, and won't be covered here. If you want to inject static content at the beginning/end of a notebook, use a custom template." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "from traitlets import Integer\n", "\n", "from nbconvert.preprocessors import Preprocessor\n", "\n", "\n", "class PelicanSubCell(Preprocessor):\n", " \"\"\"A Pelican specific preprocessor to remove some of the cells of a notebook\"\"\"\n", "\n", " # I could also read the cells from nb.metadata.pelican if someone wrote a JS extension,\n", " # but for now I'll stay with configurable value.\n", " start = Integer(0, help=\"first cell of notebook to be converted\").tag(config=True)\n", " end = Integer(-1, help=\"last cell of notebook to be converted\").tag(config=True)\n", "\n", " def preprocess(self, nb, resources):\n", " self.log.info(\"I'll keep only cells from %d to %d\", self.start, self.end)\n", " nb.cells = nb.cells[self.start : self.end]\n", " return nb, resources" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here a Pelican exporter is created that takes `PelicanSubCell` preprocessors and a `config` object as parameters. This may seem redundant, but with the configuration system you can register an inactive preprocessor on all of the exporters and activate it from config files or the command line. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "# Create a new config object that configures both the new preprocessor, as well as the exporter\n", "c = Config()\n", "c.PelicanSubCell.start = 4\n", "c.PelicanSubCell.end = 6\n", "c.RSTExporter.preprocessors = [PelicanSubCell]\n", "\n", "# Create our new, customized exporter that uses our custom preprocessor\n", "pelican = RSTExporter(config=c)\n", "\n", "# Process the notebook\n", "print(pelican.from_notebook_node(jake_notebook)[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Programmatically creating templates" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "from jinja2 import DictLoader\n", "\n", "dl = DictLoader(\n", " {\n", " \"footer\": \"\"\"\n", "{%- extends 'lab/index.html.j2' -%}\n", "\n", "{% block footer %}\n", "FOOOOOOOOTEEEEER\n", "{% endblock footer %}\n", "\"\"\"\n", " }\n", ")\n", "\n", "\n", "exportHTML = HTMLExporter(extra_loaders=[dl], template_file=\"footer\")\n", "(body, resources) = exportHTML.from_notebook_node(jake_notebook)\n", "for l in body.split(\"\\n\")[-4:]:\n", " print(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Real World Uses" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "@jakevdp uses Pelican and Jupyter Notebook to blog. Pelican [will use](https://github.com/getpelican/pelican-plugins/pull/21) nbconvert programmatically to generate blog post. Have a look a [Pythonic Preambulations](http://jakevdp.github.io/) for Jake's blog post." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "@damianavila wrote the Nikola Plugin to [write blog post as Notebooks](http://damianavila.github.io/blog/posts/one-line-deployment-of-your-site-to-gh-pages.html) and is developing a js-extension to publish notebooks via one click from the web app." ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.2" } }, "nbformat": 4, "nbformat_minor": 4 } nbconvert-7.16.4/docs/source/need_help.rst000066400000000000000000000021511461373220400205170ustar00rootroot00000000000000Need help? ========== Technical Support ----------------- - `GitHub Issues and Bug Reports `_. A place to report bugs or regressions found for nbconvert - `Community Technical Support and Discussion - Jupyter Discourse `_ : A place for installation, configuration, and troubleshooting assistance by the Jupyter community. As a non-profit project with maintainers who are primarily volunteers, we rely on the community for technical support. Please use Discourse to ask questions and share your knowledge. Documentation ------------- - `Documentation for Jupyter nbconvert `_ `PDF `_ - `nbconvert examples repo on GitHub `_ - `Documentation for Project Jupyter `_ Jupyter Resources ----------------- - `Jupyter mailing list `_ - `Project Jupyter website `_ nbconvert-7.16.4/docs/source/removing_cells.rst000066400000000000000000000067041461373220400216140ustar00rootroot00000000000000Removing cells, inputs, or outputs ================================== .. currentmodule:: nbconvert.preprocessors When converting Notebooks into other formats, it is possible to remove parts of a cell, or entire cells, using preprocessors. The notebook will remain unchanged, but the outputs will have certain pieces removed. Here are two primary ways to accomplish this. Removing pieces of cells using cell tags ---------------------------------------- The most straightforward way to control which pieces of cells are removed is to use **cell tags**. These are single-string snippets of metadata that are stored in each cells "tag" field. The ``TagRemovePreprocessor`` can be used to remove inputs, outputs, or entire cells. For example, here is a configuration that uses a different tag for removing each part of a cell with the HTMLExporter. In this case, we demonstrate using the nbconvert Python API. .. code-block:: python from traitlets.config import Config import nbformat as nbf from nbconvert.exporters import HTMLExporter from nbconvert.preprocessors import TagRemovePreprocessor # Setup config c = Config() # Configure tag removal - be sure to tag your cells to remove using the # words remove_cell to remove cells. You can also modify the code to use # a different tag word c.TagRemovePreprocessor.remove_cell_tags = ("remove_cell",) c.TagRemovePreprocessor.remove_all_outputs_tags = ("remove_output",) c.TagRemovePreprocessor.remove_input_tags = ("remove_input",) c.TagRemovePreprocessor.enabled = True # Configure and run out exporter c.HTMLExporter.preprocessors = ["nbconvert.preprocessors.TagRemovePreprocessor"] exporter = HTMLExporter(config=c) exporter.register_preprocessor(TagRemovePreprocessor(config=c), True) # Configure and run our exporter - returns a tuple - first element with html, # second with notebook metadata output = HTMLExporter(config=c).from_filename("your-notebook-file-path.ipynb") # Write to output html file with open("your-output-file-name.html", "w") as f: f.write(output[0]) This additional example demonstrates using the CLI to remove cells with a certain cell tag .. code-block:: sh jupyter nbconvert mynotebook.ipynb --TagRemovePreprocessor.enabled=True --TagRemovePreprocessor.remove_cell_tags remove_cell Removing cells using Regular Expressions on cell content -------------------------------------------------------- Sometimes you'd rather remove cells based on their _content_ rather than their tags. In this case, you can use the ``RegexRemovePreprocessor``. You initialize this preprocessor with a single ``patterns`` configuration, which is a list of strings. For each cell, this preprocessor checks whether the cell contents match any of the strings provided in ``patterns``. If the contents match any of the patterns, the cell is removed from the notebook. For example, execute the following command to convert a notebook to html and remove cells containing only whitespace: .. code-block:: bash jupyter nbconvert --RegexRemovePreprocessor.patterns="['\s*\Z']" mynotebook.ipynb The command line argument sets the list of patterns to ``'\s*\Z'`` which matches an arbitrary number of whitespace characters followed by the end of the string. See https://regex101.com/ for an interactive guide to regular expressions (make sure to select the python flavor). See https://docs.python.org/library/re.html for the official regular expression documentation in python. nbconvert-7.16.4/docs/source/usage.rst000066400000000000000000000267471461373220400177210ustar00rootroot00000000000000.. highlight:: none Using as a command line tool ============================ The command-line syntax to run the ``nbconvert`` script is:: $ jupyter nbconvert --to FORMAT notebook.ipynb This will convert the Jupyter notebook file ``notebook.ipynb`` into the output format given by the ``FORMAT`` string. Default output format --------------------- In 5.x versions of nbconvert the default output format was html. In 6.0 the default was removed, requiring CLI calls to explicitly set a ``--to`` argument in order to execute. To mimic original 5.x behavior one should add ``--to=html`` to the ``jupyter nbconvert`` command. .. _supported_output: Supported output formats ------------------------ The currently supported output formats are: - :ref:`HTML `, - :ref:`LaTeX `, - :ref:`PDF `, - :ref:`WebPDF `, - :ref:`Reveal.js HTML slideshow `, - :ref:`Markdown `, - :ref:`Ascii `, - :ref:`reStructuredText `, - :ref:`executable script `, - :ref:`notebook `. Jupyter also provides a few templates for output formats. These can be specified via an additional ``--template`` argument and are listed in the sections below. .. _convert_html: HTML ~~~~ * ``--to html`` HTML Export. Note on backward compatibility: Be aware that if you were using custom copies of the old 5.x template files (i.e. ``--template``), you will now need to use ``--template-file path/to/old/file.tpl`` in order to use that file in compatibility mode as opposed to other options. - ``--template lab`` (default) A full static HTML render of the notebook. This looks very similar to the JupyterLab interactive view. The lab template supports the extra ``--theme`` option, which defaults to ``light``. This extra option not only allows you to use the default ``light`` or ``dark`` themes provided by JupyterLab, but it allows you to use custom themes. For example: ``pip install jupyterlab-miami-nights`` then ``--theme jupyterlab_miami_nights``. - ``--template classic`` Simplified HTML, using the classic jupyter look and feel. - ``--template basic`` Base HTML, rendering with minimal structure and styles. - ``--embed-images`` If this option is provided, embed images as base64 urls in the resulting HTML file. .. _convert_latex: LaTeX ~~~~~ * ``--to latex`` Latex export. This generates ``NOTEBOOK_NAME.tex`` file, ready for export. Images are output as .png files in a folder. - ``--template article`` (default) Latex article, derived from Sphinx's howto template. - ``--template report`` Latex report, providing a table of contents and chapters. Optionally you can specify ``authors``, ``title`` and ``date`` in the notebook's metadata. These will be used to render the header of the LaTeX document. .. code-block:: json { "authors": [ { "name": "Jane Doe" }, { "name": "John Doe" } ], "date": "January 2023", "title": "Annual Data Report 2022", "kernelspec": { }, "language_info": { } } If no date is specified, today's date will be used (i.e. the date when the document is re/compiled). Use an empty string to suppress the date. The values in the notebook can be overridden by the command line arguments ``--LatexPreprocessor.title``, ``--LatexPreprocessor.date`` and ``--LatexPreprocessor.author_names`` (specify this argument multiple times for each individual author name). .. note:: nbconvert uses pandoc_ to convert between various markup languages, so pandoc is a dependency when converting to latex or reStructuredText. .. _convert_pdf: PDF ~~~ * ``--to pdf`` Generates a PDF via latex. Supports the same templates as ``--to latex``. .. _convert_webpdf: WebPDF ~~~~~~ * ``--to webpdf`` Generates a PDF by first rendering to HTML, rendering the HTML Chromium headless, and exporting to PDF. This exporter supports the same templates as ``--to html``. The webpdf exporter requires the ``playwright`` Chromium automation library, which can be installed via ``nbconvert[webpdf]``. .. _convert_revealjs: Reveal.js HTML slideshow ~~~~~~~~~~~~~~~~~~~~~~~~ .. note:: In order to designate a mapping from notebook cells to Reveal.js slides, from within the Jupyter notebook, select menu item View --> Cell Toolbar --> Slideshow. That will reveal a drop-down menu on the upper-right of each cell. From it, one may choose from "Slide," "Sub-Slide", "Fragment", "Skip", and "Notes." On conversion, cells designated as "skip" will not be included, "notes" will be included only in presenter notes, etc. * ``--to slides`` This generates a Reveal.js HTML slideshow. Running this slideshow requires a copy of reveal.js (version 4.x). By default, this will include a script tag in the html that will directly load reveal.js from a public CDN. This means that if you include your slides on a webpage, they should work as expected. However, some features (specifically, speaker notes & timers) will not work on website because they require access to a local copy of reveal.js. Speaker notes require a local copy of reveal.js. Then, you need to tell ``nbconvert`` how to find that local copy. Timers only work if you already have speaker notes, but also require a local https server. You can read more about this in ServePostProcessorExample_. To make this clearer, let's look at an example of how to get speaker notes working with a local copy of reveal.js: SlidesWithNotesExample_. .. _SlidesWithNotesExample: Example: creating slides w/ speaker notes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Let's suppose you have a notebook ``your_talk.ipynb`` that you want to convert to slides. For this example, we'll assume that you are working in the same directory as the notebook you want to convert (i.e., when you run ``ls .``, ``your_talk.ipynb`` shows up amongst the list of files). First, we need a copy of reveal.js in the same directory as your slides. One way to do this is to use the following commands in your terminal: .. code-block:: shell git clone https://github.com/hakimel/reveal.js.git cd reveal.js git checkout 3.5.0 cd .. Then we need to tell nbconvert to point to this local copy. To do that we use the ``--reveal-prefix`` command line flag to point to the local copy. .. code-block:: shell jupyter nbconvert your_talk.ipynb --to slides --reveal-prefix reveal.js This will create file ``your_talk.slides.html``, which you should be able to access with ``open your_talk.slides.html``. To access the speaker notes, press ``s`` after the slides load and they should open in a new window. Note: This does not enable slides that run completely offline. While you have a local copy of reveal.js, by default, the slides need to access mathjax, require, and jquery via a public CDN. Addressing this use case is an open issue and `PRs `_ are always encouraged. .. _ServePostProcessorExample: Serving slides with an https server: ``--post serve`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Once you have speaker notes working you may notice that your timers don't work. Timers require a bit more infrastructure; you need to serve your local copy of reveal.js from a local https server. Fortunately, ``nbconvert`` makes this fairly straightforward through the use of the ``ServePostProcessor``. To activate this server, we append the command line flag ``--post serve`` to our call to nbconvert. .. code-block:: shell jupyter nbconvert your_talk.ipynb --to slides --reveal-prefix reveal.js --post serve This will run the server, which will occupy the terminal that you ran the command in until you stop it. You can stop the server by pressing ``ctrl C`` twice. .. _convert_markdown: Markdown ~~~~~~~~ * ``--to markdown`` Simple markdown output. Markdown cells are unaffected, and code cells indented 4 spaces. Images are output as .png files in a folder. .. _convert_ascii: Ascii ~~~~~~~~ * ``--to asciidoc`` Ascii output. Images are output as .png files in a folder. .. _convert_rst: reStructuredText ~~~~~~~~~~~~~~~~ * ``--to rst`` Basic reStructuredText output. Useful as a starting point for embedding notebooks in Sphinx docs. Images are output as .png files in a folder. .. note:: nbconvert uses pandoc_ to convert between various markup languages, so pandoc is a dependency when converting to LaTeX or reStructuredText. .. _convert_script: Executable script ~~~~~~~~~~~~~~~~~ * ``--to script`` Convert a notebook to an executable script. This is the simplest way to get a Python (or other language, depending on the kernel) script out of a notebook. If there were any magics in an Jupyter notebook, this may only be executable from a Jupyter session. For example, to convert a Julia notebook to a Julia executable script:: jupyter nbconvert --to script my_julia_notebook.ipynb .. _convert_notebook: Notebook and preprocessors ~~~~~~~~~~~~~~~~~~~~~~~~~~ * ``--to notebook`` .. versionadded:: 3.0 This doesn't convert a notebook to a different format *per se*, instead it allows the running of nbconvert preprocessors on a notebook, and/or conversion to other notebook formats. For example:: jupyter nbconvert --to notebook --execute mynotebook.ipynb This will open the notebook, execute it, capture new output, and save the result in :file:`mynotebook.nbconvert.ipynb`. Specifying ``--inplace`` will overwrite the input file instead of writing a new file. By default, ``nbconvert`` will abort conversion if any exceptions occur during execution of a cell. If you specify ``--allow-errors`` (in addition to the ``--execute`` flag) then conversion will continue and the output from any exception will be included in the cell output. The following command:: jupyter nbconvert --to notebook --nbformat 3 mynotebook will create a copy of :file:`mynotebook.ipynb` in :file:`mynotebook.v3.ipynb` in version 3 of the notebook format. If you want to convert a notebook in-place, you can specify the output file to be the same as the input file:: jupyter nbconvert --to notebook mynb --output mynb Be careful with that, since it will replace the input file. .. note:: nbconvert uses pandoc_ to convert between various markup languages, so pandoc is a dependency when converting to latex or reStructuredText. .. _pandoc: https://pandoc.org/ The output file created by ``nbconvert`` will have the same base name as the notebook and will be placed in the current working directory. Any supporting files (graphics, etc) will be placed in a new directory with the same base name as the notebook, suffixed with ``_files``:: $ jupyter nbconvert notebook.ipynb $ ls notebook.ipynb notebook.html notebook_files/ For simple single-file output, such as html, markdown, etc., the output may be sent to standard output with:: $ jupyter nbconvert --to markdown notebook.ipynb --stdout Converting multiple notebooks ----------------------------- Multiple notebooks can be specified from the command line:: $ jupyter nbconvert notebook*.ipynb $ jupyter nbconvert notebook1.ipynb notebook2.ipynb or via a list in a configuration file, say ``mycfg.py``, containing the text: .. code-block:: python c = get_config() c.NbConvertApp.notebooks = ["notebook1.ipynb", "notebook2.ipynb"] and using the command:: $ jupyter nbconvert --config mycfg.py nbconvert-7.16.4/hatch_build.py000066400000000000000000000051321461373220400164340ustar00rootroot00000000000000"""Custom build script for hatch backend""" import os import sys from urllib.request import urlopen from hatchling.builders.hooks.plugin.interface import BuildHookInterface notebook_css_version = "5.4.0" notebook_css_url = "https://cdn.jupyter.org/notebook/%s/style/style.min.css" % notebook_css_version jupyterlab_css_version = "4.0.2" jupyterlab_css_url = ( "https://unpkg.com/@jupyterlab/nbconvert-css@%s/style/index.css" % jupyterlab_css_version ) jupyterlab_theme_light_version = "4.0.2" jupyterlab_theme_light_url = ( "https://unpkg.com/@jupyterlab/theme-light-extension@%s/style/variables.css" % jupyterlab_theme_light_version ) jupyterlab_theme_dark_version = "4.0.2" jupyterlab_theme_dark_url = ( "https://unpkg.com/@jupyterlab/theme-dark-extension@%s/style/variables.css" % jupyterlab_theme_dark_version ) template_css_urls = { "lab": [ (jupyterlab_css_url, "index.css"), (jupyterlab_theme_light_url, "theme-light.css"), (jupyterlab_theme_dark_url, "theme-dark.css"), ], "classic": [(notebook_css_url, "style.css")], } osp = os.path here = osp.abspath(osp.dirname(__file__)) templates_dir = osp.join(here, "share", "templates") def _get_css_file(template_name, url, filename): """Get a css file and download it to the templates dir""" directory = osp.join(templates_dir, template_name, "static") dest = osp.join(directory, filename) if osp.exists(dest): print("Already have CSS: %s, moving on." % dest) return if not osp.exists(directory): os.makedirs(directory) print("Downloading CSS: %s" % url) try: css = urlopen(url).read() # noqa: S310 except Exception as e: msg = f"Failed to download css from {url}: {e}" print(msg, file=sys.stderr) msg = "Need CSS to proceed." raise OSError(msg) from None return with open(dest, "wb") as f: f.write(css) print("Downloaded Notebook CSS to %s" % dest) def _get_css_files(): """Get all of the css files if necessary""" in_checkout = osp.exists(osp.abspath(osp.join(here, "..", ".git"))) if in_checkout: print("Not running from git, nothing to do") return for template_name, resources in template_css_urls.items(): for url, filename in resources: _get_css_file(template_name, url, filename) class CustomHook(BuildHookInterface): """A custom build hook for nbconvert.""" def initialize(self, version, build_data): """Initialize the hook.""" if self.target_name not in ["wheel", "sdist"]: return _get_css_files() nbconvert-7.16.4/nbconvert/000077500000000000000000000000001461373220400156135ustar00rootroot00000000000000nbconvert-7.16.4/nbconvert/__init__.py000066400000000000000000000025241461373220400177270ustar00rootroot00000000000000"""Utilities for converting notebooks to and from different formats.""" from ._version import __version__, version_info try: from . import filters, postprocessors, preprocessors, writers from .exporters import ( ASCIIDocExporter, Exporter, ExporterNameError, FilenameExtension, HTMLExporter, LatexExporter, MarkdownExporter, NotebookExporter, PDFExporter, PythonExporter, QtPDFExporter, QtPNGExporter, RSTExporter, ScriptExporter, SlidesExporter, TemplateExporter, WebPDFExporter, export, get_export_names, get_exporter, ) except ModuleNotFoundError: # We hit this condition when the package is not yet fully installed. pass __all__ = [ "__version__", "version_info", "filters", "postprocessors", "preprocessors", "writers", "ASCIIDocExporter", "ExporterNameError", "export", "get_export_names", "get_exporter", "Exporter", "FilenameExtension", "HTMLExporter", "LatexExporter", "MarkdownExporter", "NotebookExporter", "PDFExporter", "PythonExporter", "QtPDFExporter", "QtPNGExporter", "RSTExporter", "ScriptExporter", "SlidesExporter", "TemplateExporter", "WebPDFExporter", ] nbconvert-7.16.4/nbconvert/__main__.py000066400000000000000000000001111461373220400176760ustar00rootroot00000000000000"""nbconvert cli entry point.""" from .nbconvertapp import main main() nbconvert-7.16.4/nbconvert/_version.py000066400000000000000000000007541461373220400200170ustar00rootroot00000000000000"""nbconvert version info.""" import re from typing import List # Version string must appear intact for versioning __version__ = "7.16.4" # Build up version_info tuple for backwards compatibility pattern = r"(?P\d+).(?P\d+).(?P\d+)(?P.*)" match = re.match(pattern, __version__) assert match is not None parts: List[object] = [int(match[part]) for part in ["major", "minor", "patch"]] if match["rest"]: parts.append(match["rest"]) version_info = tuple(parts) nbconvert-7.16.4/nbconvert/conftest.py000066400000000000000000000003021461373220400200050ustar00rootroot00000000000000"""pytest configuration.""" import asyncio import os if os.name == "nt": asyncio.set_event_loop_policy( asyncio.WindowsSelectorEventLoopPolicy() # type:ignore[attr-defined] ) nbconvert-7.16.4/nbconvert/exporters/000077500000000000000000000000001461373220400176465ustar00rootroot00000000000000nbconvert-7.16.4/nbconvert/exporters/__init__.py000066400000000000000000000021761461373220400217650ustar00rootroot00000000000000from .asciidoc import ASCIIDocExporter from .base import ExporterDisabledError, ExporterNameError, export, get_export_names, get_exporter from .exporter import Exporter, FilenameExtension, ResourcesDict from .html import HTMLExporter from .latex import LatexExporter from .markdown import MarkdownExporter from .notebook import NotebookExporter from .pdf import PDFExporter from .python import PythonExporter from .qtpdf import QtPDFExporter from .qtpng import QtPNGExporter from .rst import RSTExporter from .script import ScriptExporter from .slides import SlidesExporter from .templateexporter import TemplateExporter from .webpdf import WebPDFExporter __all__ = [ "ASCIIDocExporter", "ExporterNameError", "ExporterDisabledError", "export", "get_export_names", "get_exporter", "Exporter", "FilenameExtension", "HTMLExporter", "LatexExporter", "MarkdownExporter", "NotebookExporter", "PDFExporter", "PythonExporter", "QtPDFExporter", "QtPNGExporter", "ResourcesDict", "RSTExporter", "ScriptExporter", "SlidesExporter", "TemplateExporter", "WebPDFExporter", ] nbconvert-7.16.4/nbconvert/exporters/asciidoc.py000066400000000000000000000027721461373220400220060ustar00rootroot00000000000000"""ASCIIDoc Exporter class""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. from traitlets import default from traitlets.config import Config from .templateexporter import TemplateExporter class ASCIIDocExporter(TemplateExporter): """ Exports to an ASCIIDoc document (.asciidoc) """ @default("file_extension") def _file_extension_default(self): return ".asciidoc" @default("template_name") def _template_name_default(self): return "asciidoc" output_mimetype = "text/asciidoc" export_from_notebook = "AsciiDoc" @default("raw_mimetypes") def _raw_mimetypes_default(self): return ["text/asciidoc/", "text/markdown", "text/html", ""] @property def default_config(self): c = Config( { "NbConvertBase": { "display_data_priority": [ "text/html", "text/markdown", "image/svg+xml", "image/png", "image/jpeg", "text/plain", "text/latex", ] }, "ExtractOutputPreprocessor": {"enabled": True}, "HighlightMagicsPreprocessor": {"enabled": True}, } ) if super().default_config: c2 = super().default_config.copy() c2.merge(c) c = c2 return c nbconvert-7.16.4/nbconvert/exporters/base.py000066400000000000000000000115541461373220400211400ustar00rootroot00000000000000"""Module containing single call export functions.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import os import sys if sys.version_info < (3, 10): from importlib_metadata import entry_points # type:ignore[import-not-found] else: from importlib.metadata import entry_points from nbformat import NotebookNode from traitlets.config import get_config from traitlets.log import get_logger from traitlets.utils.importstring import import_item from .exporter import Exporter # ----------------------------------------------------------------------------- # Functions # ----------------------------------------------------------------------------- __all__ = [ "export", "Exporter", "get_exporter", "get_export_names", "ExporterNameError", ] class ExporterNameError(NameError): """An exporter name error.""" class ExporterDisabledError(ValueError): """An exporter disabled error.""" def export(exporter, nb, **kw): """ Export a notebook object using specific exporter class. Parameters ---------- exporter : ``Exporter`` class or instance Class or instance of the exporter that should be used. If the method initializes its own instance of the class, it is ASSUMED that the class type provided exposes a constructor (``__init__``) with the same signature as the base Exporter class. nb : :class:`~nbformat.NotebookNode` The notebook to export. config : config (optional, keyword arg) User configuration instance. resources : dict (optional, keyword arg) Resources used in the conversion process. Returns ------- tuple output : str The resulting converted notebook. resources : dictionary Dictionary of resources used prior to and during the conversion process. """ # Check arguments if exporter is None: msg = "Exporter is None" raise TypeError(msg) if not isinstance(exporter, Exporter) and not issubclass(exporter, Exporter): msg = "exporter does not inherit from Exporter (base)" raise TypeError(msg) if nb is None: msg = "nb is None" raise TypeError(msg) # Create the exporter resources = kw.pop("resources", None) exporter_instance = exporter if isinstance(exporter, Exporter) else exporter(**kw) # Try to convert the notebook using the appropriate conversion function. if isinstance(nb, NotebookNode): output, resources = exporter_instance.from_notebook_node(nb, resources) elif isinstance(nb, (str,)): output, resources = exporter_instance.from_filename(nb, resources) else: output, resources = exporter_instance.from_file(nb, resources) return output, resources def get_exporter(name, config=get_config()): # noqa: B008 """Given an exporter name or import path, return a class ready to be instantiated Raises ExporterName if exporter is not found or ExporterDisabledError if not enabled """ if name == "ipynb": name = "notebook" try: exporters = entry_points(group="nbconvert.exporters") items = [e for e in exporters if e.name == name or e.name == name.lower()] exporter = items[0].load() if getattr(exporter(config=config), "enabled", True): return exporter raise ExporterDisabledError('Exporter "%s" disabled in configuration' % (name)) except IndexError: pass if "." in name: try: exporter = import_item(name) if getattr(exporter(config=config), "enabled", True): return exporter raise ExporterDisabledError('Exporter "%s" disabled in configuration' % (name)) except ImportError: log = get_logger() log.error("Error importing %s", name, exc_info=True) # noqa: G201 msg = 'Unknown exporter "{}", did you mean one of: {}?'.format( name, ", ".join(get_export_names()) ) raise ExporterNameError(msg) def get_export_names(config=get_config()): # noqa: B008 """Return a list of the currently supported export targets Exporters can be found in external packages by registering them as an nbconvert.exporter entrypoint. """ exporters = sorted(e.name for e in entry_points(group="nbconvert.exporters")) if os.environ.get("NBCONVERT_DISABLE_CONFIG_EXPORTERS"): get_logger().info( "Config exporter loading disabled, no additional exporters will be automatically included." ) return exporters enabled_exporters = [] for exporter_name in exporters: try: e = get_exporter(exporter_name)(config=config) if e.enabled: enabled_exporters.append(exporter_name) except (ExporterDisabledError, ValueError): pass return enabled_exporters nbconvert-7.16.4/nbconvert/exporters/exporter.py000066400000000000000000000311151461373220400220710ustar00rootroot00000000000000"""This module defines a base Exporter class. For Jinja template-based export, see templateexporter.py. """ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. from __future__ import annotations import collections import copy import datetime import os import sys import typing as t import nbformat from nbformat import NotebookNode, validator from traitlets import Bool, HasTraits, List, TraitError, Unicode from traitlets.config import Config from traitlets.config.configurable import LoggingConfigurable from traitlets.utils.importstring import import_item class ResourcesDict(collections.defaultdict): # type:ignore[type-arg] """A default dict for resources.""" def __missing__(self, key): """Handle missing value.""" return "" class FilenameExtension(Unicode): # type:ignore[type-arg] """A trait for filename extensions.""" default_value = "" info_text = "a filename extension, beginning with a dot" def validate(self, obj, value): """Validate the file name.""" # cast to proper unicode value = super().validate(obj, value) # check that it starts with a dot if value and not value.startswith("."): msg = "FileExtension trait '{}' does not begin with a dot: {!r}" raise TraitError(msg.format(self.name, value)) return value class Exporter(LoggingConfigurable): """ Class containing methods that sequentially run a list of preprocessors on a NotebookNode object and then return the modified NotebookNode object and accompanying resources dict. """ enabled = Bool(True, help="Disable this exporter (and any exporters inherited from it).").tag( config=True ) file_extension = FilenameExtension( help="Extension of the file that should be written to disk" ).tag(config=True) optimistic_validation = Bool( False, help="Reduces the number of validation steps so that it only occurs after all preprocesors have run.", ).tag(config=True) # MIME type of the result file, for HTTP response headers. # This is *not* a traitlet, because we want to be able to access it from # the class, not just on instances. output_mimetype = "" # Should this converter be accessible from the notebook front-end? # If so, should be a friendly name to display (and possibly translated). export_from_notebook: str = None # type:ignore[assignment] # Configurability, allows the user to easily add filters and preprocessors. preprocessors: List[t.Any] = List( help="""List of preprocessors, by name or namespace, to enable.""" ).tag(config=True) _preprocessors: List[t.Any] = List() default_preprocessors: List[t.Any] = List( [ "nbconvert.preprocessors.TagRemovePreprocessor", "nbconvert.preprocessors.RegexRemovePreprocessor", "nbconvert.preprocessors.ClearOutputPreprocessor", "nbconvert.preprocessors.CoalesceStreamsPreprocessor", "nbconvert.preprocessors.ExecutePreprocessor", "nbconvert.preprocessors.SVG2PDFPreprocessor", "nbconvert.preprocessors.LatexPreprocessor", "nbconvert.preprocessors.HighlightMagicsPreprocessor", "nbconvert.preprocessors.ExtractOutputPreprocessor", "nbconvert.preprocessors.ExtractAttachmentsPreprocessor", "nbconvert.preprocessors.ClearMetadataPreprocessor", ], help="""List of preprocessors available by default, by name, namespace, instance, or type.""", ).tag(config=True) def __init__(self, config=None, **kw): """ Public constructor Parameters ---------- config : ``traitlets.config.Config`` User configuration instance. `**kw` Additional keyword arguments passed to parent __init__ """ with_default_config = self.default_config if config: with_default_config.merge(config) super().__init__(config=with_default_config, **kw) self._init_preprocessors() self._nb_metadata = {} @property def default_config(self): return Config() def from_notebook_node( self, nb: NotebookNode, resources: t.Any | None = None, **kw: t.Any ) -> tuple[NotebookNode, dict[str, t.Any]]: """ Convert a notebook from a notebook node instance. Parameters ---------- nb : :class:`~nbformat.NotebookNode` Notebook node (dict-like with attr-access) resources : dict Additional resources that can be accessed read/write by preprocessors and filters. `**kw` Ignored """ nb_copy = copy.deepcopy(nb) resources = self._init_resources(resources) if "language" in nb["metadata"]: resources["language"] = nb["metadata"]["language"].lower() # Preprocess nb_copy, resources = self._preprocess(nb_copy, resources) notebook_name = "" if resources is not None: name = resources.get("metadata", {}).get("name", "") path = resources.get("metadata", {}).get("path", "") notebook_name = os.path.join(path, name) self._nb_metadata[notebook_name] = nb_copy.metadata return nb_copy, resources def from_filename( self, filename: str, resources: dict[str, t.Any] | None = None, **kw: t.Any ) -> tuple[NotebookNode, dict[str, t.Any]]: """ Convert a notebook from a notebook file. Parameters ---------- filename : str Full filename of the notebook file to open and convert. resources : dict Additional resources that can be accessed read/write by preprocessors and filters. `**kw` Ignored """ # Pull the metadata from the filesystem. if resources is None: resources = ResourcesDict() if "metadata" not in resources or resources["metadata"] == "": resources["metadata"] = ResourcesDict() path, basename = os.path.split(filename) notebook_name = os.path.splitext(basename)[0] resources["metadata"]["name"] = notebook_name resources["metadata"]["path"] = path modified_date = datetime.datetime.fromtimestamp( os.path.getmtime(filename), tz=datetime.timezone.utc ) # datetime.strftime date format for ipython if sys.platform == "win32": date_format = "%B %d, %Y" else: date_format = "%B %-d, %Y" resources["metadata"]["modified_date"] = modified_date.strftime(date_format) with open(filename, encoding="utf-8") as f: return self.from_file(f, resources=resources, **kw) def from_file( self, file_stream: t.Any, resources: dict[str, t.Any] | None = None, **kw: t.Any ) -> tuple[NotebookNode, dict[str, t.Any]]: """ Convert a notebook from a notebook file. Parameters ---------- file_stream : file-like object Notebook file-like object to convert. resources : dict Additional resources that can be accessed read/write by preprocessors and filters. `**kw` Ignored """ return self.from_notebook_node( nbformat.read(file_stream, as_version=4), resources=resources, **kw ) def register_preprocessor(self, preprocessor, enabled=False): """ Register a preprocessor. Preprocessors are classes that act upon the notebook before it is passed into the Jinja templating engine. Preprocessors are also capable of passing additional information to the Jinja templating engine. Parameters ---------- preprocessor : `nbconvert.preprocessors.Preprocessor` A dotted module name, a type, or an instance enabled : bool Mark the preprocessor as enabled """ if preprocessor is None: msg = "preprocessor must not be None" raise TypeError(msg) isclass = isinstance(preprocessor, type) constructed = not isclass # Handle preprocessor's registration based on it's type if constructed and isinstance( preprocessor, str, ): # Preprocessor is a string, import the namespace and recursively call # this register_preprocessor method preprocessor_cls = import_item(preprocessor) return self.register_preprocessor(preprocessor_cls, enabled) if constructed and callable(preprocessor): # Preprocessor is a function, no need to construct it. # Register and return the preprocessor. if enabled: preprocessor.enabled = True self._preprocessors.append(preprocessor) return preprocessor if isclass and issubclass(preprocessor, HasTraits): # Preprocessor is configurable. Make sure to pass in new default for # the enabled flag if one was specified. self.register_preprocessor(preprocessor(parent=self), enabled) return None if isclass: # Preprocessor is not configurable, construct it self.register_preprocessor(preprocessor(), enabled) return None # Preprocessor is an instance of something without a __call__ # attribute. raise TypeError( "preprocessor must be callable or an importable constructor, got %r" % preprocessor ) def _init_preprocessors(self): """ Register all of the preprocessors needed for this exporter, disabled unless specified explicitly. """ self._preprocessors = [] # Load default preprocessors (not necessarily enabled by default). for preprocessor in self.default_preprocessors: self.register_preprocessor(preprocessor) # Load user-specified preprocessors. Enable by default. for preprocessor in self.preprocessors: self.register_preprocessor(preprocessor, enabled=True) def _init_resources(self, resources): # Make sure the resources dict is of ResourcesDict type. if resources is None: resources = ResourcesDict() if not isinstance(resources, ResourcesDict): new_resources = ResourcesDict() new_resources.update(resources) resources = new_resources # Make sure the metadata extension exists in resources if "metadata" in resources: if not isinstance(resources["metadata"], ResourcesDict): new_metadata = ResourcesDict() new_metadata.update(resources["metadata"]) resources["metadata"] = new_metadata else: resources["metadata"] = ResourcesDict() if not resources["metadata"]["name"]: resources["metadata"]["name"] = "Notebook" # Set the output extension resources["output_extension"] = self.file_extension return resources def _validate_preprocessor(self, nbc, preprocessor): try: nbformat.validate(nbc, relax_add_props=True) except nbformat.ValidationError: self.log.error("Notebook is invalid after preprocessor %s", preprocessor) raise def _preprocess(self, nb, resources): """ Preprocess the notebook before passing it into the Jinja engine. To preprocess the notebook is to successively apply all the enabled preprocessors. Output from each preprocessor is passed along to the next one. Parameters ---------- nb : notebook node notebook that is being exported. resources : a dict of additional resources that can be accessed read/write by preprocessors """ # Do a copy.deepcopy first, # we are never safe enough with what the preprocessors could do. nbc = copy.deepcopy(nb) resc = copy.deepcopy(resources) if hasattr(validator, "normalize"): _, nbc = validator.normalize(nbc) # Run each preprocessor on the notebook. Carry the output along # to each preprocessor for preprocessor in self._preprocessors: nbc, resc = preprocessor(nbc, resc) if not self.optimistic_validation: self._validate_preprocessor(nbc, preprocessor) if self.optimistic_validation: self._validate_preprocessor(nbc, preprocessor) return nbc, resc nbconvert-7.16.4/nbconvert/exporters/html.py000066400000000000000000000321471461373220400211730ustar00rootroot00000000000000"""HTML Exporter class""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import base64 import json import mimetypes import os from pathlib import Path from typing import Any, Dict, Optional, Tuple import jinja2 import markupsafe from bs4 import BeautifulSoup from jupyter_core.paths import jupyter_path from traitlets import Bool, Unicode, default, validate from traitlets.config import Config if tuple(int(x) for x in jinja2.__version__.split(".")[:3]) < (3, 0, 0): from jinja2 import contextfilter # type:ignore[attr-defined] else: from jinja2 import pass_context as contextfilter from jinja2.loaders import split_template_path from nbformat import NotebookNode from nbconvert.filters.highlight import Highlight2HTML from nbconvert.filters.markdown_mistune import IPythonRenderer, MarkdownWithMath from nbconvert.filters.widgetsdatatypefilter import WidgetsDataTypeFilter from nbconvert.utils.iso639_1 import iso639_1 from .templateexporter import TemplateExporter def find_lab_theme(theme_name): """ Find a JupyterLab theme location by name. Parameters ---------- theme_name : str The name of the labextension theme you want to find. Raises ------ ValueError If the theme was not found, or if it was not specific enough. Returns ------- theme_name: str Full theme name (with scope, if any) labextension_path : Path The path to the found labextension on the system. """ paths = jupyter_path("labextensions") matching_themes = [] theme_path = None for path in paths: for dirpath, dirnames, filenames in os.walk(path): # If it's a federated labextension that contains themes if "package.json" in filenames and "themes" in dirnames: # TODO Find the theme name in the JS code instead? # TODO Find if it's a light or dark theme? with open(Path(dirpath) / "package.json", encoding="utf-8") as fobj: labext_name = json.loads(fobj.read())["name"] if labext_name == theme_name or theme_name in labext_name.split("/"): matching_themes.append(labext_name) full_theme_name = labext_name theme_path = Path(dirpath) / "themes" / labext_name if len(matching_themes) == 0: msg = f'Could not find lab theme "{theme_name}"' raise ValueError(msg) if len(matching_themes) > 1: msg = ( f'Found multiple themes matching "{theme_name}": {matching_themes}. ' "Please be more specific about which theme you want to use." ) raise ValueError(msg) return full_theme_name, theme_path class HTMLExporter(TemplateExporter): """ Exports a basic HTML document. This exporter assists with the export of HTML. Inherit from it if you are writing your own HTML template and need custom preprocessors/filters. If you don't need custom preprocessors/ filters, just change the 'template_file' config option. """ export_from_notebook = "HTML" anchor_link_text = Unicode("¶", help="The text used as the text for anchor links.").tag( config=True ) exclude_anchor_links = Bool(False, help="If anchor links should be included or not.").tag( config=True ) require_js_url = Unicode( "https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js", help=""" URL to load require.js from. Defaults to loading from cdnjs. """, ).tag(config=True) mathjax_url = Unicode( "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS_CHTML-full,Safe", help=""" URL to load Mathjax from. Defaults to loading from cdnjs. """, ).tag(config=True) mermaid_js_url = Unicode( "https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.7.0/mermaid.esm.min.mjs", help=""" URL to load MermaidJS from. Defaults to loading from cdnjs. """, ) jquery_url = Unicode( "https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js", help=""" URL to load jQuery from. Defaults to loading from cdnjs. """, ).tag(config=True) jupyter_widgets_base_url = Unicode( "https://unpkg.com/", help="URL base for Jupyter widgets" ).tag(config=True) widget_renderer_url = Unicode("", help="Full URL for Jupyter widgets").tag(config=True) html_manager_semver_range = Unicode( "*", help="Semver range for Jupyter widgets HTML manager" ).tag(config=True) @default("file_extension") def _file_extension_default(self): return ".html" @default("template_name") def _template_name_default(self): return "lab" theme = Unicode( "light", help="Template specific theme(e.g. the name of a JupyterLab CSS theme distributed as prebuilt extension for the lab template)", ).tag(config=True) sanitize_html = Bool( False, help=( "Whether the HTML in Markdown cells and cell outputs should be sanitized." "This should be set to True by nbviewer or similar tools." ), ).tag(config=True) skip_svg_encoding = Bool( False, help=("Whether the svg to image data attribute encoding should occur"), ).tag(config=True) embed_images = Bool( False, help="Whether or not to embed images as base64 in markdown cells." ).tag(config=True) output_mimetype = "text/html" @property def default_config(self): c = Config( { "NbConvertBase": { "display_data_priority": [ "application/vnd.jupyter.widget-view+json", "application/javascript", "text/html", "text/markdown", "image/svg+xml", "text/vnd.mermaid", "text/latex", "image/png", "image/jpeg", "text/plain", ] }, "HighlightMagicsPreprocessor": {"enabled": True}, } ) if super().default_config: c2 = super().default_config.copy() c2.merge(c) c = c2 return c language_code = Unicode( "en", help="Language code of the content, should be one of the ISO639-1" ).tag(config=True) @validate("language_code") def _valid_language_code(self, proposal): if self.language_code not in iso639_1: self.log.warning( '"%s" is not an ISO 639-1 language code. ' 'It has been replaced by the default value "en".', self.language_code, ) return proposal["trait"].default_value return proposal["value"] @contextfilter def markdown2html(self, context, source): """Markdown to HTML filter respecting the anchor_link_text setting""" cell = context.get("cell", {}) attachments = cell.get("attachments", {}) path = context.get("resources", {}).get("metadata", {}).get("path", "") renderer = IPythonRenderer( escape=False, attachments=attachments, embed_images=self.embed_images, path=path, anchor_link_text=self.anchor_link_text, exclude_anchor_links=self.exclude_anchor_links, ) return MarkdownWithMath(renderer=renderer).render(source) def default_filters(self): """Get the default filters.""" yield from super().default_filters() yield ("markdown2html", self.markdown2html) def from_notebook_node( # type:ignore[explicit-override, override] self, nb: NotebookNode, resources: Optional[Dict[str, Any]] = None, **kw: Any ) -> Tuple[str, Dict[str, Any]]: """Convert from notebook node.""" langinfo = nb.metadata.get("language_info", {}) lexer = langinfo.get("pygments_lexer", langinfo.get("name", None)) highlight_code = self.filters.get( "highlight_code", Highlight2HTML(pygments_lexer=lexer, parent=self) ) resources = self._init_resources(resources) filter_data_type = WidgetsDataTypeFilter( notebook_metadata=self._nb_metadata, parent=self, resources=resources ) self.register_filter("highlight_code", highlight_code) self.register_filter("filter_data_type", filter_data_type) html, resources = super().from_notebook_node(nb, resources, **kw) soup = BeautifulSoup(html, features="html.parser") # Add image's alternative text missing_alt = 0 for elem in soup.select("img:not([alt])"): elem.attrs["alt"] = "No description has been provided for this image" missing_alt += 1 if missing_alt: self.log.warning("Alternative text is missing on %s image(s).", missing_alt) # Set input and output focusable for elem in soup.select(".jp-Notebook div.jp-Cell-inputWrapper"): elem.attrs["tabindex"] = "0" for elem in soup.select(".jp-Notebook div.jp-OutputArea-output"): elem.attrs["tabindex"] = "0" return str(soup), resources def _init_resources(self, resources): def resources_include_css(name): env = self.environment code = """""" % (env.loader.get_source(env, name)[0]) return markupsafe.Markup(code) def resources_include_lab_theme(name): # Try to find the theme with the given name, looking through the labextensions _, theme_path = find_lab_theme(name) with open(theme_path / "index.css") as file: data = file.read() # Embed assets (fonts, images...) for asset in os.listdir(theme_path): local_url = f"url({Path(asset).as_posix()})" if local_url in data: mime_type = mimetypes.guess_type(asset)[0] # Replace asset url by a base64 dataurl with open(theme_path / asset, "rb") as assetfile: base64_data = base64.b64encode(assetfile.read()) base64_str = base64_data.replace(b"\n", b"").decode("ascii") data = data.replace(local_url, f"url(data:{mime_type};base64,{base64_str})") code = """""" % data return markupsafe.Markup(code) def resources_include_js(name, module=False): """Get the resources include JS for a name. If module=True, import as ES module""" env = self.environment code = f"""""" return markupsafe.Markup(code) def resources_include_url(name): """Get the resources include url for a name.""" env = self.environment mime_type, encoding = mimetypes.guess_type(name) try: # we try to load via the jinja loader, but that tries to load # as (encoded) text data = env.loader.get_source(env, name)[0].encode("utf8") except UnicodeDecodeError: # if that fails (for instance a binary file, png or ttf) # we mimic jinja2 pieces = split_template_path(name) for searchpath in self.template_paths: filename = os.path.join(searchpath, *pieces) if os.path.exists(filename): with open(filename, "rb") as f: data = f.read() break else: msg = f"No file {name!r} found in {searchpath!r}" raise ValueError(msg) data = base64.b64encode(data) data = data.replace(b"\n", b"").decode("ascii") src = f"data:{mime_type};base64,{data}" return markupsafe.Markup(src) resources = super()._init_resources(resources) resources["theme"] = self.theme resources["include_css"] = resources_include_css resources["include_lab_theme"] = resources_include_lab_theme resources["include_js"] = resources_include_js resources["include_url"] = resources_include_url resources["require_js_url"] = self.require_js_url resources["mathjax_url"] = self.mathjax_url resources["mermaid_js_url"] = self.mermaid_js_url resources["jquery_url"] = self.jquery_url resources["jupyter_widgets_base_url"] = self.jupyter_widgets_base_url resources["widget_renderer_url"] = self.widget_renderer_url resources["html_manager_semver_range"] = self.html_manager_semver_range resources["should_sanitize_html"] = self.sanitize_html resources["language_code"] = self.language_code resources["should_not_encode_svg"] = self.skip_svg_encoding return resources nbconvert-7.16.4/nbconvert/exporters/latex.py000066400000000000000000000074071461373220400213450ustar00rootroot00000000000000"""LaTeX Exporter class""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import os from traitlets import default from traitlets.config import Config from nbconvert.filters.filter_links import resolve_references from nbconvert.filters.highlight import Highlight2Latex from nbconvert.filters.pandoc import ConvertExplicitlyRelativePaths from .templateexporter import TemplateExporter class LatexExporter(TemplateExporter): """ Exports to a Latex template. Inherit from this class if your template is LaTeX based and you need custom transformers/filters. If you don't need custom transformers/filters, just change the 'template_file' config option. Place your template in the special "/latex" subfolder of the "../templates" folder. """ export_from_notebook = "LaTeX" @default("file_extension") def _file_extension_default(self): return ".tex" @default("template_name") def _template_name_default(self): return "latex" output_mimetype = "text/latex" def default_filters(self): """Get the default filters.""" yield from super().default_filters() yield ("resolve_references", resolve_references) @property def default_config(self): c = Config( { "NbConvertBase": { "display_data_priority": [ "text/latex", "application/pdf", "image/png", "image/jpeg", "image/svg+xml", "text/markdown", "text/plain", ] }, "ExtractAttachmentsPreprocessor": {"enabled": True}, "ExtractOutputPreprocessor": {"enabled": True}, "SVG2PDFPreprocessor": {"enabled": True}, "LatexPreprocessor": {"enabled": True}, "SphinxPreprocessor": {"enabled": True}, "HighlightMagicsPreprocessor": {"enabled": True}, } ) if super().default_config: c2 = super().default_config.copy() c2.merge(c) c = c2 return c def from_notebook_node(self, nb, resources=None, **kw): """Convert from notebook node.""" langinfo = nb.metadata.get("language_info", {}) lexer = langinfo.get("pygments_lexer", langinfo.get("name", None)) highlight_code = self.filters.get( "highlight_code", Highlight2Latex(pygments_lexer=lexer, parent=self) ) self.register_filter("highlight_code", highlight_code) # Need to make sure explicit relative paths are visible to latex for pdf conversion # https://github.com/jupyter/nbconvert/issues/1998 nb_path = resources.get("metadata", {}).get("path") if resources else None texinputs = os.path.abspath(nb_path) if nb_path else os.getcwd() convert_explicitly_relative_paths = self.filters.get( "convert_explicitly_relative_paths", ConvertExplicitlyRelativePaths(texinputs=texinputs, parent=self), ) self.register_filter("convert_explicitly_relative_paths", convert_explicitly_relative_paths) return super().from_notebook_node(nb, resources, **kw) def _create_environment(self): environment = super()._create_environment() # Set special Jinja2 syntax that will not conflict with latex. environment.block_start_string = "((*" environment.block_end_string = "*))" environment.variable_start_string = "(((" environment.variable_end_string = ")))" environment.comment_start_string = "((=" environment.comment_end_string = "=))" return environment nbconvert-7.16.4/nbconvert/exporters/markdown.py000066400000000000000000000030411461373220400220400ustar00rootroot00000000000000"""Markdown Exporter class""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. from traitlets import default from traitlets.config import Config from .templateexporter import TemplateExporter class MarkdownExporter(TemplateExporter): """ Exports to a markdown document (.md) """ export_from_notebook = "Markdown" @default("file_extension") def _file_extension_default(self): return ".md" @default("template_name") def _template_name_default(self): return "markdown" output_mimetype = "text/markdown" @default("raw_mimetypes") def _raw_mimetypes_default(self): return ["text/markdown", "text/html", ""] @property def default_config(self): c = Config( { "ExtractAttachmentsPreprocessor": {"enabled": True}, "ExtractOutputPreprocessor": {"enabled": True}, "NbConvertBase": { "display_data_priority": [ "text/html", "text/markdown", "image/svg+xml", "text/latex", "image/png", "image/jpeg", "text/plain", ] }, "HighlightMagicsPreprocessor": {"enabled": True}, } ) if super().default_config: c2 = super().default_config.copy() c2.merge(c) c = c2 return c nbconvert-7.16.4/nbconvert/exporters/notebook.py000066400000000000000000000026171461373220400220460ustar00rootroot00000000000000"""NotebookExporter class""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. import nbformat from traitlets import Enum, default from .exporter import Exporter class NotebookExporter(Exporter): """Exports to an IPython notebook. This is useful when you want to use nbconvert's preprocessors to operate on a notebook (e.g. to execute it) and then write it back to a notebook file. """ nbformat_version = Enum( list(nbformat.versions), default_value=nbformat.current_nbformat, help="""The nbformat version to write. Use this to downgrade notebooks. """, ).tag(config=True) @default("file_extension") def _file_extension_default(self): return ".ipynb" output_mimetype = "application/json" export_from_notebook = "Notebook" def from_notebook_node(self, nb, resources=None, **kw): """Convert from notebook node.""" nb_copy, resources = super().from_notebook_node(nb, resources, **kw) if self.nbformat_version != nb_copy.nbformat: resources["output_suffix"] = ".v%i" % self.nbformat_version else: resources["output_suffix"] = ".nbconvert" output = nbformat.writes(nb_copy, version=self.nbformat_version) if not output.endswith("\n"): output = output + "\n" return output, resources nbconvert-7.16.4/nbconvert/exporters/pdf.py000066400000000000000000000173741461373220400210050ustar00rootroot00000000000000"""Export to PDF via latex""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. from __future__ import annotations import os import shutil import subprocess import sys from tempfile import TemporaryDirectory from traitlets import Bool, Instance, Integer, List, Unicode, default from nbconvert.utils import _contextlib_chdir from .latex import LatexExporter class LatexFailed(IOError): """Exception for failed latex run Captured latex output is in error.output. """ def __init__(self, output): """Initialize the error.""" self.output = output def __unicode__(self): """Unicode representation.""" return "PDF creating failed, captured latex output:\n%s" % self.output def __str__(self): """String representation.""" return self.__unicode__() def prepend_to_env_search_path(varname, value, envdict): """Add value to the environment variable varname in envdict e.g. prepend_to_env_search_path('BIBINPUTS', '/home/sally/foo', os.environ) """ if not value: return # Nothing to add envdict[varname] = value + os.pathsep + envdict.get(varname, "") class PDFExporter(LatexExporter): """Writer designed to write to PDF files. This inherits from `LatexExporter`. It creates a LaTeX file in a temporary directory using the template machinery, and then runs LaTeX to create a pdf. """ export_from_notebook = "PDF via LaTeX" latex_count = Integer(3, help="How many times latex will be called.").tag(config=True) latex_command = List( ["xelatex", "{filename}", "-quiet"], help="Shell command used to compile latex." ).tag(config=True) bib_command = List(["bibtex", "{filename}"], help="Shell command used to run bibtex.").tag( config=True ) verbose = Bool(False, help="Whether to display the output of latex commands.").tag(config=True) texinputs = Unicode(help="texinputs dir. A notebook's directory is added") writer = Instance("nbconvert.writers.FilesWriter", args=(), kw={"build_directory": "."}) output_mimetype = "application/pdf" _captured_output = List(Unicode()) @default("file_extension") def _file_extension_default(self): return ".pdf" @default("template_extension") def _template_extension_default(self): return ".tex.j2" def run_command(self, command_list, filename, count, log_function, raise_on_failure=None): """Run command_list count times. Parameters ---------- command_list : list A list of args to provide to Popen. Each element of this list will be interpolated with the filename to convert. filename : unicode The name of the file to convert. count : int How many times to run the command. raise_on_failure: Exception class (default None) If provided, will raise the given exception for if an instead of returning False on command failure. Returns ------- success : bool A boolean indicating if the command was successful (True) or failed (False). """ command = [c.format(filename=filename) for c in command_list] # This will throw a clearer error if the command is not found cmd = shutil.which(command_list[0]) if cmd is None: link = "https://nbconvert.readthedocs.io/en/latest/install.html#installing-tex" msg = ( f"{command_list[0]} not found on PATH, if you have not installed " f"{command_list[0]} you may need to do so. Find further instructions " f"at {link}." ) raise OSError(msg) times = "time" if count == 1 else "times" self.log.info("Running %s %i %s: %s", command_list[0], count, times, command) shell = sys.platform == "win32" if shell: command = subprocess.list2cmdline(command) # type:ignore[assignment] env = os.environ.copy() prepend_to_env_search_path("TEXINPUTS", self.texinputs, env) prepend_to_env_search_path("BIBINPUTS", self.texinputs, env) prepend_to_env_search_path("BSTINPUTS", self.texinputs, env) with open(os.devnull, "rb") as null: stdout = subprocess.PIPE if not self.verbose else None for _ in range(count): p = subprocess.Popen( command, stdout=stdout, stderr=subprocess.STDOUT, stdin=null, shell=shell, # noqa: S603 env=env, ) out, _ = p.communicate() if p.returncode: if self.verbose: # noqa: SIM108 # verbose means I didn't capture stdout with PIPE, # so it's already been displayed and `out` is None. out_str = "" else: out_str = out.decode("utf-8", "replace") log_function(command, out) self._captured_output.append(out_str) if raise_on_failure: msg = f'Failed to run "{command}" command:\n{out_str}' raise raise_on_failure(msg) return False # failure return True # success def run_latex(self, filename, raise_on_failure=LatexFailed): """Run xelatex self.latex_count times.""" def log_error(command, out): self.log.critical("%s failed: %s\n%s", command[0], command, out) return self.run_command( self.latex_command, filename, self.latex_count, log_error, raise_on_failure ) def run_bib(self, filename, raise_on_failure=False): """Run bibtex one time.""" filename = os.path.splitext(filename)[0] def log_error(command, out): self.log.warning( "%s had problems, most likely because there were no citations", command[0] ) self.log.debug("%s output: %s\n%s", command[0], command, out) return self.run_command(self.bib_command, filename, 1, log_error, raise_on_failure) def from_notebook_node(self, nb, resources=None, **kw): """Convert from notebook node.""" latex, resources = super().from_notebook_node(nb, resources=resources, **kw) # set texinputs directory, so that local files will be found if resources and resources.get("metadata", {}).get("path"): self.texinputs = os.path.abspath(resources["metadata"]["path"]) else: self.texinputs = os.getcwd() self._captured_outputs = [] with TemporaryDirectory() as td, _contextlib_chdir.chdir(td): notebook_name = "notebook" resources["output_extension"] = ".tex" tex_file = self.writer.write(latex, resources, notebook_name=notebook_name) self.log.info("Building PDF") self.run_latex(tex_file) if self.run_bib(tex_file): self.run_latex(tex_file) pdf_file = notebook_name + ".pdf" if not os.path.isfile(pdf_file): raise LatexFailed("\n".join(self._captured_output)) self.log.info("PDF successfully created") with open(pdf_file, "rb") as f: pdf_data = f.read() # convert output extension to pdf # the writer above required it to be tex resources["output_extension"] = ".pdf" # clear figure outputs and attachments, extracted by latex export, # so we don't claim to be a multi-file export. resources.pop("outputs", None) resources.pop("attachments", None) return pdf_data, resources nbconvert-7.16.4/nbconvert/exporters/python.py000066400000000000000000000012431461373220400215410ustar00rootroot00000000000000"""Python script Exporter class""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. from traitlets import default from .templateexporter import TemplateExporter class PythonExporter(TemplateExporter): """ Exports a Python code file. Note that the file produced will have a shebang of '#!/usr/bin/env python' regardless of the actual python version used in the notebook. """ @default("file_extension") def _file_extension_default(self): return ".py" @default("template_name") def _template_name_default(self): return "python" output_mimetype = "text/x-python" nbconvert-7.16.4/nbconvert/exporters/qt_exporter.py000066400000000000000000000041011461373220400225700ustar00rootroot00000000000000"""A qt exporter.""" import os import sys import tempfile from traitlets import default from .html import HTMLExporter class QtExporter(HTMLExporter): """A qt exporter.""" paginate = None format = "" @default("file_extension") def _file_extension_default(self): return ".html" def _check_launch_reqs(self): if sys.platform.startswith("win") and self.format == "png": msg = "Exporting to PNG using Qt is currently not supported on Windows." raise RuntimeError(msg) from .qt_screenshot import QT_INSTALLED if not QT_INSTALLED: msg = ( f"PyQtWebEngine is not installed to support Qt {self.format.upper()} conversion. " f"Please install `nbconvert[qt{self.format}]` to enable." ) raise RuntimeError(msg) from .qt_screenshot import QtScreenshot return QtScreenshot def _run_pyqtwebengine(self, html): ext = ".html" temp_file = tempfile.NamedTemporaryFile(suffix=ext, delete=False) filename = f"{temp_file.name[:-len(ext)]}.{self.format}" with temp_file: temp_file.write(html.encode("utf-8")) try: QtScreenshot = self._check_launch_reqs() s = QtScreenshot() s.capture(f"file://{temp_file.name}", filename, self.paginate) finally: # Ensure the file is deleted even if pyqtwebengine raises an exception os.unlink(temp_file.name) return s.data def from_notebook_node(self, nb, resources=None, **kw): """Convert from notebook node.""" self._check_launch_reqs() html, resources = super().from_notebook_node(nb, resources=resources, **kw) self.log.info("Building %s", self.format.upper()) data = self._run_pyqtwebengine(html) self.log.info("%s successfully created", self.format.upper()) # convert output extension # the writer above required it to be html resources["output_extension"] = f".{self.format}" return data, resources nbconvert-7.16.4/nbconvert/exporters/qt_screenshot.py000066400000000000000000000063601461373220400231060ustar00rootroot00000000000000"""A qt screenshot exporter.""" import os try: from PyQt5 import QtCore # type:ignore[import-not-found] from PyQt5.QtGui import QPageLayout, QPageSize # type:ignore[import-not-found] from PyQt5.QtWebEngineWidgets import ( # type:ignore[import-not-found] QWebEngineSettings, QWebEngineView, ) from PyQt5.QtWidgets import QApplication # type:ignore[import-not-found] QT_INSTALLED = True except ModuleNotFoundError: QT_INSTALLED = False if QT_INSTALLED: APP = None if not QApplication.instance(): APP = QApplication([]) class QtScreenshot(QWebEngineView): # type:ignore[misc] """A qt screenshot exporter.""" def __init__(self): """Initialize the exporter.""" super().__init__() self.app = APP def capture(self, url, output_file, paginate): """Capture the screenshot.""" self.output_file = output_file self.paginate = paginate self.load(QtCore.QUrl(url)) self.loadFinished.connect(self.on_loaded) # Create hidden view without scrollbars self.setAttribute(QtCore.Qt.WA_DontShowOnScreen) self.page().settings().setAttribute(QWebEngineSettings.ShowScrollBars, False) self.data = b"" if output_file.endswith(".pdf"): self.export = self.export_pdf def cleanup(*args): """Cleanup the app.""" self.app.quit() # type:ignore[union-attr] self.get_data() self.page().pdfPrintingFinished.connect(cleanup) elif output_file.endswith(".png"): self.export = self.export_png else: msg = f"Export file extension not supported: {output_file}" raise RuntimeError(msg) self.show() self.app.exec() # type:ignore[union-attr] def on_loaded(self): """Handle app load.""" self.size = self.page().contentsSize().toSize() self.resize(self.size) # Wait for resize QtCore.QTimer.singleShot(1000, self.export) def export_pdf(self): """Export to pdf.""" if self.paginate: page_size = QPageSize(QPageSize.A4) page_layout = QPageLayout(page_size, QPageLayout.Portrait, QtCore.QMarginsF()) else: factor = 0.75 page_size = QPageSize( QtCore.QSizeF(self.size.width() * factor, self.size.height() * factor), QPageSize.Point, ) page_layout = QPageLayout(page_size, QPageLayout.Portrait, QtCore.QMarginsF()) self.page().printToPdf(self.output_file, pageLayout=page_layout) def export_png(self): """Export to png.""" self.grab().save(self.output_file, "PNG") self.app.quit() # type:ignore[union-attr] self.get_data() def get_data(self): """Get output data.""" if os.path.exists(self.output_file): with open(self.output_file, "rb") as f: self.data = f.read() os.unlink(self.output_file) nbconvert-7.16.4/nbconvert/exporters/qtpdf.py000066400000000000000000000014501461373220400213360ustar00rootroot00000000000000"""Export to PDF via a headless browser""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. from traitlets import Bool from .qt_exporter import QtExporter class QtPDFExporter(QtExporter): """Writer designed to write to PDF files. This inherits from :class:`HTMLExporter`. It creates the HTML using the template machinery, and then uses pyqtwebengine to create a pdf. """ export_from_notebook = "PDF via HTML" format = "pdf" paginate = Bool( # type:ignore[assignment] True, help=""" Split generated notebook into multiple pages. If False, a PDF with one long page will be generated. Set to True to match behavior of LaTeX based PDF generator """, ).tag(config=True) nbconvert-7.16.4/nbconvert/exporters/qtpng.py000066400000000000000000000007371461373220400213600ustar00rootroot00000000000000"""Export to PNG via a headless browser""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. from .qt_exporter import QtExporter class QtPNGExporter(QtExporter): """Writer designed to write to PNG files. This inherits from :class:`HTMLExporter`. It creates the HTML using the template machinery, and then uses pyqtwebengine to create a png. """ export_from_notebook = "PNG via HTML" format = "png" nbconvert-7.16.4/nbconvert/exporters/rst.py000066400000000000000000000020371461373220400210320ustar00rootroot00000000000000"""reStructuredText Exporter class""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. from traitlets import default from traitlets.config import Config from .templateexporter import TemplateExporter class RSTExporter(TemplateExporter): """ Exports reStructuredText documents. """ @default("file_extension") def _file_extension_default(self): return ".rst" @default("template_name") def _template_name_default(self): return "rst" output_mimetype = "text/restructuredtext" export_from_notebook = "reST" @property def default_config(self): c = Config( { "CoalesceStreamsPreprocessor": {"enabled": True}, "ExtractOutputPreprocessor": {"enabled": True}, "HighlightMagicsPreprocessor": {"enabled": True}, } ) if super().default_config: c2 = super().default_config.copy() c2.merge(c) c = c2 return c nbconvert-7.16.4/nbconvert/exporters/script.py000066400000000000000000000061511461373220400215270ustar00rootroot00000000000000"""Generic script exporter class for any kernel language""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import sys if sys.version_info < (3, 10): from importlib_metadata import entry_points # type:ignore[import-not-found] else: from importlib.metadata import entry_points from traitlets import Dict, default from .base import get_exporter from .templateexporter import TemplateExporter class ScriptExporter(TemplateExporter): """A script exporter.""" # Caches of already looked-up and instantiated exporters for delegation: _exporters = Dict() _lang_exporters = Dict() export_from_notebook = "Script" @default("template_file") def _template_file_default(self): return "script.j2" @default("template_name") def _template_name_default(self): return "script" def _get_language_exporter(self, lang_name): """Find an exporter for the language name from notebook metadata. Uses the nbconvert.exporters.script group of entry points. Returns None if no exporter is found. """ if lang_name not in self._lang_exporters: try: exporters = entry_points(group="nbconvert.exporters.script") exporter = [e for e in exporters if e.name == lang_name][0].load() # noqa: RUF015 except (KeyError, IndexError): self._lang_exporters[lang_name] = None else: # TODO: passing config is wrong, but changing this revealed more complicated issues self._lang_exporters[lang_name] = exporter(config=self.config, parent=self) return self._lang_exporters[lang_name] def from_notebook_node(self, nb, resources=None, **kw): """Convert from notebook node.""" langinfo = nb.metadata.get("language_info", {}) # delegate to custom exporter, if specified exporter_name = langinfo.get("nbconvert_exporter") if exporter_name and exporter_name != "script": self.log.debug("Loading script exporter: %s", exporter_name) if exporter_name not in self._exporters: exporter = get_exporter(exporter_name) # TODO: passing config is wrong, but changing this revealed more complicated issues self._exporters[exporter_name] = exporter(config=self.config, parent=self) exporter = self._exporters[exporter_name] return exporter.from_notebook_node(nb, resources, **kw) # Look up a script exporter for this notebook's language lang_name = langinfo.get("name") if lang_name: self.log.debug("Using script exporter for language: %s", lang_name) exporter = self._get_language_exporter(lang_name) if exporter is not None: return exporter.from_notebook_node(nb, resources, **kw) # Fall back to plain script export self.file_extension = langinfo.get("file_extension", ".txt") self.output_mimetype = langinfo.get("mimetype", "text/plain") return super().from_notebook_node(nb, resources, **kw) nbconvert-7.16.4/nbconvert/exporters/slides.py000066400000000000000000000156731461373220400215170ustar00rootroot00000000000000"""HTML slide show Exporter class""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. from copy import deepcopy from warnings import warn from traitlets import Bool, Unicode, default from nbconvert.preprocessors.base import Preprocessor from .html import HTMLExporter class _RevealMetadataPreprocessor(Preprocessor): # A custom preprocessor adding convenience metadata to cells def preprocess(self, nb, resources=None): nb = deepcopy(nb) for cell in nb.cells: # Make sure every cell has a slide_type try: slide_type = cell.metadata.get("slideshow", {}).get("slide_type", "-") except AttributeError: slide_type = "-" cell.metadata.slide_type = slide_type # Find the first visible cell for index, cell in enumerate(nb.cells): if cell.metadata.slide_type not in {"notes", "skip"}: cell.metadata.slide_type = "slide" cell.metadata.slide_start = True cell.metadata.subslide_start = True first_slide_ix = index break else: msg = "All cells are hidden, cannot create slideshow" raise ValueError(msg) in_fragment = False for index, cell in enumerate(nb.cells[first_slide_ix + 1 :], start=(first_slide_ix + 1)): previous_cell = nb.cells[index - 1] # Slides are
elements in the HTML, subslides (the vertically # stacked slides) are also
elements inside the slides, # and fragments are
s within subslides. Subslide and fragment # elements can contain content: #
#
# (content) #
(content)
#
#
# Get the slide type. If type is subslide or slide, # end the last slide/subslide/fragment as applicable. if cell.metadata.slide_type == "slide": previous_cell.metadata.slide_end = True cell.metadata.slide_start = True if cell.metadata.slide_type in {"subslide", "slide"}: previous_cell.metadata.fragment_end = in_fragment previous_cell.metadata.subslide_end = True cell.metadata.subslide_start = True in_fragment = False elif cell.metadata.slide_type == "fragment": cell.metadata.fragment_start = True if in_fragment: previous_cell.metadata.fragment_end = True else: in_fragment = True # The last cell will always be the end of a slide nb.cells[-1].metadata.fragment_end = in_fragment nb.cells[-1].metadata.subslide_end = True nb.cells[-1].metadata.slide_end = True return nb, resources class SlidesExporter(HTMLExporter): """Exports HTML slides with reveal.js""" # Overrides from HTMLExporter ################################# export_from_notebook = "Reveal.js slides" @default("template_name") def _template_name_default(self): return "reveal" @default("file_extension") def _file_extension_default(self): return ".slides.html" @default("template_extension") def _template_extension_default(self): return ".html.j2" # Extra resources ################################# reveal_url_prefix = Unicode( help="""The URL prefix for reveal.js (version 3.x). This defaults to the reveal CDN, but can be any url pointing to a copy of reveal.js. For speaker notes to work, this must be a relative path to a local copy of reveal.js: e.g., "reveal.js". If a relative path is given, it must be a subdirectory of the current directory (from which the server is run). See the usage documentation (https://nbconvert.readthedocs.io/en/latest/usage.html#reveal-js-html-slideshow) for more details. """ ).tag(config=True) @default("reveal_url_prefix") def _reveal_url_prefix_default(self): if "RevealHelpPreprocessor.url_prefix" in self.config: warn( "Please update RevealHelpPreprocessor.url_prefix to " "SlidesExporter.reveal_url_prefix in config files.", stacklevel=2, ) return self.config.RevealHelpPreprocessor.url_prefix return "https://unpkg.com/reveal.js@4.0.2" reveal_theme = Unicode( "simple", help=""" Name of the reveal.js theme to use. We look for a file with this name under ``reveal_url_prefix``/css/theme/``reveal_theme``.css. https://github.com/hakimel/reveal.js/tree/master/css/theme has list of themes that ship by default with reveal.js. """, ).tag(config=True) reveal_transition = Unicode( "slide", help=""" Name of the reveal.js transition to use. The list of transitions that ships by default with reveal.js are: none, fade, slide, convex, concave and zoom. """, ).tag(config=True) reveal_scroll = Bool( False, help=""" If True, enable scrolling within each slide """, ).tag(config=True) reveal_number = Unicode( "", help=""" slide number format (e.g. 'c/t'). Choose from: 'c': current, 't': total, 'h': horizontal, 'v': vertical """, ).tag(config=True) reveal_width = Unicode( "", help=""" width used to determine the aspect ratio of your presentation. Use the horizontal pixels available on your intended presentation equipment. """, ).tag(config=True) reveal_height = Unicode( "", help=""" height used to determine the aspect ratio of your presentation. Use the horizontal pixels available on your intended presentation equipment. """, ).tag(config=True) font_awesome_url = Unicode( "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css", help=""" URL to load font awesome from. Defaults to loading from cdnjs. """, ).tag(config=True) def _init_resources(self, resources): resources = super()._init_resources(resources) if "reveal" not in resources: resources["reveal"] = {} resources["reveal"]["url_prefix"] = self.reveal_url_prefix resources["reveal"]["theme"] = self.reveal_theme resources["reveal"]["transition"] = self.reveal_transition resources["reveal"]["scroll"] = self.reveal_scroll resources["reveal"]["number"] = self.reveal_number resources["reveal"]["height"] = self.reveal_height resources["reveal"]["width"] = self.reveal_width return resources nbconvert-7.16.4/nbconvert/exporters/templateexporter.py000066400000000000000000000651561461373220400236410ustar00rootroot00000000000000"""This module defines TemplateExporter, a highly configurable converter that uses Jinja2 to export notebook files into different formats. """ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. from __future__ import annotations import html import json import os import typing as t import uuid import warnings from pathlib import Path from jinja2 import ( BaseLoader, ChoiceLoader, DictLoader, Environment, FileSystemLoader, TemplateNotFound, ) from jupyter_core.paths import jupyter_path from nbformat import NotebookNode from traitlets import Bool, Dict, HasTraits, List, Unicode, default, observe, validate from traitlets.config import Config from traitlets.utils.importstring import import_item from nbconvert import filters from .exporter import Exporter # Jinja2 extensions to load. JINJA_EXTENSIONS = ["jinja2.ext.loopcontrols"] ROOT = os.path.dirname(__file__) DEV_MODE = os.path.exists(os.path.join(ROOT, "../../.git")) default_filters = { "indent": filters.indent, "markdown2html": filters.markdown2html, "markdown2asciidoc": filters.markdown2asciidoc, "ansi2html": filters.ansi2html, "filter_data_type": filters.DataTypeFilter, "get_lines": filters.get_lines, "highlight2html": filters.Highlight2HTML, "highlight2latex": filters.Highlight2Latex, "ipython2python": filters.ipython2python, "posix_path": filters.posix_path, "markdown2latex": filters.markdown2latex, "markdown2rst": filters.markdown2rst, "comment_lines": filters.comment_lines, "strip_ansi": filters.strip_ansi, "strip_dollars": filters.strip_dollars, "strip_files_prefix": filters.strip_files_prefix, "html2text": filters.html2text, "add_anchor": filters.add_anchor, "ansi2latex": filters.ansi2latex, "wrap_text": filters.wrap_text, "escape_latex": filters.escape_latex, "citation2latex": filters.citation2latex, "path2url": filters.path2url, "add_prompts": filters.add_prompts, "ascii_only": filters.ascii_only, "prevent_list_blocks": filters.prevent_list_blocks, "get_metadata": filters.get_metadata, "convert_pandoc": filters.convert_pandoc, "json_dumps": json.dumps, # For removing any HTML "escape_html": lambda s: html.escape(str(s)), "escape_html_keep_quotes": lambda s: html.escape(str(s), quote=False), "escape_html_script": lambda s: s.replace("/", "\\/"), # For sanitizing HTML for any XSS "clean_html": filters.clean_html, "strip_trailing_newline": filters.strip_trailing_newline, "text_base64": filters.text_base64, } # copy of https://github.com/jupyter/jupyter_server/blob/b62458a7f5ad6b5246d2f142258dedaa409de5d9/jupyter_server/config_manager.py#L19 def recursive_update(target, new): """Recursively update one dictionary using another. None values will delete their keys. """ for k, v in new.items(): if isinstance(v, dict): if k not in target: target[k] = {} recursive_update(target[k], v) if not target[k]: # Prune empty subdicts del target[k] elif v is None: target.pop(k, None) else: target[k] = v return target # return for convenience # define function at the top level to avoid pickle errors def deprecated(msg): """Emit a deprecation warning.""" warnings.warn(msg, DeprecationWarning, stacklevel=2) class ExtensionTolerantLoader(BaseLoader): """A template loader which optionally adds a given extension when searching. Constructor takes two arguments: *loader* is another Jinja loader instance to wrap. *extension* is the extension, which will be added to the template name if finding the template without it fails. This should include the dot, e.g. '.tpl'. """ def __init__(self, loader, extension): """Initialize the loader.""" self.loader = loader self.extension = extension def get_source(self, environment, template): """Get the source for a template.""" try: return self.loader.get_source(environment, template) except TemplateNotFound: if template.endswith(self.extension): raise TemplateNotFound(template) from None return self.loader.get_source(environment, template + self.extension) def list_templates(self): """List available templates.""" return self.loader.list_templates() class TemplateExporter(Exporter): """ Exports notebooks into other file formats. Uses Jinja 2 templating engine to output new formats. Inherit from this class if you are creating a new template type along with new filters/preprocessors. If the filters/ preprocessors provided by default suffice, there is no need to inherit from this class. Instead, override the template_file and file_extension traits via a config file. Filters available by default for templates: {filters} """ # finish the docstring __doc__ = __doc__.format(filters="- " + "\n - ".join(sorted(default_filters.keys()))) _template_cached = None def _invalidate_template_cache(self, change=None): self._template_cached = None @property def template(self): if self._template_cached is None: self._template_cached = self._load_template() return self._template_cached _environment_cached = None def _invalidate_environment_cache(self, change=None): self._environment_cached = None self._invalidate_template_cache() @property def environment(self): if self._environment_cached is None: self._environment_cached = self._create_environment() return self._environment_cached @property def default_config(self): c = Config( { "RegexRemovePreprocessor": {"enabled": True}, "TagRemovePreprocessor": {"enabled": True}, } ) if super().default_config: c2 = super().default_config.copy() c2.merge(c) c = c2 return c template_name = Unicode(help="Name of the template to use").tag( config=True, affects_template=True ) template_file = Unicode(None, allow_none=True, help="Name of the template file to use").tag( config=True, affects_template=True ) raw_template = Unicode("", help="raw template string").tag(affects_environment=True) enable_async = Bool(False, help="Enable Jinja async template execution").tag( affects_environment=True ) _last_template_file = "" _raw_template_key = "" @validate("template_name") def _template_name_validate(self, change): template_name = change["value"] if template_name and template_name.endswith(".tpl"): warnings.warn( f"5.x style template name passed '{self.template_name}'. Use --template-name for the template directory with a index..j2 file and/or --template-file to denote a different template.", DeprecationWarning, stacklevel=2, ) directory, self.template_file = os.path.split(self.template_name) if directory: directory, template_name = os.path.split(directory) if directory and os.path.isabs(directory): self.extra_template_basedirs = [directory] return template_name @observe("template_file") def _template_file_changed(self, change): new = change["new"] if new == "default": self.template_file = self.default_template # type:ignore[attr-defined] return # check if template_file is a file path # rather than a name already on template_path full_path = os.path.abspath(new) if os.path.isfile(full_path): directory, self.template_file = os.path.split(full_path) self.extra_template_paths = [directory, *self.extra_template_paths] # While not strictly an invalid template file name, the extension hints that there isn't a template directory involved if self.template_file and self.template_file.endswith(".tpl"): warnings.warn( f"5.x style template file passed '{new}'. Use --template-name for the template directory with a index..j2 file and/or --template-file to denote a different template.", DeprecationWarning, stacklevel=2, ) @default("template_file") def _template_file_default(self): if self.template_extension: return "index" + self.template_extension return None @observe("raw_template") def _raw_template_changed(self, change): if not change["new"]: self.template_file = self._last_template_file self._invalidate_template_cache() template_paths = List(["."]).tag(config=True, affects_environment=True) extra_template_basedirs = List(Unicode()).tag(config=True, affects_environment=True) extra_template_paths = List(Unicode()).tag(config=True, affects_environment=True) @default("extra_template_basedirs") def _default_extra_template_basedirs(self): return [os.getcwd()] # Extension that the template files use. template_extension = Unicode().tag(config=True, affects_environment=True) template_data_paths = List( jupyter_path("nbconvert", "templates"), help="Path where templates can be installed too." ).tag(affects_environment=True) @default("template_extension") def _template_extension_default(self): if self.file_extension: return self.file_extension + ".j2" return self.file_extension exclude_input = Bool( False, help="This allows you to exclude code cell inputs from all templates if set to True." ).tag(config=True) exclude_input_prompt = Bool( False, help="This allows you to exclude input prompts from all templates if set to True." ).tag(config=True) exclude_output = Bool( False, help="This allows you to exclude code cell outputs from all templates if set to True.", ).tag(config=True) exclude_output_prompt = Bool( False, help="This allows you to exclude output prompts from all templates if set to True." ).tag(config=True) exclude_output_stdin = Bool( True, help="This allows you to exclude output of stdin stream from lab template if set to True.", ).tag(config=True) exclude_code_cell = Bool( False, help="This allows you to exclude code cells from all templates if set to True." ).tag(config=True) exclude_markdown = Bool( False, help="This allows you to exclude markdown cells from all templates if set to True." ).tag(config=True) exclude_raw = Bool( False, help="This allows you to exclude raw cells from all templates if set to True." ).tag(config=True) exclude_unknown = Bool( False, help="This allows you to exclude unknown cells from all templates if set to True." ).tag(config=True) extra_loaders: List[t.Any] = List( help="Jinja loaders to find templates. Will be tried in order " "before the default FileSystem ones.", ).tag(affects_environment=True) filters = Dict( help="""Dictionary of filters, by name and namespace, to add to the Jinja environment.""" ).tag(config=True, affects_environment=True) raw_mimetypes = List( Unicode(), help="""formats of raw cells to be included in this Exporter's output.""" ).tag(config=True) @default("raw_mimetypes") def _raw_mimetypes_default(self): return [self.output_mimetype, ""] # TODO: passing config is wrong, but changing this revealed more complicated issues def __init__(self, config=None, **kw): """ Public constructor Parameters ---------- config : config User configuration instance. extra_loaders : list[of Jinja Loaders] ordered list of Jinja loader to find templates. Will be tried in order before the default FileSystem ones. template_file : str (optional, kw arg) Template to use when exporting. """ super().__init__(config=config, **kw) self.observe( self._invalidate_environment_cache, list(self.traits(affects_environment=True)) ) self.observe(self._invalidate_template_cache, list(self.traits(affects_template=True))) def _load_template(self): """Load the Jinja template object from the template file This is triggered by various trait changes that would change the template. """ # this gives precedence to a raw_template if present with self.hold_trait_notifications(): if self.template_file and (self.template_file != self._raw_template_key): self._last_template_file = self.template_file if self.raw_template: self.template_file = self._raw_template_key if not self.template_file: msg = "No template_file specified!" raise ValueError(msg) # First try to load the # template by name with extension added, then try loading the template # as if the name is explicitly specified. template_file = self.template_file self.log.debug("Attempting to load template %s", template_file) self.log.debug(" template_paths: %s", os.pathsep.join(self.template_paths)) return self.environment.get_template(template_file) def from_filename( # type:ignore[override] self, filename: str, resources: dict[str, t.Any] | None = None, **kw: t.Any ) -> tuple[str, dict[str, t.Any]]: """Convert a notebook from a filename.""" return super().from_filename(filename, resources, **kw) # type:ignore[return-value] def from_file( # type:ignore[override] self, file_stream: t.Any, resources: dict[str, t.Any] | None = None, **kw: t.Any ) -> tuple[str, dict[str, t.Any]]: """Convert a notebook from a file.""" return super().from_file(file_stream, resources, **kw) # type:ignore[return-value] def from_notebook_node( # type:ignore[explicit-override, override] self, nb: NotebookNode, resources: dict[str, t.Any] | None = None, **kw: t.Any ) -> tuple[str, dict[str, t.Any]]: """ Convert a notebook from a notebook node instance. Parameters ---------- nb : :class:`~nbformat.NotebookNode` Notebook node resources : dict Additional resources that can be accessed read/write by preprocessors and filters. """ nb_copy, resources = super().from_notebook_node(nb, resources, **kw) resources.setdefault("raw_mimetypes", self.raw_mimetypes) resources["global_content_filter"] = { "include_code": not self.exclude_code_cell, "include_markdown": not self.exclude_markdown, "include_raw": not self.exclude_raw, "include_unknown": not self.exclude_unknown, "include_input": not self.exclude_input, "include_output": not self.exclude_output, "include_output_stdin": not self.exclude_output_stdin, "include_input_prompt": not self.exclude_input_prompt, "include_output_prompt": not self.exclude_output_prompt, "no_prompt": self.exclude_input_prompt and self.exclude_output_prompt, } # Top level variables are passed to the template_exporter here. output = self.template.render(nb=nb_copy, resources=resources) output = output.lstrip("\r\n") return output, resources def _register_filter(self, environ, name, jinja_filter): """ Register a filter. A filter is a function that accepts and acts on one string. The filters are accessible within the Jinja templating engine. Parameters ---------- name : str name to give the filter in the Jinja engine filter : filter """ if jinja_filter is None: msg = "filter" raise TypeError(msg) isclass = isinstance(jinja_filter, type) constructed = not isclass # Handle filter's registration based on it's type if constructed and isinstance(jinja_filter, (str,)): # filter is a string, import the namespace and recursively call # this register_filter method filter_cls = import_item(jinja_filter) return self._register_filter(environ, name, filter_cls) if constructed and callable(jinja_filter): # filter is a function, no need to construct it. environ.filters[name] = jinja_filter return jinja_filter if isclass and issubclass(jinja_filter, HasTraits): # filter is configurable. Make sure to pass in new default for # the enabled flag if one was specified. filter_instance = jinja_filter(parent=self) self._register_filter(environ, name, filter_instance) return None if isclass: # filter is not configurable, construct it filter_instance = jinja_filter() self._register_filter(environ, name, filter_instance) return None # filter is an instance of something without a __call__ # attribute. msg = "filter" raise TypeError(msg) def register_filter(self, name, jinja_filter): """ Register a filter. A filter is a function that accepts and acts on one string. The filters are accessible within the Jinja templating engine. Parameters ---------- name : str name to give the filter in the Jinja engine filter : filter """ return self._register_filter(self.environment, name, jinja_filter) def default_filters(self): """Override in subclasses to provide extra filters. This should return an iterable of 2-tuples: (name, class-or-function). You should call the method on the parent class and include the filters it provides. If a name is repeated, the last filter provided wins. Filters from user-supplied config win over filters provided by classes. """ return default_filters.items() def _create_environment(self): """ Create the Jinja templating environment. """ paths = self.template_paths self.log.debug("Template paths:\n\t%s", "\n\t".join(paths)) loaders = [ *self.extra_loaders, ExtensionTolerantLoader(FileSystemLoader(paths), self.template_extension), DictLoader({self._raw_template_key: self.raw_template}), ] environment = Environment( # noqa: S701 loader=ChoiceLoader(loaders), extensions=JINJA_EXTENSIONS, enable_async=self.enable_async, ) environment.globals["uuid4"] = uuid.uuid4 # Add default filters to the Jinja2 environment for key, value in self.default_filters(): self._register_filter(environment, key, value) # Load user filters. Overwrite existing filters if need be. if self.filters: for key, user_filter in self.filters.items(): self._register_filter(environment, key, user_filter) return environment def _init_preprocessors(self): super()._init_preprocessors() conf = self._get_conf() preprocessors = conf.get("preprocessors", {}) # preprocessors is a dict for three reasons # * We rely on recursive_update, which can only merge dicts, lists will be overwritten # * We can use the key with numerical prefixing to guarantee ordering (/etc/*.d/XY-file style) # * We can disable preprocessors by overwriting the value with None for _, preprocessor in sorted(preprocessors.items(), key=lambda x: x[0]): if preprocessor is not None: kwargs = preprocessor.copy() preprocessor_cls = kwargs.pop("type") preprocessor_cls = import_item(preprocessor_cls) if preprocessor_cls.__name__ in self.config: kwargs.update(self.config[preprocessor_cls.__name__]) preprocessor = preprocessor_cls(**kwargs) # noqa: PLW2901 self.register_preprocessor(preprocessor) def _get_conf(self): conf: dict[str, t.Any] = {} # the configuration once all conf files are merged for path in map(Path, self.template_paths): conf_path = path / "conf.json" if conf_path.exists(): with conf_path.open() as f: conf = recursive_update(conf, json.load(f)) return conf @default("template_paths") def _template_paths(self, prune=True, root_dirs=None): paths = [] root_dirs = self.get_prefix_root_dirs() template_names = self.get_template_names() for template_name in template_names: for base_dir in self.extra_template_basedirs: path = os.path.join(base_dir, template_name) if not prune or os.path.exists(path): paths.append(path) for root_dir in root_dirs: base_dir = os.path.join(root_dir, "nbconvert", "templates") path = os.path.join(base_dir, template_name) if not prune or os.path.exists(path): paths.append(path) for root_dir in root_dirs: # we include root_dir for when we want to be very explicit, e.g. # {% extends 'nbconvert/templates/classic/base.html' %} paths.append(root_dir) # we include base_dir for when we want to be explicit, but less than root_dir, e.g. # {% extends 'classic/base.html' %} base_dir = os.path.join(root_dir, "nbconvert", "templates") paths.append(base_dir) compatibility_dir = os.path.join(root_dir, "nbconvert", "templates", "compatibility") paths.append(compatibility_dir) additional_paths = [] for path in self.template_data_paths: if not prune or os.path.exists(path): additional_paths.append(path) return paths + self.extra_template_paths + additional_paths @classmethod def get_compatibility_base_template_conf(cls, name): """Get the base template config.""" # Hard-coded base template confs to use for backwards compatibility for 5.x-only templates if name == "display_priority": return {"base_template": "base"} if name == "full": return {"base_template": "classic", "mimetypes": {"text/html": True}} return None def get_template_names(self): """Finds a list of template names where each successive template name is the base template""" template_names = [] root_dirs = self.get_prefix_root_dirs() base_template: str | None = self.template_name merged_conf: dict[str, t.Any] = {} # the configuration once all conf files are merged while base_template is not None: template_names.append(base_template) conf: dict[str, t.Any] = {} found_at_least_one = False for base_dir in self.extra_template_basedirs: template_dir = os.path.join(base_dir, base_template) if os.path.exists(template_dir): found_at_least_one = True conf_file = os.path.join(template_dir, "conf.json") if os.path.exists(conf_file): with open(conf_file) as f: conf = recursive_update(json.load(f), conf) for root_dir in root_dirs: template_dir = os.path.join(root_dir, "nbconvert", "templates", base_template) if os.path.exists(template_dir): found_at_least_one = True conf_file = os.path.join(template_dir, "conf.json") if os.path.exists(conf_file): with open(conf_file) as f: conf = recursive_update(json.load(f), conf) if not found_at_least_one: # Check for backwards compatibility template names for root_dir in root_dirs: compatibility_file = base_template + ".tpl" compatibility_path = os.path.join( root_dir, "nbconvert", "templates", "compatibility", compatibility_file ) if os.path.exists(compatibility_path): found_at_least_one = True warnings.warn( f"5.x template name passed '{self.template_name}'. Use 'lab' or 'classic' for new template usage.", DeprecationWarning, stacklevel=2, ) self.template_file = compatibility_file conf = self.get_compatibility_base_template_conf(base_template) self.template_name = t.cast(str, conf.get("base_template")) break if not found_at_least_one: paths = "\n\t".join(root_dirs) msg = f"No template sub-directory with name {base_template!r} found in the following paths:\n\t{paths}" raise ValueError(msg) merged_conf = recursive_update(dict(conf), merged_conf) base_template = t.cast(t.Any, conf.get("base_template")) conf = merged_conf mimetypes = [mimetype for mimetype, enabled in conf.get("mimetypes", {}).items() if enabled] if self.output_mimetype and self.output_mimetype not in mimetypes and mimetypes: supported_mimetypes = "\n\t".join(mimetypes) msg = f"Unsupported mimetype {self.output_mimetype!r} for template {self.template_name!r}, mimetypes supported are: \n\t{supported_mimetypes}" raise ValueError(msg) return template_names def get_prefix_root_dirs(self): """Get the prefix root dirs.""" # We look at the usual jupyter locations, and for development purposes also # relative to the package directory (first entry, meaning with highest precedence) root_dirs = [] if DEV_MODE: root_dirs.append(os.path.abspath(os.path.join(ROOT, "..", "..", "share", "jupyter"))) root_dirs.extend(jupyter_path()) return root_dirs def _init_resources(self, resources): resources = super()._init_resources(resources) resources["deprecated"] = deprecated return resources nbconvert-7.16.4/nbconvert/exporters/webpdf.py000066400000000000000000000150261461373220400214730ustar00rootroot00000000000000"""Export to PDF via a headless browser""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. import asyncio import concurrent.futures import os import subprocess import sys import tempfile from importlib import util as importlib_util from traitlets import Bool, default from .html import HTMLExporter PLAYWRIGHT_INSTALLED = importlib_util.find_spec("playwright") is not None IS_WINDOWS = os.name == "nt" class WebPDFExporter(HTMLExporter): """Writer designed to write to PDF files. This inherits from :class:`HTMLExporter`. It creates the HTML using the template machinery, and then run playwright to create a pdf. """ export_from_notebook = "PDF via HTML" allow_chromium_download = Bool( False, help="Whether to allow downloading Chromium if no suitable version is found on the system.", ).tag(config=True) paginate = Bool( True, help=""" Split generated notebook into multiple pages. If False, a PDF with one long page will be generated. Set to True to match behavior of LaTeX based PDF generator """, ).tag(config=True) @default("file_extension") def _file_extension_default(self): return ".html" @default("template_name") def _template_name_default(self): return "webpdf" disable_sandbox = Bool( False, help=""" Disable chromium security sandbox when converting to PDF. WARNING: This could cause arbitrary code execution in specific circumstances, where JS in your notebook can execute serverside code! Please use with caution. ``https://github.com/puppeteer/puppeteer/blob/main@%7B2020-12-14T17:22:24Z%7D/docs/troubleshooting.md#setting-up-chrome-linux-sandbox`` has more information. This is required for webpdf to work inside most container environments. """, ).tag(config=True) def run_playwright(self, html): """Run playwright.""" async def main(temp_file): """Run main playwright script.""" args = ["--no-sandbox"] if self.disable_sandbox else [] try: from playwright.async_api import async_playwright # type: ignore[import-not-found] except ModuleNotFoundError as e: msg = ( "Playwright is not installed to support Web PDF conversion. " "Please install `nbconvert[webpdf]` to enable." ) raise RuntimeError(msg) from e if self.allow_chromium_download: cmd = [sys.executable, "-m", "playwright", "install", "chromium"] subprocess.check_call(cmd) # noqa: S603 playwright = await async_playwright().start() chromium = playwright.chromium try: browser = await chromium.launch( handle_sigint=False, handle_sigterm=False, handle_sighup=False, args=args ) except Exception as e: msg = ( "No suitable chromium executable found on the system. " "Please use '--allow-chromium-download' to allow downloading one," "or install it using `playwright install chromium`." ) await playwright.stop() raise RuntimeError(msg) from e page = await browser.new_page() await page.emulate_media(media="print") await page.wait_for_timeout(100) await page.goto(f"file://{temp_file.name}", wait_until="networkidle") await page.wait_for_timeout(100) pdf_params = {"print_background": True} if not self.paginate: # Floating point precision errors cause the printed # PDF from spilling over a new page by a pixel fraction. dimensions = await page.evaluate( """() => { const rect = document.body.getBoundingClientRect(); return { width: Math.ceil(rect.width) + 1, height: Math.ceil(rect.height) + 1, } }""" ) width = dimensions["width"] height = dimensions["height"] # 200 inches is the maximum size for Adobe Acrobat Reader. pdf_params.update( { "width": min(width, 200 * 72), "height": min(height, 200 * 72), } ) pdf_data = await page.pdf(**pdf_params) await browser.close() await playwright.stop() return pdf_data pool = concurrent.futures.ThreadPoolExecutor() # Create a temporary file to pass the HTML code to Chromium: # Unfortunately, tempfile on Windows does not allow for an already open # file to be opened by a separate process. So we must close it first # before calling Chromium. We also specify delete=False to ensure the # file is not deleted after closing (the default behavior). temp_file = tempfile.NamedTemporaryFile(suffix=".html", delete=False) with temp_file: temp_file.write(html.encode("utf-8")) try: # TODO: when dropping Python 3.6, use # pdf_data = pool.submit(asyncio.run, main(temp_file)).result() def run_coroutine(coro): """Run an internal coroutine.""" loop = ( asyncio.ProactorEventLoop() # type:ignore[attr-defined] if IS_WINDOWS else asyncio.new_event_loop() ) asyncio.set_event_loop(loop) return loop.run_until_complete(coro) pdf_data = pool.submit(run_coroutine, main(temp_file)).result() finally: # Ensure the file is deleted even if playwright raises an exception os.unlink(temp_file.name) return pdf_data def from_notebook_node(self, nb, resources=None, **kw): """Convert from a notebook node.""" html, resources = super().from_notebook_node(nb, resources=resources, **kw) self.log.info("Building PDF") pdf_data = self.run_playwright(html) self.log.info("PDF successfully created") # convert output extension to pdf # the writer above required it to be html resources["output_extension"] = ".pdf" return pdf_data, resources nbconvert-7.16.4/nbconvert/filters/000077500000000000000000000000001461373220400172635ustar00rootroot00000000000000nbconvert-7.16.4/nbconvert/filters/__init__.py000066400000000000000000000030521461373220400213740ustar00rootroot00000000000000from nbconvert.utils.text import indent from .ansi import ansi2html, ansi2latex, strip_ansi from .citation import citation2latex from .datatypefilter import DataTypeFilter from .highlight import Highlight2HTML, Highlight2Latex from .latex import escape_latex from .markdown import ( markdown2asciidoc, markdown2html, markdown2html_mistune, markdown2html_pandoc, markdown2latex, markdown2rst, ) from .metadata import get_metadata from .pandoc import ConvertExplicitlyRelativePaths, convert_pandoc from .strings import ( add_anchor, add_prompts, ascii_only, clean_html, comment_lines, get_lines, html2text, ipython2python, path2url, posix_path, prevent_list_blocks, strip_dollars, strip_files_prefix, strip_trailing_newline, text_base64, wrap_text, ) __all__ = [ "indent", "ansi2html", "ansi2latex", "strip_ansi", "citation2latex", "DataTypeFilter", "Highlight2HTML", "Highlight2Latex", "escape_latex", "markdown2html", "markdown2html_pandoc", "markdown2html_mistune", "markdown2latex", "markdown2rst", "markdown2asciidoc", "get_metadata", "convert_pandoc", "ConvertExplicitlyRelativePaths", "wrap_text", "html2text", "clean_html", "add_anchor", "strip_dollars", "strip_files_prefix", "comment_lines", "get_lines", "ipython2python", "posix_path", "path2url", "add_prompts", "ascii_only", "prevent_list_blocks", "strip_trailing_newline", "text_base64", ] nbconvert-7.16.4/nbconvert/filters/ansi.py000066400000000000000000000175521461373220400206010ustar00rootroot00000000000000"""Filters for processing ANSI colors within Jinja templates.""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. import re import markupsafe __all__ = ["strip_ansi", "ansi2html", "ansi2latex"] _ANSI_RE = re.compile("\x1b\\[(.*?)([@-~])") _ANSI_COLORS = ( "ansi-black", "ansi-red", "ansi-green", "ansi-yellow", "ansi-blue", "ansi-magenta", "ansi-cyan", "ansi-white", "ansi-black-intense", "ansi-red-intense", "ansi-green-intense", "ansi-yellow-intense", "ansi-blue-intense", "ansi-magenta-intense", "ansi-cyan-intense", "ansi-white-intense", ) def strip_ansi(source): """ Remove ANSI escape codes from text. Parameters ---------- source : str Source to remove the ANSI from """ return _ANSI_RE.sub("", source) def ansi2html(text): """ Convert ANSI colors to HTML colors. Parameters ---------- text : unicode Text containing ANSI colors to convert to HTML """ text = markupsafe.escape(text) return _ansi2anything(text, _htmlconverter) def ansi2latex(text): """ Convert ANSI colors to LaTeX colors. Parameters ---------- text : unicode Text containing ANSI colors to convert to LaTeX """ return _ansi2anything(text, _latexconverter) def _htmlconverter(fg, bg, bold, underline, inverse): """ Return start and end tags for given foreground/background/bold/underline. """ if (fg, bg, bold, underline, inverse) == (None, None, False, False, False): return "", "" classes = [] styles = [] if inverse: fg, bg = bg, fg if isinstance(fg, int): classes.append(_ANSI_COLORS[fg] + "-fg") elif fg: styles.append("color: rgb({},{},{})".format(*fg)) elif inverse: classes.append("ansi-default-inverse-fg") if isinstance(bg, int): classes.append(_ANSI_COLORS[bg] + "-bg") elif bg: styles.append("background-color: rgb({},{},{})".format(*bg)) elif inverse: classes.append("ansi-default-inverse-bg") if bold: classes.append("ansi-bold") if underline: classes.append("ansi-underline") starttag = "" def _latexconverter(fg, bg, bold, underline, inverse): """ Return start and end markup given foreground/background/bold/underline. """ if (fg, bg, bold, underline, inverse) == (None, None, False, False, False): return "", "" starttag, endtag = "", "" if inverse: fg, bg = bg, fg if isinstance(fg, int): starttag += r"\textcolor{" + _ANSI_COLORS[fg] + "}{" endtag = "}" + endtag elif fg: # See http://tex.stackexchange.com/a/291102/13684 starttag += r"\def\tcRGB{\textcolor[RGB]}\expandafter" starttag += r"\tcRGB\expandafter{{\detokenize{{{},{},{}}}}}{{".format(*fg) endtag = "}" + endtag elif inverse: starttag += r"\textcolor{ansi-default-inverse-fg}{" endtag = "}" + endtag if isinstance(bg, int): starttag += r"\setlength{\fboxsep}{0pt}" starttag += r"\colorbox{" + _ANSI_COLORS[bg] + "}{" endtag = r"\strut}" + endtag elif bg: starttag += r"\setlength{\fboxsep}{0pt}" # See http://tex.stackexchange.com/a/291102/13684 starttag += r"\def\cbRGB{\colorbox[RGB]}\expandafter" starttag += r"\cbRGB\expandafter{{\detokenize{{{},{},{}}}}}{{".format(*bg) endtag = r"\strut}" + endtag elif inverse: starttag += r"\setlength{\fboxsep}{0pt}" starttag += r"\colorbox{ansi-default-inverse-bg}{" endtag = r"\strut}" + endtag if bold: starttag += r"\textbf{" endtag = "}" + endtag if underline: starttag += r"\underline{" endtag = "}" + endtag return starttag, endtag def _ansi2anything(text, converter): r""" Convert ANSI colors to HTML or LaTeX. See https://en.wikipedia.org/wiki/ANSI_escape_code Accepts codes like '\x1b[32m' (red) and '\x1b[1;32m' (bold, red). Non-color escape sequences (not ending with 'm') are filtered out. Ideally, this should have the same behavior as the function fixConsole() in notebook/notebook/static/base/js/utils.js. """ fg, bg = None, None bold = False underline = False inverse = False numbers = [] out = [] while text: m = _ANSI_RE.search(text) if m: if m.group(2) == "m": try: # Empty code is same as code 0 numbers = [int(n) if n else 0 for n in m.group(1).split(";")] except ValueError: pass # Invalid color specification else: pass # Not a color code chunk, text = text[: m.start()], text[m.end() :] else: chunk, text = text, "" if chunk: starttag, endtag = converter( fg + 8 if bold and fg in range(8) else fg, # type:ignore[operator] bg, bold, underline, inverse, ) out.append(starttag) out.append(chunk) out.append(endtag) while numbers: n = numbers.pop(0) if n == 0: # Code 0 (same as empty code): reset everything fg = bg = None bold = underline = inverse = False elif n == 1: bold = True elif n == 4: underline = True elif n == 5: # Code 5: blinking bold = True elif n == 7: inverse = True elif n in (21, 22): bold = False elif n == 24: underline = False elif n == 27: inverse = False elif 30 <= n <= 37: fg = n - 30 elif n == 38: try: fg = _get_extended_color(numbers) except ValueError: numbers.clear() elif n == 39: fg = None elif 40 <= n <= 47: bg = n - 40 elif n == 48: try: bg = _get_extended_color(numbers) except ValueError: numbers.clear() elif n == 49: bg = None elif 90 <= n <= 97: fg = n - 90 + 8 elif 100 <= n <= 107: bg = n - 100 + 8 else: pass # Unknown codes are ignored return "".join(out) def _get_extended_color(numbers): n = numbers.pop(0) if n == 2 and len(numbers) >= 3: # 24-bit RGB r = numbers.pop(0) g = numbers.pop(0) b = numbers.pop(0) if not all(0 <= c <= 255 for c in (r, g, b)): raise ValueError() elif n == 5 and len(numbers) >= 1: # 256 colors idx = numbers.pop(0) if idx < 0: raise ValueError() if idx < 16: # 16 default terminal colors return idx if idx < 232: # 6x6x6 color cube, see http://stackoverflow.com/a/27165165/500098 r = (idx - 16) // 36 r = 55 + r * 40 if r > 0 else 0 g = ((idx - 16) % 36) // 6 g = 55 + g * 40 if g > 0 else 0 b = (idx - 16) % 6 b = 55 + b * 40 if b > 0 else 0 elif idx < 256: # grayscale, see http://stackoverflow.com/a/27165165/500098 r = g = b = (idx - 232) * 10 + 8 else: raise ValueError() else: raise ValueError() return r, g, b nbconvert-7.16.4/nbconvert/filters/citation.py000066400000000000000000000071561461373220400214600ustar00rootroot00000000000000"""Citation handling for LaTeX output.""" # ----------------------------------------------------------------------------- # Copyright (c) 2013, the IPython Development Team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file COPYING.txt, distributed with this software. # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # Imports # ----------------------------------------------------------------------------- from html.parser import HTMLParser # ----------------------------------------------------------------------------- # Functions # ----------------------------------------------------------------------------- __all__ = ["citation2latex"] def citation2latex(s): """Parse citations in Markdown cells. This looks for HTML tags having a data attribute names ``data-cite`` and replaces it by the call to LaTeX cite command. The transformation looks like this:: (Granger, 2013) Becomes :: \\cite{granger} Any HTML tag can be used, which allows the citations to be formatted in HTML in any manner. """ parser = CitationParser() parser.feed(s) parser.close() outtext = "" startpos = 0 for citation in parser.citelist: outtext += s[startpos : citation[1]] outtext += "\\cite{%s}" % citation[0] startpos = citation[2] if len(citation) == 3 else -1 outtext += s[startpos:] if startpos != -1 else "" return outtext # ----------------------------------------------------------------------------- # Classes # ----------------------------------------------------------------------------- class CitationParser(HTMLParser): """Citation Parser Replaces html tags with data-cite attribute with respective latex \\cite. Inherites from HTMLParser, overrides: - handle_starttag - handle_endtag """ # number of open tags opentags = None # list of found citations citelist = None # type:ignore[var-annotated] # active citation tag citetag = None def __init__(self): """Initialize the parser.""" self.citelist = [] self.opentags = 0 HTMLParser.__init__(self) def get_offset(self): """Get the offset position.""" # Compute startposition in source lin, offset = self.getpos() pos = 0 for _ in range(lin - 1): pos = self.data.find("\n", pos) + 1 return pos + offset def handle_starttag(self, tag, attrs): """Handle a start tag.""" # for each tag check if attributes are present and if no citation is active if self.opentags == 0 and len(attrs) > 0: for atr, data in attrs: if atr.lower() == "data-cite": self.citetag = tag self.opentags = 1 self.citelist.append([data, self.get_offset()]) return if tag == self.citetag: # found an open citation tag but not the starting one self.opentags += 1 # type:ignore[operator] def handle_endtag(self, tag): """Handle an end tag.""" if tag == self.citetag: # found citation tag check if starting one if self.opentags == 1: pos = self.get_offset() self.citelist[-1].append(pos + len(tag) + 3) self.opentags -= 1 # type:ignore[operator] def feed(self, data): """Handle a feed.""" self.data = data HTMLParser.feed(self, data) nbconvert-7.16.4/nbconvert/filters/datatypefilter.py000066400000000000000000000030241461373220400226550ustar00rootroot00000000000000"""Filter used to select the first preferred output format available. The filter contained in the file allows the converter templates to select the output format that is most valuable to the active export format. The value of the different formats is set via NbConvertBase.display_data_priority """ # ----------------------------------------------------------------------------- # Copyright (c) 2013, the IPython Development Team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file COPYING.txt, distributed with this software. # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # Classes and functions # ----------------------------------------------------------------------------- from warnings import warn from nbconvert.utils.base import NbConvertBase __all__ = ["DataTypeFilter"] class DataTypeFilter(NbConvertBase): """Returns the preferred display format""" def __call__(self, output): """Return the first available format in the priority. Produces a UserWarning if no compatible mimetype is found. `output` is dict with structure {mimetype-of-element: value-of-element} """ for fmt in self.display_data_priority: if fmt in output: return [fmt] warn( f"Your element with mimetype(s) {output.keys()} is not able to be represented.", stacklevel=2, ) return [] nbconvert-7.16.4/nbconvert/filters/filter_links.py000066400000000000000000000030241461373220400223210ustar00rootroot00000000000000"""A pandoc filter used in converting notebooks to Latex. Converts links between notebooks to Latex cross-references. """ import re from pandocfilters import RawInline, applyJSONFilters, stringify # type:ignore[import-untyped] def resolve_references(source): """ This applies the resolve_one_reference to the text passed in via the source argument. This expects content in the form of a string encoded JSON object as represented internally in ``pandoc``. """ return applyJSONFilters([resolve_one_reference], source) def resolve_one_reference(key, val, fmt, meta): """ This takes a tuple of arguments that are compatible with ``pandocfilters.walk()`` that allows identifying hyperlinks in the document and transforms them into valid LaTeX \\hyperref{} calls so that linking to headers between cells is possible. See the documentation in ``pandocfilters.walk()`` for further information on the meaning and specification of ``key``, ``val``, ``fmt``, and ``meta``. """ if key == "Link": text = stringify(val[1]) target = val[2][0] m = re.match(r"#(.+)$", target) if m: # pandoc automatically makes labels for headings. label = m.group(1).lower() label = re.sub(r"[^\w-]+", "", label) # Strip HTML entities text = re.sub(r"_", r"\_", text) # Escape underscores in display text return RawInline("tex", rf"\hyperref[{label}]{{{text}}}") return None # Other elements will be returned unchanged. nbconvert-7.16.4/nbconvert/filters/highlight.py000066400000000000000000000137431461373220400216140ustar00rootroot00000000000000""" Module containing filter functions that allow code to be highlighted from within Jinja templates. """ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. # pygments must not be imported at the module level # because errors should be raised at runtime if it's actually needed, # not import time, when it may not be needed. from html import escape from warnings import warn from traitlets import Dict, observe from nbconvert.utils.base import NbConvertBase MULTILINE_OUTPUTS = ["text", "html", "svg", "latex", "javascript", "json"] __all__ = ["Highlight2HTML", "Highlight2Latex"] class Highlight2HTML(NbConvertBase): """Convert highlighted code to html.""" extra_formatter_options = Dict( {}, help=""" Extra set of options to control how code is highlighted. Passed through to the pygments' HtmlFormatter class. See available list in https://pygments.org/docs/formatters/#HtmlFormatter """, config=True, ) def __init__(self, pygments_lexer=None, **kwargs): """Initialize the converter.""" self.pygments_lexer = pygments_lexer or "ipython3" super().__init__(**kwargs) @observe("default_language") def _default_language_changed(self, change): warn( "Setting default_language in config is deprecated as of 5.0, " "please use language_info metadata instead.", stacklevel=2, ) self.pygments_lexer = change["new"] def __call__(self, source, language=None, metadata=None): """ Return a syntax-highlighted version of the input source as html output. Parameters ---------- source : str source of the cell to highlight language : str language to highlight the syntax of metadata : NotebookNode cell metadata metadata of the cell to highlight """ from pygments.formatters import HtmlFormatter if not language: language = self.pygments_lexer return _pygments_highlight( source if len(source) > 0 else " ", # needed to help post processors: HtmlFormatter( cssclass=escape(f" highlight hl-{language}"), **self.extra_formatter_options ), language, metadata, ) class Highlight2Latex(NbConvertBase): """Convert highlighted code to latex.""" extra_formatter_options = Dict( {}, help=""" Extra set of options to control how code is highlighted. Passed through to the pygments' LatexFormatter class. See available list in https://pygments.org/docs/formatters/#LatexFormatter """, config=True, ) def __init__(self, pygments_lexer=None, **kwargs): """Initialize the converter.""" self.pygments_lexer = pygments_lexer or "ipython3" super().__init__(**kwargs) @observe("default_language") def _default_language_changed(self, change): warn( "Setting default_language in config is deprecated as of 5.0, " "please use language_info metadata instead.", stacklevel=2, ) self.pygments_lexer = change["new"] def __call__(self, source, language=None, metadata=None, strip_verbatim=False): """ Return a syntax-highlighted version of the input source as latex output. Parameters ---------- source : str source of the cell to highlight language : str language to highlight the syntax of metadata : NotebookNode cell metadata metadata of the cell to highlight strip_verbatim : bool remove the Verbatim environment that pygments provides by default """ from pygments.formatters import LatexFormatter if not language: language = self.pygments_lexer latex = _pygments_highlight( source, LatexFormatter(**self.extra_formatter_options), language, metadata ) if strip_verbatim: latex = latex.replace(r"\begin{Verbatim}[commandchars=\\\{\}]" + "\n", "") return latex.replace("\n\\end{Verbatim}\n", "") return latex def _pygments_highlight(source, output_formatter, language="ipython", metadata=None): """ Return a syntax-highlighted version of the input source Parameters ---------- source : str source of the cell to highlight output_formatter : Pygments formatter language : str language to highlight the syntax of metadata : NotebookNode cell metadata metadata of the cell to highlight """ from pygments import highlight from pygments.lexers import get_lexer_by_name from pygments.util import ClassNotFound # If the cell uses a magic extension language, # use the magic language instead. if language.startswith("ipython") and metadata and "magics_language" in metadata: language = metadata["magics_language"] lexer = None if language == "ipython2": try: from IPython.lib.lexers import IPythonLexer except ImportError: warn("IPython lexer unavailable, falling back on Python", stacklevel=2) language = "python" else: lexer = IPythonLexer() elif language == "ipython3": try: from IPython.lib.lexers import IPython3Lexer except ImportError: warn("IPython3 lexer unavailable, falling back on Python 3", stacklevel=2) language = "python3" else: lexer = IPython3Lexer() if lexer is None: try: lexer = get_lexer_by_name(language, stripall=True) except ClassNotFound: warn("No lexer found for language %r. Treating as plain text." % language, stacklevel=2) from pygments.lexers.special import TextLexer lexer = TextLexer() return highlight(source, lexer, output_formatter) nbconvert-7.16.4/nbconvert/filters/latex.py000066400000000000000000000034331461373220400207550ustar00rootroot00000000000000"""Latex filters. Module of useful filters for processing Latex within Jinja latex templates. """ # ----------------------------------------------------------------------------- # Copyright (c) 2013, the IPython Development Team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file COPYING.txt, distributed with this software. # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # Imports # ----------------------------------------------------------------------------- import re # ----------------------------------------------------------------------------- # Globals and constants # ----------------------------------------------------------------------------- LATEX_RE_SUBS = ((re.compile(r"\.\.\.+"), r"{\\ldots}"),) # Latex substitutions for escaping latex. # see: http://stackoverflow.com/questions/16259923/how-can-i-escape-latex-special-characters-inside-django-templates LATEX_SUBS = { "&": r"\&", "%": r"\%", "$": r"\$", "#": r"\#", "_": r"\_", "{": r"\{", "}": r"\}", "~": r"\textasciitilde{}", "^": r"\^{}", "\\": r"\textbackslash{}", } # ----------------------------------------------------------------------------- # Functions # ----------------------------------------------------------------------------- __all__ = ["escape_latex"] def escape_latex(text): """ Escape characters that may conflict with latex. Parameters ---------- text : str Text containing characters that may conflict with Latex """ text = "".join(LATEX_SUBS.get(c, c) for c in text) for pattern, replacement in LATEX_RE_SUBS: text = pattern.sub(replacement, text) return text nbconvert-7.16.4/nbconvert/filters/markdown.py000066400000000000000000000054301461373220400214610ustar00rootroot00000000000000"""Markdown filters This file contains a collection of utility filters for dealing with markdown within Jinja templates. """ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. import re try: from .markdown_mistune import markdown2html_mistune except ImportError as e: _mistune_import_error = e def markdown2html_mistune(source: str) -> str: """mistune is unavailable, raise ImportError""" msg = f"markdown2html requires mistune: {_mistune_import_error}" raise ImportError(msg) from .pandoc import convert_pandoc __all__ = [ "markdown2html", "markdown2html_pandoc", "markdown2html_mistune", "markdown2latex", "markdown2rst", "markdown2asciidoc", ] def markdown2latex(source, markup="markdown", extra_args=None): """ Convert a markdown string to LaTeX via pandoc. This function will raise an error if pandoc is not installed. Any error messages generated by pandoc are printed to stderr. Parameters ---------- source : string Input string, assumed to be valid markdown. markup : string Markup used by pandoc's reader default : pandoc extended markdown (see https://pandoc.org/README.html#pandocs-markdown) Returns ------- out : string Output as returned by pandoc. """ return convert_pandoc(source, markup, "latex", extra_args=extra_args) def markdown2html_pandoc(source, extra_args=None): """ Convert a markdown string to HTML via pandoc. """ extra_args = extra_args or ["--mathjax"] return convert_pandoc(source, "markdown", "html", extra_args=extra_args) def markdown2asciidoc(source, extra_args=None): """Convert a markdown string to asciidoc via pandoc""" extra_args = extra_args or ["--atx-headers"] asciidoc = convert_pandoc(source, "markdown", "asciidoc", extra_args=extra_args) # workaround for https://github.com/jgm/pandoc/issues/3068 if "__" in asciidoc: asciidoc = re.sub(r"\b__([\w \n-]+)__([:,.\n\)])", r"_\1_\2", asciidoc) # urls / links: asciidoc = re.sub(r"\(__([\w\/-:\.]+)__\)", r"(_\1_)", asciidoc) return asciidoc # The mistune renderer is the default, because it's simple to depend on it markdown2html = markdown2html_mistune def markdown2rst(source, extra_args=None): """ Convert a markdown string to ReST via pandoc. This function will raise an error if pandoc is not installed. Any error messages generated by pandoc are printed to stderr. Parameters ---------- source : string Input string, assumed to be valid markdown. Returns ------- out : string Output as returned by pandoc. """ return convert_pandoc(source, "markdown", "rst", extra_args=extra_args) nbconvert-7.16.4/nbconvert/filters/markdown_mistune.py000066400000000000000000000436721461373220400232370ustar00rootroot00000000000000"""Markdown filters with mistune Used from markdown.py """ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. import base64 import mimetypes import os from html import escape from typing import Any, Callable, Dict, Iterable, Match, Optional, Tuple import bs4 from pygments import highlight from pygments.formatters import HtmlFormatter from pygments.lexer import Lexer from pygments.lexers import get_lexer_by_name from pygments.util import ClassNotFound from nbconvert.filters.strings import add_anchor try: # for Mistune >= 3.0 from mistune import ( # type:ignore[attr-defined] BlockParser, BlockState, HTMLRenderer, InlineParser, InlineState, Markdown, import_plugin, ) MISTUNE_V3 = True except ImportError: # for Mistune >= 2.0 import re from mistune import ( # type: ignore[attr-defined] PLUGINS, BlockParser, HTMLRenderer, InlineParser, Markdown, ) MISTUNE_V3 = False def import_plugin(name: str) -> "MarkdownPlugin": # type: ignore[misc] """Simple implementation of Mistune V3's import_plugin for V2.""" return PLUGINS[name] # type: ignore[no-any-return] class InvalidNotebook(Exception): """An invalid notebook model.""" def _dotall(pattern: str) -> str: """Makes the '.' special character match any character inside the pattern, including a newline. This is implemented with the inline flag `(?s:...)` and is equivalent to using `re.DOTALL`. It is useful for LaTeX environments, where line breaks may be present. """ return f"(?s:{pattern})" if MISTUNE_V3: # Parsers for Mistune >= 3.0.0 class MathBlockParser(BlockParser): """This acts as a pass-through to the MathInlineParser. It is needed in order to avoid other block level rules splitting math sections apart. It works by matching each multiline math environment as a single paragraph, so that other rules don't think each section is its own paragraph. Inline is ignored here. """ AXT_HEADING_WITHOUT_LEADING_SPACES = ( r"^ {0,3}(?P#{1,6})(?!#+)(?P[ \t]*(.*?)?)$" ) MULTILINE_MATH = _dotall( # Display math mode, old TeX delimiter: $$ \sqrt{2} $$ r"(?[a-z]*\*?)\}.*?\\end\{(?P=math_env_name)\}" ) SPECIFICATION = { **BlockParser.SPECIFICATION, "axt_heading": AXT_HEADING_WITHOUT_LEADING_SPACES, "multiline_math": MULTILINE_MATH, } # Multiline math must be searched before other rules DEFAULT_RULES: Tuple[str, ...] = ("multiline_math", *BlockParser.DEFAULT_RULES) # type: ignore[assignment] def parse_multiline_math(self, m: Match[str], state: BlockState) -> int: """Send mutiline math as a single paragraph to MathInlineParser.""" matched_text = m[0] state.add_paragraph(matched_text) return m.end() class MathInlineParser(InlineParser): r"""This interprets the content of LaTeX style math objects. In particular this grabs ``$$...$$``, ``\\[...\\]``, ``\\(...\\)``, ``$...$``, and ``\begin{foo}...\end{foo}`` styles for declaring mathematics. It strips delimiters from all these varieties, and extracts the type of environment in the last case (``foo`` in this example). """ # Display math mode, using older TeX delimiter: $$ \pi $$ BLOCK_MATH_TEX = _dotall(r"(?.*?)(?.*?)(?.+?)(?.*?)(?[a-z]*\*?)\}" r"(?P.*?)" r"\\end\{(?P=math_env_name)\}" ) SPECIFICATION = { **InlineParser.SPECIFICATION, "block_math_tex": BLOCK_MATH_TEX, "block_math_latex": BLOCK_MATH_LATEX, "inline_math_tex": INLINE_MATH_TEX, "inline_math_latex": INLINE_MATH_LATEX, "latex_environment": LATEX_ENVIRONMENT, } # Block math must be matched first, and all math must come before text DEFAULT_RULES: Tuple[str, ...] = ( "block_math_tex", "block_math_latex", "inline_math_tex", "inline_math_latex", "latex_environment", *InlineParser.DEFAULT_RULES, ) # type: ignore[assignment] def parse_block_math_tex(self, m: Match[str], state: InlineState) -> int: """Parse older TeX-style display math.""" body = m.group("math_block_tex") state.append_token({"type": "block_math", "raw": body}) return m.end() def parse_block_math_latex(self, m: Match[str], state: InlineState) -> int: """Parse newer LaTeX-style display math.""" body = m.group("math_block_latex") state.append_token({"type": "block_math", "raw": body}) return m.end() def parse_inline_math_tex(self, m: Match[str], state: InlineState) -> int: """Parse older TeX-style inline math.""" body = m.group("math_inline_tex") state.append_token({"type": "inline_math", "raw": body}) return m.end() def parse_inline_math_latex(self, m: Match[str], state: InlineState) -> int: """Parse newer LaTeX-style inline math.""" body = m.group("math_inline_latex") state.append_token({"type": "inline_math", "raw": body}) return m.end() def parse_latex_environment(self, m: Match[str], state: InlineState) -> int: """Parse a latex environment.""" attrs = {"name": m.group("math_env_name"), "body": m.group("math_env_body")} state.append_token({"type": "latex_environment", "attrs": attrs}) return m.end() else: # Parsers for Mistune >= 2.0.0 < 3.0.0 class MathBlockParser(BlockParser): # type: ignore[no-redef] """This acts as a pass-through to the MathInlineParser. It is needed in order to avoid other block level rules splitting math sections apart. """ MULTILINE_MATH = re.compile( # Display math mode, old TeX delimiter: $$ \sqrt{2} $$ r"(? Dict[str, str]: """Pass token through mutiline math.""" return {"type": "multiline_math", "text": m.group(0)} class MathInlineParser(InlineParser): # type: ignore[no-redef] r"""This interprets the content of LaTeX style math objects. In particular this grabs ``$$...$$``, ``\\[...\\]``, ``\\(...\\)``, ``$...$``, and ``\begin{foo}...\end{foo}`` styles for declaring mathematics. It strips delimiters from all these varieties, and extracts the type of environment in the last case (``foo`` in this example). """ # Display math mode, using older TeX delimiter: $$ \pi $$ BLOCK_MATH_TEX = _dotall(r"(? Tuple[str, str]: """Parse block text math.""" # sometimes the Scanner keeps the final '$$', so we use the # full matched string and remove the math markers text = m.group(0)[2:-2] return "block_math", text def parse_block_math_latex(self, m: Match[str], state: Any) -> Tuple[str, str]: """Parse block latex math .""" text = m.group(1) return "block_math", text def parse_inline_math_tex(self, m: Match[str], state: Any) -> Tuple[str, str]: """Parse inline tex math.""" text = m.group(1) return "inline_math", text def parse_inline_math_latex(self, m: Match[str], state: Any) -> Tuple[str, str]: """Parse inline latex math.""" text = m.group(1) return "inline_math", text def parse_latex_environment(self, m: Match[str], state: Any) -> Tuple[str, str, str]: """Parse a latex environment.""" name, text = m.group(1), m.group(2) return "latex_environment", name, text class IPythonRenderer(HTMLRenderer): """An ipython html renderer.""" def __init__( self, escape: bool = True, allow_harmful_protocols: bool = True, embed_images: bool = False, exclude_anchor_links: bool = False, anchor_link_text: str = "¶", path: str = "", attachments: Optional[Dict[str, Dict[str, str]]] = None, ): """Initialize the renderer.""" super().__init__(escape, allow_harmful_protocols) self.embed_images = embed_images self.exclude_anchor_links = exclude_anchor_links self.anchor_link_text = anchor_link_text self.path = path if attachments is not None: self.attachments = attachments else: self.attachments = {} def block_code(self, code: str, info: Optional[str] = None) -> str: """Handle block code.""" lang: Optional[str] = "" lexer: Optional[Lexer] = None if info: if info.startswith("mermaid"): return self.block_mermaidjs(code) try: if info.strip().split(None, 1): lang = info.strip().split(maxsplit=1)[0] lexer = get_lexer_by_name(lang, stripall=True) except ClassNotFound: code = f"{lang}\n{code}" lang = None if not lang: return super().block_code(code, info=info) formatter = HtmlFormatter() return highlight(code, lexer, formatter) def block_mermaidjs(self, code: str) -> str: """Handle mermaid syntax.""" return ( """""" ) def block_html(self, html: str) -> str: """Handle block html.""" if self.embed_images: html = self._html_embed_images(html) return super().block_html(html) def inline_html(self, html: str) -> str: """Handle inline html.""" if self.embed_images: html = self._html_embed_images(html) return super().inline_html(html) def heading(self, text: str, level: int, **attrs: Dict[str, Any]) -> str: """Handle a heading.""" html = super().heading(text, level, **attrs) if self.exclude_anchor_links: return html return str(add_anchor(html, anchor_link_text=self.anchor_link_text)) def escape_html(self, text: str) -> str: """Escape html content.""" return escape(text, quote=False) def block_math(self, body: str) -> str: """Handle block math.""" return f"$${self.escape_html(body)}$$" def multiline_math(self, text: str) -> str: """Handle mulitline math for older mistune versions.""" return text def latex_environment(self, name: str, body: str) -> str: """Handle a latex environment.""" name, body = self.escape_html(name), self.escape_html(body) return f"\\begin{{{name}}}{body}\\end{{{name}}}" def inline_math(self, body: str) -> str: """Handle inline math.""" return f"${self.escape_html(body)}$" def image(self, text: str, url: str, title: Optional[str] = None) -> str: """Rendering a image with title and text. :param text: alt text of the image. :param url: source link of the image. :param title: title text of the image. :note: The parameters `text` and `url` are swapped in older versions of mistune. """ if MISTUNE_V3: url = self._embed_image_or_attachment(url) else: # for mistune v2, the first argument is the URL text = self._embed_image_or_attachment(text) return super().image(text, url, title) def _embed_image_or_attachment(self, src: str) -> str: """Embed an image or attachment, depending on the configuration. If neither is possible, returns the original URL. """ attachment_prefix = "attachment:" if src.startswith(attachment_prefix): name = src[len(attachment_prefix) :] if name not in self.attachments: msg = f"missing attachment: {name}" raise InvalidNotebook(msg) attachment = self.attachments[name] # we choose vector over raster, and lossless over lossy preferred_mime_types = ("image/svg+xml", "image/png", "image/jpeg") for mime_type in preferred_mime_types: if mime_type in attachment: return f"data:{mime_type};base64,{attachment[mime_type]}" # otherwise we choose the first mimetype we can find default_mime_type = next(iter(attachment.keys())) return f"data:{default_mime_type};base64,{attachment[default_mime_type]}" if self.embed_images: base64_url = self._src_to_base64(src) if base64_url is not None: return base64_url return src def _src_to_base64(self, src: str) -> Optional[str]: """Turn the source file into a base64 url. :param src: source link of the file. :return: the base64 url or None if the file was not found. """ src_path = os.path.join(self.path, src) if not os.path.exists(src_path): return None with open(src_path, "rb") as fobj: mime_type, _ = mimetypes.guess_type(src_path) base64_data = base64.b64encode(fobj.read()) base64_str = base64_data.replace(b"\n", b"").decode("ascii") return f"data:{mime_type};base64,{base64_str}" def _html_embed_images(self, html: str) -> str: parsed_html = bs4.BeautifulSoup(html, features="html.parser") imgs: bs4.ResultSet[bs4.Tag] = parsed_html.find_all("img") # Replace img tags's sources by base64 dataurls for img in imgs: src = img.attrs.get("src") if src is None: continue base64_url = self._src_to_base64(img.attrs["src"]) if base64_url is not None: img.attrs["src"] = base64_url return str(parsed_html) # Represents an already imported plugin for Mistune MarkdownPlugin = Callable[[Markdown], None] class MarkdownWithMath(Markdown): """Markdown text with math enabled.""" DEFAULT_PLUGINS = ( # "abbr", (see https://github.com/jupyter/nbconvert/pull/1853) # "footnotes", "strikethrough", "table", "url", "task_lists", "def_list", ) def __init__( self, renderer: HTMLRenderer, block: Optional[BlockParser] = None, inline: Optional[InlineParser] = None, plugins: Optional[Iterable[MarkdownPlugin]] = None, ): """Initialize the parser.""" if block is None: block = MathBlockParser() if inline is None: if MISTUNE_V3: inline = MathInlineParser(hard_wrap=False) else: inline = MathInlineParser(renderer, hard_wrap=False) # type: ignore[arg-type,misc] if plugins is None: plugins = (import_plugin(p) for p in self.DEFAULT_PLUGINS) super().__init__(renderer, block, inline, plugins) def render(self, source: str) -> str: """Render the HTML output for a Markdown source.""" return str(super().__call__(source)) def markdown2html_mistune(source: str) -> str: """Convert a markdown string to HTML using mistune""" return MarkdownWithMath(renderer=IPythonRenderer(escape=False)).render(source) nbconvert-7.16.4/nbconvert/filters/metadata.py000066400000000000000000000007351461373220400214220ustar00rootroot00000000000000"""filters for metadata""" def get_metadata(output, key, mimetype=None): """Resolve an output metadata key If mimetype given, resolve at mimetype level first, then fallback to top-level. Otherwise, just resolve at top-level. Returns None if no data found. """ md = output.get("metadata") or {} if mimetype and mimetype in md: value = md[mimetype].get(key) if value is not None: return value return md.get(key) nbconvert-7.16.4/nbconvert/filters/pandoc.py000066400000000000000000000054631461373220400211110ustar00rootroot00000000000000""" Convert between any two formats using pandoc, and related filters """ import os from pandocfilters import Image, applyJSONFilters # type:ignore[import-untyped] from nbconvert.utils.base import NbConvertBase from nbconvert.utils.pandoc import pandoc __all__ = ["ConvertExplicitlyRelativePaths", "convert_pandoc"] def convert_pandoc(source, from_format, to_format, extra_args=None): """Convert between any two formats using pandoc. This function will raise an error if pandoc is not installed. Any error messages generated by pandoc are printed to stderr. Parameters ---------- source : string Input string, assumed to be valid in from_format. from_format : string Pandoc format of source. to_format : string Pandoc format for output. Returns ------- out : string Output as returned by pandoc. """ return pandoc(source, from_format, to_format, extra_args=extra_args) # When converting to pdf, explicitly relative references # like "./" and "../" doesn't work with TEXINPUTS. # So we need to convert them to absolute paths. # See https://github.com/jupyter/nbconvert/issues/1998 class ConvertExplicitlyRelativePaths(NbConvertBase): """A converter that handles relative path references.""" def __init__(self, texinputs=None, **kwargs): """Initialize the converter.""" # texinputs should be the directory of the notebook file self.nb_dir = os.path.abspath(texinputs) if texinputs else "" self.ancestor_dirs = self.nb_dir.split("/") super().__init__(**kwargs) def __call__(self, source): """Invoke the converter.""" # If this is not set for some reason, we can't do anything, if self.nb_dir: return applyJSONFilters([self.action], source) return source def action(self, key, value, frmt, meta): """Perform the action.""" # Convert explicitly relative paths: # ./path -> path (This should be visible to the latex engine since TEXINPUTS already has .) # ../path -> /abs_path # assuming all relative references are at the start of a given path if key == "Image": # Image seems to have this composition, according to https://github.com/jgm/pandoc-types attr, caption, [filename, typedef] = value if filename[:2] == "./": filename = filename[2:] elif filename[:3] == "../": n_up = 0 while filename[:3] == "../": n_up += 1 filename = filename[3:] ancestors = "/".join(self.ancestor_dirs[:-n_up]) + "/" filename = ancestors + filename return Image(attr, caption, [filename, typedef]) # If not image, return "no change" return None nbconvert-7.16.4/nbconvert/filters/strings.py000066400000000000000000000165601461373220400213360ustar00rootroot00000000000000"""String filters. Contains a collection of useful string manipulation filters for use in Jinja templates. """ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. import base64 import os import re import textwrap import warnings from urllib.parse import quote from xml.etree.ElementTree import Element import bleach # defusedxml does safe(r) parsing of untrusted XML data from defusedxml import ElementTree # type:ignore[import-untyped] from nbconvert.preprocessors.sanitize import _get_default_css_sanitizer __all__ = [ "wrap_text", "html2text", "clean_html", "add_anchor", "strip_dollars", "strip_files_prefix", "comment_lines", "get_lines", "ipython2python", "posix_path", "path2url", "add_prompts", "ascii_only", "prevent_list_blocks", "strip_trailing_newline", "text_base64", ] def wrap_text(text, width=100): """ Intelligently wrap text. Wrap text without breaking words if possible. Parameters ---------- text : str Text to wrap. width : int, optional Number of characters to wrap to, default 100. """ split_text = text.split("\n") wrp = map(lambda x: textwrap.wrap(x, width), split_text) # noqa: C417 wrpd = map("\n".join, wrp) return "\n".join(wrpd) def html2text(element): """extract inner text from html Analog of jQuery's $(element).text() """ if isinstance(element, (str,)): try: element = ElementTree.fromstring(element) except Exception: # failed to parse, just return it unmodified return element text = element.text or "" for child in element: text += html2text(child) text += element.tail or "" return text def clean_html(element): """Clean an html element.""" element = element.decode() if isinstance(element, bytes) else str(element) kwargs = {} css_sanitizer = _get_default_css_sanitizer() if css_sanitizer: kwargs["css_sanitizer"] = css_sanitizer return bleach.clean( element, tags=[*bleach.ALLOWED_TAGS, "div", "pre", "code", "span", "table", "tr", "td"], attributes={ **bleach.ALLOWED_ATTRIBUTES, "*": ["class", "id"], }, **kwargs, ) def _convert_header_id(header_contents): """Convert header contents to valid id value. Takes string as input, returns string. Note: this may be subject to change in the case of changes to how we wish to generate ids. For use on markdown headings. """ # Valid IDs need to be non-empty and contain no space characters, but are otherwise arbitrary. # However, these IDs are also used in URL fragments, which are more restrictive, so we URL # encode any characters that are not valid in URL fragments. return quote(header_contents.replace(" ", "-"), safe="?/:@!$&'()*+,;=") def add_anchor(html, anchor_link_text="¶"): """Add an id and an anchor-link to an html header For use on markdown headings """ try: h = ElementTree.fromstring(html) except Exception: # failed to parse, just return it unmodified return html link = _convert_header_id(html2text(h)) h.set("id", link) a = Element("a", {"class": "anchor-link", "href": "#" + link}) try: # Test if the anchor link text is HTML (e.g. an image) a.append(ElementTree.fromstring(anchor_link_text)) except Exception: # If we fail to parse, assume we've just got regular text a.text = anchor_link_text h.append(a) return ElementTree.tostring(h).decode(encoding="utf-8") def add_prompts(code, first=">>> ", cont="... "): """Add prompts to code snippets""" new_code = [] code_list = code.split("\n") new_code.append(first + code_list[0]) for line in code_list[1:]: new_code.append(cont + line) return "\n".join(new_code) def strip_dollars(text): """ Remove all dollar symbols from text Parameters ---------- text : str Text to remove dollars from """ return text.strip("$") files_url_pattern = re.compile(r'(src|href)\=([\'"]?)/?files/') markdown_url_pattern = re.compile(r"(!?)\[(?P.*?)\]\(/?files/(?P.*?)\)") def strip_files_prefix(text): """ Fix all fake URLs that start with ``files/``, stripping out the ``files/`` prefix. Applies to both urls (for html) and relative paths (for markdown paths). Parameters ---------- text : str Text in which to replace 'src="files/real...' with 'src="real...' """ cleaned_text = files_url_pattern.sub(r"\1=\2", text) cleaned_text = markdown_url_pattern.sub(r"\1[\2](\3)", cleaned_text) return cleaned_text # noqa: RET504 def comment_lines(text, prefix="# "): """ Build a Python comment line from input text. Parameters ---------- text : str Text to comment out. prefix : str Character to append to the start of each line. """ # Replace line breaks with line breaks and comment symbols. # Also add a comment symbol at the beginning to comment out # the first line. return prefix + ("\n" + prefix).join(text.split("\n")) def get_lines(text, start=None, end=None): """ Split the input text into separate lines and then return the lines that the caller is interested in. Parameters ---------- text : str Text to parse lines from. start : int, optional First line to grab from. end : int, optional Last line to grab from. """ # Split the input into lines. lines = text.split("\n") # Return the right lines. return "\n".join(lines[start:end]) # re-join def ipython2python(code): """Transform IPython syntax to pure Python syntax Parameters ---------- code : str IPython code, to be transformed to pure Python """ try: from IPython.core.inputtransformer2 import TransformerManager except ImportError: warnings.warn( "IPython is needed to transform IPython syntax to pure Python." " Install ipython if you need this functionality.", stacklevel=2, ) return code else: isp = TransformerManager() return isp.transform_cell(code) def posix_path(path): """Turn a path into posix-style path/to/etc Mainly for use in latex on Windows, where native Windows paths are not allowed. """ if os.path.sep != "/": return path.replace(os.path.sep, "/") return path def path2url(path): """Turn a file path into a URL""" parts = path.split(os.path.sep) return "/".join(quote(part) for part in parts) def ascii_only(s): """ensure a string is ascii""" return s.encode("ascii", "replace").decode("ascii") def prevent_list_blocks(s): """ Prevent presence of enumerate or itemize blocks in latex headings cells """ out = re.sub(r"(^\s*\d*)\.", r"\1\.", s) out = re.sub(r"(^\s*)\-", r"\1\-", out) out = re.sub(r"(^\s*)\+", r"\1\+", out) out = re.sub(r"(^\s*)\*", r"\1\*", out) return out # noqa: RET504 def strip_trailing_newline(text): """ Strips a newline from the end of text. """ if text.endswith("\n"): text = text[:-1] return text def text_base64(text): """ Encode base64 text """ return base64.b64encode(text.encode()).decode() nbconvert-7.16.4/nbconvert/filters/widgetsdatatypefilter.py000066400000000000000000000054041461373220400242500ustar00rootroot00000000000000"""Filter used to select the first preferred output format available, excluding interactive widget format if the widget state is not available. The filter contained in the file allows the converter templates to select the output format that is most valuable to the active export format. The value of the different formats is set via NbConvertBase.display_data_priority """ # ----------------------------------------------------------------------------- # Copyright (c) 2013, the IPython Development Team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file COPYING.txt, distributed with this software. # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # Classes and functions # ----------------------------------------------------------------------------- import os from warnings import warn from nbconvert.utils.base import NbConvertBase __all__ = ["WidgetsDataTypeFilter"] WIDGET_VIEW_MIMETYPE = "application/vnd.jupyter.widget-view+json" WIDGET_STATE_MIMETYPE = "application/vnd.jupyter.widget-state+json" class WidgetsDataTypeFilter(NbConvertBase): """Returns the preferred display format, excluding the widget output if there is no widget state available""" def __init__(self, notebook_metadata=None, resources=None, **kwargs): """Initialize the filter.""" self.metadata = notebook_metadata self.notebook_path = "" if resources is not None: name = resources.get("metadata", {}).get("name", "") path = resources.get("metadata", {}).get("path", "") self.notebook_path = os.path.join(path, name) super().__init__(**kwargs) def __call__(self, output): """Return the first available format in the priority. Produces a UserWarning if no compatible mimetype is found. `output` is dict with structure {mimetype-of-element: value-of-element} """ metadata = self.metadata.get(self.notebook_path, {}) widgets_state = ( metadata["widgets"][WIDGET_STATE_MIMETYPE]["state"] if metadata.get("widgets") is not None else {} ) for fmt in self.display_data_priority: if fmt in output: # If there is no widget state available, we skip this mimetype if ( fmt == WIDGET_VIEW_MIMETYPE and output[WIDGET_VIEW_MIMETYPE]["model_id"] not in widgets_state ): continue return [fmt] warn( f"Your element with mimetype(s) {output.keys()} is not able to be represented.", stacklevel=2, ) return [] nbconvert-7.16.4/nbconvert/nbconvertapp.py000077500000000000000000000603261461373220400207000ustar00rootroot00000000000000#!/usr/bin/env python """NbConvert is a utility for conversion of .ipynb files. Command-line interface for the NbConvert conversion utility. """ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. from __future__ import annotations import asyncio import glob import logging import os import sys import typing as t from textwrap import dedent, fill from jupyter_core.application import JupyterApp, base_aliases, base_flags from traitlets import Bool, DottedObjectName, Instance, List, Type, Unicode, default, observe from traitlets.config import Configurable, catch_config_error from traitlets.utils.importstring import import_item from nbconvert import __version__, exporters, postprocessors, preprocessors, writers from nbconvert.utils.text import indent from .exporters.base import get_export_names, get_exporter from .utils.base import NbConvertBase from .utils.exceptions import ConversionException from .utils.io import unicode_stdin_stream # ----------------------------------------------------------------------------- # Classes and functions # ----------------------------------------------------------------------------- class DottedOrNone(DottedObjectName): """A string holding a valid dotted object name in Python, such as A.b3._c Also allows for None type. """ default_value = "" def validate(self, obj, value): """Validate an input.""" if value is not None and len(value) > 0: return super().validate(obj, value) return value nbconvert_aliases = {} nbconvert_aliases.update(base_aliases) nbconvert_aliases.update( { "to": "NbConvertApp.export_format", "template": "TemplateExporter.template_name", "template-file": "TemplateExporter.template_file", "theme": "HTMLExporter.theme", "sanitize_html": "HTMLExporter.sanitize_html", "writer": "NbConvertApp.writer_class", "post": "NbConvertApp.postprocessor_class", "output": "NbConvertApp.output_base", "output-dir": "FilesWriter.build_directory", "reveal-prefix": "SlidesExporter.reveal_url_prefix", "nbformat": "NotebookExporter.nbformat_version", } ) nbconvert_flags = {} nbconvert_flags.update(base_flags) nbconvert_flags.update( { "execute": ( {"ExecutePreprocessor": {"enabled": True}}, "Execute the notebook prior to export.", ), "allow-errors": ( {"ExecutePreprocessor": {"allow_errors": True}}, ( "Continue notebook execution even if one of the cells throws " "an error and include the error message in the cell output " "(the default behaviour is to abort conversion). This flag " "is only relevant if '--execute' was specified, too." ), ), "stdin": ( { "NbConvertApp": { "from_stdin": True, } }, "read a single notebook file from stdin. Write the resulting notebook with default basename 'notebook.*'", ), "stdout": ( {"NbConvertApp": {"writer_class": "StdoutWriter"}}, "Write notebook output to stdout instead of files.", ), "inplace": ( { "NbConvertApp": { "use_output_suffix": False, "export_format": "notebook", }, "FilesWriter": {"build_directory": ""}, }, """Run nbconvert in place, overwriting the existing notebook (only relevant when converting to notebook format)""", ), "clear-output": ( { "NbConvertApp": { "use_output_suffix": False, "export_format": "notebook", }, "FilesWriter": {"build_directory": ""}, "ClearOutputPreprocessor": {"enabled": True}, }, """Clear output of current file and save in place, overwriting the existing notebook. """, ), "coalesce-streams": ( { "NbConvertApp": {"use_output_suffix": False, "export_format": "notebook"}, "FilesWriter": {"build_directory": ""}, "CoalesceStreamsPreprocessor": {"enabled": True}, }, """Coalesce consecutive stdout and stderr outputs into one stream (within each cell).""", ), "no-prompt": ( { "TemplateExporter": { "exclude_input_prompt": True, "exclude_output_prompt": True, } }, "Exclude input and output prompts from converted document.", ), "no-input": ( { "TemplateExporter": { "exclude_output_prompt": True, "exclude_input": True, "exclude_input_prompt": True, } }, """Exclude input cells and output prompts from converted document. This mode is ideal for generating code-free reports.""", ), "allow-chromium-download": ( { "WebPDFExporter": { "allow_chromium_download": True, } }, """Whether to allow downloading chromium if no suitable version is found on the system.""", ), "disable-chromium-sandbox": ( { "WebPDFExporter": { "disable_sandbox": True, } }, """Disable chromium security sandbox when converting to PDF..""", ), "show-input": ( { "TemplateExporter": { "exclude_input": False, } }, """Shows code input. This flag is only useful for dejavu users.""", ), "embed-images": ( { "HTMLExporter": { "embed_images": True, } }, """Embed the images as base64 dataurls in the output. This flag is only useful for the HTML/WebPDF/Slides exports.""", ), "sanitize-html": ( { "HTMLExporter": { "sanitize_html": True, } }, """Whether the HTML in Markdown cells and cell outputs should be sanitized..""", ), } ) class NbConvertApp(JupyterApp): """Application used to convert from notebook file type (``*.ipynb``)""" version = __version__ name = "jupyter-nbconvert" aliases = nbconvert_aliases flags = nbconvert_flags @default("log_level") def _log_level_default(self): return logging.INFO classes = List() # type:ignore[assignment] @default("classes") def _classes_default(self): classes: list[type[t.Any]] = [NbConvertBase] for pkg in (exporters, preprocessors, writers, postprocessors): for name in dir(pkg): cls = getattr(pkg, name) if isinstance(cls, type) and issubclass(cls, Configurable): classes.append(cls) return classes description = Unicode( # type:ignore[assignment] """This application is used to convert notebook files (*.ipynb) to various other formats. WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""" ) output_base = Unicode( "{notebook_name}", help="""Overwrite base name use for output files. Supports pattern replacements '{notebook_name}'. """, ).tag(config=True) use_output_suffix = Bool( True, help="""Whether to apply a suffix prior to the extension (only relevant when converting to notebook format). The suffix is determined by the exporter, and is usually '.nbconvert'.""", ).tag(config=True) output_files_dir = Unicode( "{notebook_name}_files", help="""Directory to copy extra files (figures) to. '{notebook_name}' in the string will be converted to notebook basename.""", ).tag(config=True) examples = Unicode( f""" The simplest way to use nbconvert is > jupyter nbconvert mynotebook.ipynb --to html Options include {get_export_names()}. > jupyter nbconvert --to latex mynotebook.ipynb Both HTML and LaTeX support multiple output templates. LaTeX includes 'base', 'article' and 'report'. HTML includes 'basic', 'lab' and 'classic'. You can specify the flavor of the format used. > jupyter nbconvert --to html --template lab mynotebook.ipynb You can also pipe the output to stdout, rather than a file > jupyter nbconvert mynotebook.ipynb --stdout PDF is generated via latex > jupyter nbconvert mynotebook.ipynb --to pdf You can get (and serve) a Reveal.js-powered slideshow > jupyter nbconvert myslides.ipynb --to slides --post serve Multiple notebooks can be given at the command line in a couple of different ways: > jupyter nbconvert notebook*.ipynb > jupyter nbconvert notebook1.ipynb notebook2.ipynb or you can specify the notebooks list in a config file, containing:: c.NbConvertApp.notebooks = ["my_notebook.ipynb"] > jupyter nbconvert --config mycfg.py """ ) # Writer specific variables writer = Instance( "nbconvert.writers.base.WriterBase", help="""Instance of the writer class used to write the results of the conversion.""", allow_none=True, ) writer_class = DottedObjectName( "FilesWriter", help="""Writer class used to write the results of the conversion""", ).tag(config=True) writer_aliases = { "fileswriter": "nbconvert.writers.files.FilesWriter", "debugwriter": "nbconvert.writers.debug.DebugWriter", "stdoutwriter": "nbconvert.writers.stdout.StdoutWriter", } writer_factory = Type(allow_none=True) @observe("writer_class") def _writer_class_changed(self, change): new = change["new"] if new.lower() in self.writer_aliases: new = self.writer_aliases[new.lower()] self.writer_factory = import_item(new) # Post-processor specific variables postprocessor = Instance( "nbconvert.postprocessors.base.PostProcessorBase", help="""Instance of the PostProcessor class used to write the results of the conversion.""", allow_none=True, ) postprocessor_class = DottedOrNone( help="""PostProcessor class used to write the results of the conversion""" ).tag(config=True) postprocessor_aliases = {"serve": "nbconvert.postprocessors.serve.ServePostProcessor"} postprocessor_factory = Type(None, allow_none=True) @observe("postprocessor_class") def _postprocessor_class_changed(self, change): new = change["new"] if new.lower() in self.postprocessor_aliases: new = self.postprocessor_aliases[new.lower()] if new: self.postprocessor_factory = import_item(new) export_format = Unicode( # type:ignore[call-overload] allow_none=False, help=f"""The export format to be used, either one of the built-in formats {get_export_names()} or a dotted object name that represents the import path for an ``Exporter`` class""", ).tag(config=True) notebooks = List( Unicode(), help="""List of notebooks to convert. Wildcards are supported. Filenames passed positionally will be added to the list. """, ).tag(config=True) from_stdin = Bool(False, help="read a single notebook from stdin.").tag(config=True) recursive_glob = Bool( False, help="set the 'recursive' option for glob for searching wildcards." ).tag(config=True) @catch_config_error def initialize(self, argv=None): """Initialize application, notebooks, writer, and postprocessor""" # See https://bugs.python.org/issue37373 :( if sys.version_info > (3, 8) and sys.platform.startswith("win"): asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) self.init_syspath() super().initialize(argv) if hasattr(self, "load_config_environ"): self.load_config_environ() self.init_notebooks() self.init_writer() self.init_postprocessor() def init_syspath(self): """Add the cwd to the sys.path ($PYTHONPATH)""" sys.path.insert(0, os.getcwd()) def init_notebooks(self): """Construct the list of notebooks. If notebooks are passed on the command-line, they override (rather than add) notebooks specified in config files. Glob each notebook to replace notebook patterns with filenames. """ # Specifying notebooks on the command-line overrides (rather than # adds) the notebook list patterns = self.extra_args if self.extra_args else self.notebooks # Use glob to replace all the notebook patterns with filenames. filenames = [] for pattern in patterns: # Use glob to find matching filenames. Allow the user to convert # notebooks without having to type the extension. globbed_files = glob.glob(pattern, recursive=self.recursive_glob) globbed_files.extend(glob.glob(pattern + ".ipynb", recursive=self.recursive_glob)) if not globbed_files: self.log.warning("pattern %r matched no files", pattern) for filename in globbed_files: if filename not in filenames: filenames.append(filename) self.notebooks = filenames def init_writer(self): """Initialize the writer (which is stateless)""" self._writer_class_changed({"new": self.writer_class}) if self.writer_factory: self.writer = self.writer_factory(parent=self) if hasattr(self.writer, "build_directory") and self.writer.build_directory != "": self.use_output_suffix = False def init_postprocessor(self): """Initialize the postprocessor (which is stateless)""" self._postprocessor_class_changed({"new": self.postprocessor_class}) if self.postprocessor_factory: self.postprocessor = self.postprocessor_factory(parent=self) def start(self): """Run start after initialization process has completed""" super().start() self.convert_notebooks() def _notebook_filename_to_name(self, notebook_filename): """ Returns the notebook name from the notebook filename by applying `output_base` pattern and stripping extension """ basename = os.path.basename(notebook_filename) notebook_name = basename[: basename.rfind(".")] notebook_name = self.output_base.format(notebook_name=notebook_name) return notebook_name # noqa: RET504 def init_single_notebook_resources(self, notebook_filename): """Step 1: Initialize resources This initializes the resources dictionary for a single notebook. Returns ------- dict resources dictionary for a single notebook that MUST include the following keys: - config_dir: the location of the Jupyter config directory - unique_key: the notebook name - output_files_dir: a directory where output files (not including the notebook itself) should be saved """ notebook_name = self._notebook_filename_to_name(notebook_filename) self.log.debug("Notebook name is '%s'", notebook_name) # first initialize the resources we want to use resources = {} resources["config_dir"] = self.config_dir resources["unique_key"] = notebook_name output_files_dir = self.output_files_dir.format(notebook_name=notebook_name) resources["output_files_dir"] = output_files_dir return resources def export_single_notebook(self, notebook_filename, resources, input_buffer=None): """Step 2: Export the notebook Exports the notebook to a particular format according to the specified exporter. This function returns the output and (possibly modified) resources from the exporter. Parameters ---------- notebook_filename : str name of notebook file. resources : dict input_buffer : readable file-like object returning unicode. if not None, notebook_filename is ignored Returns ------- output dict resources (possibly modified) """ try: if input_buffer is not None: output, resources = self.exporter.from_file(input_buffer, resources=resources) else: output, resources = self.exporter.from_filename( notebook_filename, resources=resources ) except ConversionException: self.log.error("Error while converting '%s'", notebook_filename, exc_info=True) # noqa: G201 self.exit(1) return output, resources def write_single_notebook(self, output, resources): """Step 3: Write the notebook to file This writes output from the exporter to file using the specified writer. It returns the results from the writer. Parameters ---------- output : resources : dict resources for a single notebook including name, config directory and directory to save output Returns ------- file results from the specified writer output of exporter """ if "unique_key" not in resources: msg = "unique_key MUST be specified in the resources, but it is not" raise KeyError(msg) notebook_name = resources["unique_key"] if self.use_output_suffix and self.output_base == "{notebook_name}": notebook_name += resources.get("output_suffix", "") if not self.writer: msg = "No writer object defined!" raise ValueError(msg) return self.writer.write(output, resources, notebook_name=notebook_name) def postprocess_single_notebook(self, write_results): """Step 4: Post-process the written file Only used if a postprocessor has been specified. After the converted notebook is written to a file in Step 3, this post-processes the notebook. """ # Post-process if post processor has been defined. if hasattr(self, "postprocessor") and self.postprocessor: self.postprocessor(write_results) def convert_single_notebook(self, notebook_filename, input_buffer=None): """Convert a single notebook. Performs the following steps: 1. Initialize notebook resources 2. Export the notebook to a particular format 3. Write the exported notebook to file 4. (Maybe) postprocess the written file Parameters ---------- notebook_filename : str input_buffer : If input_buffer is not None, conversion is done and the buffer is used as source into a file basenamed by the notebook_filename argument. """ if input_buffer is None: self.log.info("Converting notebook %s to %s", notebook_filename, self.export_format) else: self.log.info("Converting notebook into %s", self.export_format) resources = self.init_single_notebook_resources(notebook_filename) output, resources = self.export_single_notebook( notebook_filename, resources, input_buffer=input_buffer ) write_results = self.write_single_notebook(output, resources) self.postprocess_single_notebook(write_results) def convert_notebooks(self): """Convert the notebooks in the self.notebooks traitlet""" # no notebooks to convert! if len(self.notebooks) == 0 and not self.from_stdin: self.print_help() sys.exit(-1) if not self.export_format: msg = ( "Please specify an output format with '--to '." f"\nThe following formats are available: {get_export_names()}" ) raise ValueError(msg) # initialize the exporter cls = get_exporter(self.export_format) self.exporter = cls(config=self.config) # strip duplicate extension from output_base, to avoid Basename.ext.ext if getattr(self.exporter, "file_extension", False): base, ext = os.path.splitext(self.output_base) if ext == self.exporter.file_extension: self.output_base = base # convert each notebook if not self.from_stdin: for notebook_filename in self.notebooks: self.convert_single_notebook(notebook_filename) else: input_buffer = unicode_stdin_stream() # default name when conversion from stdin self.convert_single_notebook("notebook.ipynb", input_buffer=input_buffer) input_buffer.close() def document_flag_help(self): """ Return a string containing descriptions of all the flags. """ flags = "The following flags are defined:\n\n" for flag, (cfg, fhelp) in self.flags.items(): flags += f"{flag}\n" flags += indent(fill(fhelp, 80)) + "\n\n" flags += indent(fill("Long Form: " + str(cfg), 80)) + "\n\n" return flags def document_alias_help(self): """Return a string containing all of the aliases""" aliases = "The following aliases are defined:\n\n" for alias, longname in self.aliases.items(): aliases += f"\t**{alias}** ({longname})\n\n" return aliases def document_config_options(self): """ Provides a much improves version of the configuration documentation by breaking the configuration options into app, exporter, writer, preprocessor, postprocessor, and other sections. """ categories = { category: [c for c in self._classes_inc_parents() if category in c.__name__.lower()] for category in ["app", "exporter", "writer", "preprocessor", "postprocessor"] } accounted_for = {c for category in categories.values() for c in category} categories["other"] = [c for c in self._classes_inc_parents() if c not in accounted_for] header = dedent( """ {section} Options ----------------------- """ ) sections = "" for category in categories: sections += header.format(section=category.title()) if category in ["exporter", "preprocessor", "writer"]: sections += f".. image:: _static/{category}_inheritance.png\n\n" sections += "\n".join(c.class_config_rst_doc() for c in categories[category]) return sections.replace(" : ", r" \: ") class DejavuApp(NbConvertApp): """A deja vu app.""" def initialize(self, argv=None): """Initialize the app.""" self.config.TemplateExporter.exclude_input = True self.config.TemplateExporter.exclude_output_prompt = True self.config.TemplateExporter.exclude_input_prompt = True self.config.ExecutePreprocessor.enabled = True self.config.WebPDFExporter.paginate = False self.config.QtPDFExporter.paginate = False super().initialize(argv) if hasattr(self, "load_config_environ"): self.load_config_environ() @default("export_format") def _default_export_format(self): return "html" # ----------------------------------------------------------------------------- # Main entry point # ----------------------------------------------------------------------------- main = launch_new_instance = NbConvertApp.launch_instance dejavu_main = DejavuApp.launch_instance nbconvert-7.16.4/nbconvert/postprocessors/000077500000000000000000000000001461373220400207235ustar00rootroot00000000000000nbconvert-7.16.4/nbconvert/postprocessors/__init__.py000066400000000000000000000004031461373220400230310ustar00rootroot00000000000000from .base import PostProcessorBase # protect against unavailable tornado try: from .serve import ServePostProcessor except ImportError: ServePostProcessor = None # type:ignore[misc,assignment] __all__ = ["PostProcessorBase", "ServePostProcessor"] nbconvert-7.16.4/nbconvert/postprocessors/base.py000066400000000000000000000022021461373220400222030ustar00rootroot00000000000000""" Basic post processor """ # ----------------------------------------------------------------------------- # Copyright (c) 2013, the IPython Development Team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file COPYING.txt, distributed with this software. # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # Imports # ----------------------------------------------------------------------------- from nbconvert.utils.base import NbConvertBase # ----------------------------------------------------------------------------- # Classes # ----------------------------------------------------------------------------- class PostProcessorBase(NbConvertBase): """The base class for post processors.""" def __call__(self, input_): """ See def postprocess() ... """ self.postprocess(input_) def postprocess(self, input_): """ Post-process output from a writer. """ msg = "postprocess" raise NotImplementedError(msg) nbconvert-7.16.4/nbconvert/postprocessors/serve.py000066400000000000000000000104161461373220400224230ustar00rootroot00000000000000"""PostProcessor for serving reveal.js HTML slideshows.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. from __future__ import annotations import os import threading import typing as t import webbrowser from tornado import gen, httpserver, ioloop, log, web from tornado.httpclient import AsyncHTTPClient from traitlets import Bool, Int, Unicode from .base import PostProcessorBase class ProxyHandler(web.RequestHandler): """handler the proxies requests from a local prefix to a CDN""" @gen.coroutine def get(self, prefix, url): """proxy a request to a CDN""" proxy_url = "/".join([self.settings["cdn"], url]) client = self.settings["client"] response = yield client.fetch(proxy_url) for header in ["Content-Type", "Cache-Control", "Date", "Last-Modified", "Expires"]: if header in response.headers: self.set_header(header, response.headers[header]) self.finish(response.body) class ServePostProcessor(PostProcessorBase): """Post processor designed to serve files Proxies reveal.js requests to a CDN if no local reveal.js is present """ open_in_browser = Bool(True, help="""Should the browser be opened automatically?""").tag( config=True ) browser = Unicode( "", help="""Specify what browser should be used to open slides. See https://docs.python.org/3/library/webbrowser.html#webbrowser.register to see how keys are mapped to browser executables. If not specified, the default browser will be determined by the `webbrowser` standard library module, which allows setting of the BROWSER environment variable to override it. """, ).tag(config=True) reveal_cdn = Unicode( "https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.5.0", help="""URL for reveal.js CDN.""" ).tag(config=True) reveal_prefix = Unicode("reveal.js", help="URL prefix for reveal.js").tag(config=True) ip = Unicode("127.0.0.1", help="The IP address to listen on.").tag(config=True) port = Int(8000, help="port for the server to listen on.").tag(config=True) def postprocess(self, input): """Serve the build directory with a webserver.""" dirname, filename = os.path.split(input) handlers: list[tuple[t.Any, ...]] = [ (r"/(.+)", web.StaticFileHandler, {"path": dirname}), (r"/", web.RedirectHandler, {"url": "/%s" % filename}), ] if "://" in self.reveal_prefix or self.reveal_prefix.startswith("//"): # reveal specifically from CDN, nothing to do pass elif os.path.isdir(os.path.join(dirname, self.reveal_prefix)): # reveal prefix exists self.log.info("Serving local %s", self.reveal_prefix) else: self.log.info("Redirecting %s requests to %s", self.reveal_prefix, self.reveal_cdn) handlers.insert(0, (r"/(%s)/(.*)" % self.reveal_prefix, ProxyHandler)) app = web.Application( handlers, # type:ignore[arg-type] cdn=self.reveal_cdn, client=AsyncHTTPClient(), ) # hook up tornado logging to our logger log.app_log = self.log http_server = httpserver.HTTPServer(app) http_server.listen(self.port, address=self.ip) url = "http://%s:%i/%s" % (self.ip, self.port, filename) print("Serving your slides at %s" % url) print("Use Control-C to stop this server") if self.open_in_browser: try: browser = webbrowser.get(self.browser or None) b = lambda: browser.open(url, new=2) # noqa: E731 threading.Thread(target=b).start() except webbrowser.Error as e: self.log.warning("No web browser found: %s.", e) browser = None try: ioloop.IOLoop.instance().start() except KeyboardInterrupt: print("\nInterrupted") def main(path): """allow running this module to serve the slides""" server = ServePostProcessor() server(path) if __name__ == "__main__": import sys main(sys.argv[1]) nbconvert-7.16.4/nbconvert/preprocessors/000077500000000000000000000000001461373220400205245ustar00rootroot00000000000000nbconvert-7.16.4/nbconvert/preprocessors/__init__.py000066400000000000000000000023771461373220400226460ustar00rootroot00000000000000# Class base Preprocessors # Backwards compatibility for imported name from nbclient.exceptions import CellExecutionError from .base import Preprocessor from .clearmetadata import ClearMetadataPreprocessor from .clearoutput import ClearOutputPreprocessor from .coalescestreams import CoalesceStreamsPreprocessor from .convertfigures import ConvertFiguresPreprocessor from .csshtmlheader import CSSHTMLHeaderPreprocessor from .execute import ExecutePreprocessor from .extractattachments import ExtractAttachmentsPreprocessor from .extractoutput import ExtractOutputPreprocessor from .highlightmagics import HighlightMagicsPreprocessor from .latex import LatexPreprocessor from .regexremove import RegexRemovePreprocessor from .svg2pdf import SVG2PDFPreprocessor from .tagremove import TagRemovePreprocessor __all__ = [ "CellExecutionError", "Preprocessor", "ClearMetadataPreprocessor", "ClearOutputPreprocessor", "CoalesceStreamsPreprocessor", "ConvertFiguresPreprocessor", "CSSHTMLHeaderPreprocessor", "ExecutePreprocessor", "ExtractAttachmentsPreprocessor", "ExtractOutputPreprocessor", "HighlightMagicsPreprocessor", "LatexPreprocessor", "RegexRemovePreprocessor", "SVG2PDFPreprocessor", "TagRemovePreprocessor", ] nbconvert-7.16.4/nbconvert/preprocessors/base.py000066400000000000000000000053511461373220400220140ustar00rootroot00000000000000"""Base class for preprocessors""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. from traitlets import Bool from nbconvert.utils.base import NbConvertBase class Preprocessor(NbConvertBase): """A configurable preprocessor Inherit from this class if you wish to have configurability for your preprocessor. Any configurable traitlets this class exposed will be configurable in profiles using c.SubClassName.attribute = value You can overwrite `preprocess_cell()` to apply a transformation independently on each cell or `preprocess()` if you prefer your own logic. See corresponding docstring for information. Disabled by default and can be enabled via the config by 'c.YourPreprocessorName.enabled = True' """ enabled = Bool(False).tag(config=True) def __init__(self, **kw): """ Public constructor Parameters ---------- config : Config Configuration file structure `**kw` Additional keyword arguments passed to parent """ super().__init__(**kw) def __call__(self, nb, resources): """Apply the preprocessor.""" if self.enabled: self.log.debug("Applying preprocessor: %s", self.__class__.__name__) return self.preprocess(nb, resources) return nb, resources def preprocess(self, nb, resources): """ Preprocessing to apply on each notebook. Must return modified nb, resources. If you wish to apply your preprocessing to each cell, you might want to override preprocess_cell method instead. Parameters ---------- nb : NotebookNode Notebook being converted resources : dictionary Additional resources used in the conversion process. Allows preprocessors to pass variables into the Jinja engine. """ for index, cell in enumerate(nb.cells): nb.cells[index], resources = self.preprocess_cell(cell, resources, index) return nb, resources def preprocess_cell(self, cell, resources, index): """ Override if you want to apply some preprocessing to each cell. Must return modified cell and resource dictionary. Parameters ---------- cell : NotebookNode cell Notebook cell being processed resources : dictionary Additional resources used in the conversion process. Allows preprocessors to pass variables into the Jinja engine. index : int Index of the cell being processed """ msg = "should be implemented by subclass" raise NotImplementedError(msg) nbconvert-7.16.4/nbconvert/preprocessors/clearmetadata.py000066400000000000000000000072641461373220400236760ustar00rootroot00000000000000"""Module containing a preprocessor that removes metadata from code cells""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. from traitlets import Bool, Set from .base import Preprocessor class ClearMetadataPreprocessor(Preprocessor): """ Removes all the metadata from all code cells in a notebook. """ clear_cell_metadata = Bool( True, help=("Flag to choose if cell metadata is to be cleared in addition to notebook metadata."), ).tag(config=True) clear_notebook_metadata = Bool( True, help=("Flag to choose if notebook metadata is to be cleared in addition to cell metadata."), ).tag(config=True) preserve_nb_metadata_mask = Set( [("language_info", "name")], help=( "Indicates the key paths to preserve when deleting metadata " "across both cells and notebook metadata fields. Tuples of " "keys can be passed to preserved specific nested values" ), ).tag(config=True) preserve_cell_metadata_mask = Set( help=( "Indicates the key paths to preserve when deleting metadata " "across both cells and notebook metadata fields. Tuples of " "keys can be passed to preserved specific nested values" ) ).tag(config=True) def current_key(self, mask_key): """Get the current key for a mask key.""" if isinstance(mask_key, str): return mask_key if len(mask_key) == 0: # Safeguard return None return mask_key[0] def current_mask(self, mask): """Get the current mask for a mask.""" return {self.current_key(k) for k in mask if self.current_key(k) is not None} def nested_masks(self, mask): """Get the nested masks for a mask.""" return { self.current_key(k[0]): k[1:] for k in mask if k and not isinstance(k, str) and len(k) > 1 } def nested_filter(self, items, mask): """Get the nested filter for items given a mask.""" keep_current = self.current_mask(mask) keep_nested_lookup = self.nested_masks(mask) for k, v in items: keep_nested = keep_nested_lookup.get(k) if k in keep_current: if keep_nested is not None: if isinstance(v, dict): yield k, dict(self.nested_filter(v.items(), keep_nested)) else: yield k, v def preprocess_cell(self, cell, resources, cell_index): """ All the code cells are returned with an empty metadata field. """ if self.clear_cell_metadata and cell.cell_type == "code": # noqa: SIM102 # Remove metadata if "metadata" in cell: cell.metadata = dict( self.nested_filter(cell.metadata.items(), self.preserve_cell_metadata_mask) ) return cell, resources def preprocess(self, nb, resources): """ Preprocessing to apply on each notebook. Must return modified nb, resources. Parameters ---------- nb : NotebookNode Notebook being converted resources : dictionary Additional resources used in the conversion process. Allows preprocessors to pass variables into the Jinja engine. """ nb, resources = super().preprocess(nb, resources) if self.clear_notebook_metadata and "metadata" in nb: nb.metadata = dict( self.nested_filter(nb.metadata.items(), self.preserve_nb_metadata_mask) ) return nb, resources nbconvert-7.16.4/nbconvert/preprocessors/clearoutput.py000066400000000000000000000016421461373220400234500ustar00rootroot00000000000000"""Module containing a preprocessor that removes the outputs from code cells""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. from traitlets import Set from .base import Preprocessor class ClearOutputPreprocessor(Preprocessor): """ Removes the output from all code cells in a notebook. """ remove_metadata_fields = Set({"collapsed", "scrolled"}).tag(config=True) def preprocess_cell(self, cell, resources, cell_index): """ Apply a transformation on each cell. See base.py for details. """ if cell.cell_type == "code": cell.outputs = [] cell.execution_count = None # Remove metadata associated with output if "metadata" in cell: for field in self.remove_metadata_fields: cell.metadata.pop(field, None) return cell, resources nbconvert-7.16.4/nbconvert/preprocessors/coalescestreams.py000066400000000000000000000025511461373220400242560ustar00rootroot00000000000000"""Preprocessor for merging consecutive stream outputs for easier handling.""" import re # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. from nbconvert.preprocessors import Preprocessor CR_PAT = re.compile(r".*\r(?=[^\n])") class CoalesceStreamsPreprocessor(Preprocessor): """ Merge consecutive sequences of stream output into single stream to prevent extra newlines inserted at flush calls """ def preprocess_cell(self, cell, resources, cell_index): """ Apply a transformation on each cell. See base.py for details. """ outputs = cell.get("outputs", []) if not outputs: return cell, resources last = outputs[0] new_outputs = [last] for output in outputs[1:]: if ( output.output_type == "stream" and last.output_type == "stream" and last.name == output.name ): last.text += output.text else: new_outputs.append(output) last = output # process \r characters for output in new_outputs: if output.output_type == "stream" and "\r" in output.text: output.text = CR_PAT.sub("", output.text) cell.outputs = new_outputs return cell, resources nbconvert-7.16.4/nbconvert/preprocessors/convertfigures.py000066400000000000000000000030031461373220400241370ustar00rootroot00000000000000"""Module containing a preprocessor that converts outputs in the notebook from one format to another. Converts all of the outputs in a notebook from one format to another. """ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. from traitlets import Unicode from .base import Preprocessor class ConvertFiguresPreprocessor(Preprocessor): """ Converts all of the outputs in a notebook from one format to another. """ from_format = Unicode(help="Format the converter accepts").tag(config=True) to_format = Unicode(help="Format the converter writes").tag(config=True) def __init__(self, **kw): """ Public constructor """ super().__init__(**kw) def convert_figure(self, data_format, data): """Convert the figure.""" raise NotImplementedError() def preprocess_cell(self, cell, resources, cell_index): """ Apply a transformation on each cell, See base.py """ # Loop through all of the datatypes of the outputs in the cell. for output in cell.get("outputs", []): if ( output.output_type in {"execute_result", "display_data"} and self.from_format in output.data and self.to_format not in output.data ): output.data[self.to_format] = self.convert_figure( self.from_format, output.data[self.from_format] ) return cell, resources nbconvert-7.16.4/nbconvert/preprocessors/csshtmlheader.py000066400000000000000000000063531461373220400237330ustar00rootroot00000000000000"""Module that pre-processes the notebook for export to HTML.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import hashlib import os from jupyterlab_pygments import JupyterStyle # type:ignore[import-untyped] from pygments.style import Style from traitlets import Type, Unicode, Union from .base import Preprocessor try: from notebook import DEFAULT_STATIC_FILES_PATH # type:ignore[import-not-found] except ImportError: DEFAULT_STATIC_FILES_PATH = None class CSSHTMLHeaderPreprocessor(Preprocessor): """ Preprocessor used to pre-process notebook for HTML output. Adds IPython notebook front-end CSS and Pygments CSS to HTML output. """ highlight_class = Unicode(".highlight", help="CSS highlight class identifier").tag(config=True) style = Union( [Unicode("default"), Type(klass=Style)], help="Name of the pygments style to use", default_value=JupyterStyle, ).tag(config=True) def __init__(self, *pargs, **kwargs): """Initialize the preprocessor.""" Preprocessor.__init__(self, *pargs, **kwargs) self._default_css_hash = None def preprocess(self, nb, resources): """Fetch and add CSS to the resource dictionary Fetch CSS from IPython and Pygments to add at the beginning of the html files. Add this css in resources in the "inlining.css" key Parameters ---------- nb : NotebookNode Notebook being converted resources : dictionary Additional resources used in the conversion process. Allows preprocessors to pass variables into the Jinja engine. """ resources["inlining"] = {} resources["inlining"]["css"] = self._generate_header(resources) return nb, resources def _generate_header(self, resources): """ Fills self.header with lines of CSS extracted from IPython and Pygments. """ from pygments.formatters import HtmlFormatter header = [] formatter = HtmlFormatter(style=self.style) pygments_css = formatter.get_style_defs(self.highlight_class) header.append(pygments_css) # Load the user's custom CSS and IPython's default custom CSS. If they # differ, assume the user has made modifications to his/her custom CSS # and that we should inline it in the nbconvert output. config_dir = resources["config_dir"] custom_css_filename = os.path.join(config_dir, "custom", "custom.css") if os.path.isfile(custom_css_filename): if DEFAULT_STATIC_FILES_PATH and self._default_css_hash is None: self._default_css_hash = self._hash( os.path.join(DEFAULT_STATIC_FILES_PATH, "custom", "custom.css") ) if self._hash(custom_css_filename) != self._default_css_hash: with open(custom_css_filename, encoding="utf-8") as f: header.append(f.read()) return header def _hash(self, filename): """Compute the hash of a file.""" md5 = hashlib.md5() # noqa: S324 with open(filename, "rb") as f: md5.update(f.read()) return md5.digest() nbconvert-7.16.4/nbconvert/preprocessors/execute.py000066400000000000000000000107741461373220400225510ustar00rootroot00000000000000# Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. """Module containing a preprocessor that executes the code cells and updates outputs""" from __future__ import annotations import typing as t from jupyter_client.manager import KernelManager from nbclient.client import NotebookClient from nbclient.client import execute as _execute # Backwards compatibility for imported name from nbclient.exceptions import CellExecutionError # noqa: F401 from nbformat import NotebookNode from .base import Preprocessor def executenb(*args, **kwargs): """DEPRECATED.""" from warnings import warn warn( "The 'nbconvert.preprocessors.execute.executenb' function was moved to nbclient.execute. " "We recommend importing that library directly.", FutureWarning, stacklevel=2, ) return _execute(*args, **kwargs) # We inherit from both classes to allow for traitlets to resolve as they did pre-6.0. # This unfortunately makes for some ugliness around initialization as NotebookClient # assumes it's a constructed class with a nb object that we have to hack around. class ExecutePreprocessor(Preprocessor, NotebookClient): """ Executes all the cells in a notebook """ def __init__(self, **kw): """Initialize the preprocessor.""" nb = kw.get("nb") if nb is None: nb = NotebookNode() Preprocessor.__init__(self, nb=nb, **kw) NotebookClient.__init__(self, nb, **kw) def _check_assign_resources(self, resources): if resources or not hasattr(self, "resources"): self.resources = resources def preprocess( self, nb: NotebookNode, resources: t.Any = None, km: KernelManager | None = None ) -> tuple[NotebookNode, dict[str, t.Any]]: """ Preprocess notebook executing each code cell. The input argument *nb* is modified in-place. Note that this function recalls NotebookClient.__init__, which may look wrong. However since the preprocess call acts line an init on execution state it's expected. Therefore, we need to capture it here again to properly reset because traitlet assignments are not passed. There is a risk if traitlets apply any side effects for dual init. The risk should be manageable, and this approach minimizes side-effects relative to other alternatives. One alternative but rejected implementation would be to copy the client's init internals which has already gotten out of sync with nbclient 0.5 release before nbconvert 6.0 released. Parameters ---------- nb : NotebookNode Notebook being executed. resources : dictionary (optional) Additional resources used in the conversion process. For example, passing ``{'metadata': {'path': run_path}}`` sets the execution path to ``run_path``. km: KernelManager (optional) Optional kernel manager. If none is provided, a kernel manager will be created. Returns ------- nb : NotebookNode The executed notebook. resources : dictionary Additional resources used in the conversion process. """ NotebookClient.__init__(self, nb, km) self.reset_execution_trackers() self._check_assign_resources(resources) with self.setup_kernel(): assert self.kc info_msg = self.wait_for_reply(self.kc.kernel_info()) assert info_msg self.nb.metadata["language_info"] = info_msg["content"]["language_info"] for index, cell in enumerate(self.nb.cells): self.preprocess_cell(cell, resources, index) self.set_widgets_metadata() return self.nb, self.resources def preprocess_cell(self, cell, resources, index): """ Override if you want to apply some preprocessing to each cell. Must return modified cell and resource dictionary. Parameters ---------- cell : NotebookNode cell Notebook cell being processed resources : dictionary Additional resources used in the conversion process. Allows preprocessors to pass variables into the Jinja engine. index : int Index of the cell being processed """ self._check_assign_resources(resources) cell = self.execute_cell(cell, index, store_history=True) return cell, self.resources nbconvert-7.16.4/nbconvert/preprocessors/extractattachments.py000066400000000000000000000077601461373220400250160ustar00rootroot00000000000000""" Module that extracts attachments from notebooks into their own files """ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import os from base64 import b64decode from traitlets import Bool, Unicode from .base import Preprocessor class ExtractAttachmentsPreprocessor(Preprocessor): """ Extracts attachments from all (markdown and raw) cells in a notebook. The extracted attachments are stored in a directory ('attachments' by default). https://nbformat.readthedocs.io/en/latest/format_description.html#cell-attachments """ attachments_directory_template = Unicode( "{notebook_name}_attachments", help="Directory to place attachments if use_separate_dir is True", ).tag(config=True) use_separate_dir = Bool( False, help="Whether to use output_files_dir (which ExtractOutput also uses) or " "create a separate directory for attachments", ).tag(config=True) def __init__(self, **kw): """ Public constructor """ super().__init__(**kw) # directory path, self.path_name = "" # will be set in self.preprocess, needs resources # Where extracted attachments are stored in resources self.resources_item_key = ( "attachments" # Here as a default, in case someone doesn't want to call preprocess ) # Add condition and configurability here def preprocess(self, nb, resources): """ Determine some settings and apply preprocessor to notebook """ if self.use_separate_dir: self.path_name = self.attachments_directory_template.format( notebook_name=resources["unique_key"] ) # Initialize resources for attachments resources["attachment_files_dir"] = self.path_name resources["attachments"] = {} self.resources_item_key = "attachments" else: # Use same resources as ExtractOutput self.path_name = resources["output_files_dir"] self.resources_item_key = "outputs" # Make sure key exists if not isinstance(resources[self.resources_item_key], dict): resources[self.resources_item_key] = {} nb, resources = super().preprocess(nb, resources) return nb, resources def preprocess_cell(self, cell, resources, index): """ Extract attachments to individual files and change references to them. E.g. '![image.png](attachment:021fdd80.png)' becomes '![image.png]({path_name}/021fdd80.png)' Assumes self.path_name and self.resources_item_key is set properly (usually in preprocess). """ if "attachments" in cell: for fname in cell.attachments: self.log.debug("Encountered attachment %s", fname) # Add file for writer # Right now I don't know of a situation where there would be multiple # mime types under same filename, and I can't index into it without the mimetype. # So I only read the first one. for mimetype in cell.attachments[fname]: # convert to bytes and decode data = cell.attachments[fname][mimetype].encode("utf-8") decoded = b64decode(data) break # FilesWriter wants path to be in attachment filename here new_filename = os.path.join(self.path_name, fname) resources[self.resources_item_key][new_filename] = decoded # Edit the reference to the attachment # os.path.join on windows uses "\\" separator, # but files like markdown still want "/" if os.path.sep != "/": new_filename = new_filename.replace(os.path.sep, "/") cell.source = cell.source.replace("attachment:" + fname, new_filename) return cell, resources nbconvert-7.16.4/nbconvert/preprocessors/extractoutput.py000066400000000000000000000144551461373220400240420ustar00rootroot00000000000000"""A preprocessor that extracts all of the outputs from the notebook file. The extracted outputs are returned in the 'resources' dictionary. """ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. import json import os import sys from binascii import a2b_base64 from mimetypes import guess_extension from textwrap import dedent from traitlets import Set, Unicode from .base import Preprocessor def guess_extension_without_jpe(mimetype): """ This function fixes a problem with '.jpe' extensions of jpeg images which are then not recognised by latex. For any other case, the function works in the same way as mimetypes.guess_extension """ ext = guess_extension(mimetype) if ext == ".jpe": ext = ".jpeg" return ext def platform_utf_8_encode(data): """Encode data based on platform.""" if isinstance(data, str): if sys.platform == "win32": data = data.replace("\n", "\r\n") data = data.encode("utf-8") return data class ExtractOutputPreprocessor(Preprocessor): """ Extracts all of the outputs from the notebook file. The extracted outputs are returned in the 'resources' dictionary. """ output_filename_template = Unicode("{unique_key}_{cell_index}_{index}{extension}").tag( config=True ) extract_output_types = Set({"image/png", "image/jpeg", "image/svg+xml", "application/pdf"}).tag( config=True ) def preprocess_cell(self, cell, resources, cell_index): """ Apply a transformation on each cell, Parameters ---------- cell : NotebookNode cell Notebook cell being processed resources : dictionary Additional resources used in the conversion process. Allows preprocessors to pass variables into the Jinja engine. cell_index : int Index of the cell being processed (see base.py) """ # Get the unique key from the resource dict if it exists. If it does not # exist, use 'output' as the default. Also, get files directory if it # has been specified unique_key = resources.get("unique_key", "output") output_files_dir = resources.get("output_files_dir", None) # Make sure outputs key exists if not isinstance(resources["outputs"], dict): resources["outputs"] = {} # Loop through all of the outputs in the cell for index, out in enumerate(cell.get("outputs", [])): if out.output_type not in {"display_data", "execute_result"}: continue if "text/html" in out.data: out["data"]["text/html"] = dedent(out["data"]["text/html"]) # Get the output in data formats that the template needs extracted for mime_type in self.extract_output_types: if mime_type in out.data: data = out.data[mime_type] # Binary files are base64-encoded, SVG is already XML if mime_type in {"image/png", "image/jpeg", "application/pdf"}: # data is b64-encoded as text (str, unicode), # we want the original bytes data = a2b_base64(data) elif mime_type == "application/json" or not isinstance(data, str): # Data is either JSON-like and was parsed into a Python # object according to the spec, or data is for sure # JSON. In the latter case we want to go extra sure that # we enclose a scalar string value into extra quotes by # serializing it properly. if isinstance(data, bytes): # We need to guess the encoding in this # instance. Some modules that return raw data like # svg can leave the data in byte form instead of str data = data.decode("utf-8") data = platform_utf_8_encode(json.dumps(data)) else: # All other text_type data will fall into this path data = platform_utf_8_encode(data) ext = guess_extension_without_jpe(mime_type) if ext is None: ext = "." + mime_type.rsplit("/")[-1] if out.metadata.get("filename", ""): filename = out.metadata["filename"] if not filename.endswith(ext): filename += ext else: filename = self.output_filename_template.format( unique_key=unique_key, cell_index=cell_index, index=index, extension=ext ) # On the cell, make the figure available via # cell.outputs[i].metadata.filenames['mime/type'] # where # cell.outputs[i].data['mime/type'] contains the data if output_files_dir is not None: filename = os.path.join(output_files_dir, filename) out.metadata.setdefault("filenames", {}) out.metadata["filenames"][mime_type] = filename if filename in resources["outputs"]: msg = ( "Your outputs have filename metadata associated " "with them. Nbconvert saves these outputs to " "external files using this filename metadata. " "Filenames need to be unique across the notebook, " f"or images will be overwritten. The filename {filename} is " "associated with more than one output. The second " "output associated with this filename is in cell " f"{cell_index}." ) raise ValueError(msg) # In the resources, make the figure available via # resources['outputs']['filename'] = data resources["outputs"][filename] = data return cell, resources nbconvert-7.16.4/nbconvert/preprocessors/highlightmagics.py000066400000000000000000000061751461373220400242420ustar00rootroot00000000000000"""This preprocessor detect cells using a different language through magic extensions such as `%%R` or `%%octave`. Cell's metadata is marked so that the appropriate highlighter can be used in the `highlight` filter. """ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import re from traitlets import Dict from .base import Preprocessor class HighlightMagicsPreprocessor(Preprocessor): """ Detects and tags code cells that use a different languages than Python. """ # list of magic language extensions and their associated pygment lexers default_languages = Dict( { "%%R": "r", "%%bash": "bash", "%%cython": "cython", "%%javascript": "javascript", "%%julia": "julia", "%%latex": "latex", "%%octave": "octave", "%%perl": "perl", "%%ruby": "ruby", "%%sh": "sh", "%%sql": "sql", } ) # user defined language extensions languages = Dict( help=( "Syntax highlighting for magic's extension languages. " "Each item associates a language magic extension such as %%R, " "with a pygments lexer such as r." ) ).tag(config=True) def __init__(self, config=None, **kw): """Public constructor""" super().__init__(config=config, **kw) # Update the default languages dict with the user configured ones self.default_languages.update(self.languages) # build a regular expression to catch language extensions and choose # an adequate pygments lexer any_language = "|".join(self.default_languages.keys()) self.re_magic_language = re.compile(rf"^\s*({any_language})\s+") def which_magic_language(self, source): """ When a cell uses another language through a magic extension, the other language is returned. If no language magic is detected, this function returns None. Parameters ---------- source: str Source code of the cell to highlight """ m = self.re_magic_language.match(source) if m: # By construction of the re, the matched language must be in the # languages dictionary return self.default_languages[m.group(1)] return None def preprocess_cell(self, cell, resources, cell_index): """ Tags cells using a magic extension language Parameters ---------- cell : NotebookNode cell Notebook cell being processed resources : dictionary Additional resources used in the conversion process. Allows preprocessors to pass variables into the Jinja engine. cell_index : int Index of the cell being processed (see base.py) """ # Only tag code cells if cell.cell_type == "code": magic_language = self.which_magic_language(cell.source) if magic_language: cell["metadata"]["magics_language"] = magic_language return cell, resources nbconvert-7.16.4/nbconvert/preprocessors/latex.py000066400000000000000000000052571461373220400222240ustar00rootroot00000000000000"""Module that allows latex output notebooks to be conditioned before they are converted. """ # ----------------------------------------------------------------------------- # Copyright (c) 2013, the IPython Development Team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file COPYING.txt, distributed with this software. # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # Imports # ----------------------------------------------------------------------------- from traitlets import List, Unicode from .base import Preprocessor # ----------------------------------------------------------------------------- # Classes # ----------------------------------------------------------------------------- class LatexPreprocessor(Preprocessor): """Preprocessor for latex destined documents. Populates the ``latex`` key in the resources dict, adding definitions for pygments highlight styles. Sets the authors, date and title of the latex document, overriding the values given in the metadata. """ date = Unicode( None, help=("Date of the LaTeX document"), allow_none=True, ).tag(config=True) title = Unicode(None, help=("Title of the LaTeX document"), allow_none=True).tag(config=True) author_names = List( Unicode(), default_value=None, help=("Author names to list in the LaTeX document"), allow_none=True, ).tag(config=True) style = Unicode("default", help="Name of the pygments style to use").tag(config=True) def preprocess(self, nb, resources): """Preprocessing to apply on each notebook. Parameters ---------- nb : NotebookNode Notebook being converted resources : dictionary Additional resources used in the conversion process. Allows preprocessors to pass variables into the Jinja engine. """ # Generate Pygments definitions for Latex from pygments.formatters import LatexFormatter resources.setdefault("latex", {}) resources["latex"].setdefault( "pygments_definitions", LatexFormatter(style=self.style).get_style_defs() ) resources["latex"].setdefault("pygments_style_name", self.style) if self.author_names is not None: nb.metadata["authors"] = [{"name": author} for author in self.author_names] if self.date is not None: nb.metadata["date"] = self.date if self.title is not None: nb.metadata["title"] = self.title return nb, resources nbconvert-7.16.4/nbconvert/preprocessors/regexremove.py000066400000000000000000000047021461373220400234310ustar00rootroot00000000000000""" Module containing a preprocessor that removes cells if they match one or more regular expression. """ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. from __future__ import annotations import re from traitlets import List, Unicode from .base import Preprocessor class RegexRemovePreprocessor(Preprocessor): """ Removes cells from a notebook that match one or more regular expression. For each cell, the preprocessor checks whether its contents match the regular expressions in the ``patterns`` traitlet which is a list of unicode strings. If the contents match any of the patterns, the cell is removed from the notebook. To modify the list of matched patterns, modify the patterns traitlet. For example, execute the following command to convert a notebook to html and remove cells containing only whitespace:: jupyter nbconvert --RegexRemovePreprocessor.patterns="['\\s*\\Z']" mynotebook.ipynb The command line argument sets the list of patterns to ``'\\s*\\Z'`` which matches an arbitrary number of whitespace characters followed by the end of the string. See https://regex101.com/ for an interactive guide to regular expressions (make sure to select the python flavor). See https://docs.python.org/library/re.html for the official regular expression documentation in python. """ patterns = List(Unicode()).tag(config=True) def check_conditions(self, cell): """ Checks that a cell matches the pattern. Returns: Boolean. True means cell should *not* be removed. """ # Compile all the patterns into one: each pattern is first wrapped # by a non-capturing group to ensure the correct order of precedence # and the patterns are joined with a logical or pattern = re.compile("|".join("(?:%s)" % pattern for pattern in self.patterns)) # Filter out cells that meet the pattern and have no outputs return not pattern.match(cell.source) def preprocess(self, nb, resources): """ Preprocessing to apply to each notebook. See base.py for details. """ # Skip preprocessing if the list of patterns is empty if not self.patterns: return nb, resources # Filter out cells that meet the conditions nb.cells = [cell for cell in nb.cells if self.check_conditions(cell)] return nb, resources nbconvert-7.16.4/nbconvert/preprocessors/sanitize.py000066400000000000000000000125271461373220400227330ustar00rootroot00000000000000""" NBConvert Preprocessor for sanitizing HTML rendering of notebooks. """ import warnings from bleach import ALLOWED_ATTRIBUTES, ALLOWED_TAGS, clean from traitlets import Any, Bool, List, Set, Unicode from .base import Preprocessor _USE_BLEACH_CSS_SANITIZER = False _USE_BLEACH_STYLES = False try: # bleach[css] >=5.0 from bleach.css_sanitizer import ALLOWED_CSS_PROPERTIES as ALLOWED_STYLES from bleach.css_sanitizer import CSSSanitizer _USE_BLEACH_CSS_SANITIZER = True _USE_BLEACH_STYLES = False except ImportError: try: # bleach <5 from bleach import ALLOWED_STYLES # type:ignore[attr-defined, no-redef] _USE_BLEACH_CSS_SANITIZER = False _USE_BLEACH_STYLES = True warnings.warn( "Support for bleach <5 will be removed in a future version of nbconvert", DeprecationWarning, stacklevel=2, ) except ImportError: warnings.warn( "The installed bleach/tinycss2 do not provide CSS sanitization, " "please upgrade to bleach >=5", UserWarning, stacklevel=2, ) __all__ = ["SanitizeHTML"] class SanitizeHTML(Preprocessor): """A preprocessor to sanitize html.""" # Bleach config. attributes = Any( config=True, default_value=ALLOWED_ATTRIBUTES, help="Allowed HTML tag attributes", ) tags = List( Unicode(), config=True, default_value=ALLOWED_TAGS, # type:ignore[arg-type] help="List of HTML tags to allow", ) styles = List( Unicode(), config=True, default_value=ALLOWED_STYLES, # type:ignore[arg-type] help="Allowed CSS styles if {% endfor %} {% block notebook_css %} {{ resources.include_css("static/style.css") }} {% endblock notebook_css %} {%- block html_head_js_mathjax -%} {{ mathjax(resources.mathjax_url) }} {%- endblock html_head_js_mathjax -%} {%- block html_head_css -%} {%- endblock html_head_css -%} {%- endblock html_head -%} {%- endblock header -%} {% block body_header %}
{% endblock body_header %} {% block body_footer %}
{% endblock body_footer %} {% block footer %} {% block footer_js %} {% endblock footer_js %} {{ super() }} {% endblock footer %} nbconvert-7.16.4/share/templates/compatibility/000077500000000000000000000000001461373220400215645ustar00rootroot00000000000000nbconvert-7.16.4/share/templates/compatibility/display_priority.tpl000066400000000000000000000002051461373220400257100ustar00rootroot00000000000000{{ resources.deprecated("This template is deprecated, please use base/display_priority.j2") }} {%- extends 'display_priority.j2' -%} nbconvert-7.16.4/share/templates/compatibility/full.tpl000066400000000000000000000001741461373220400232510ustar00rootroot00000000000000{{ resources.deprecated("This template is deprecated, please use classic/index.html.j2") }} {%- extends 'index.html.j2' -%} nbconvert-7.16.4/share/templates/lab/000077500000000000000000000000001461373220400174515ustar00rootroot00000000000000nbconvert-7.16.4/share/templates/lab/base.html.j2000066400000000000000000000236731461373220400215760ustar00rootroot00000000000000{%- extends 'display_priority.j2' -%} {% from 'celltags.j2' import celltags %} {% from 'cell_id_anchor.j2' import cell_id_anchor %} {% block codecell %} {%- if not cell.outputs -%} {%- set no_output_class="jp-mod-noOutputs" -%} {%- endif -%} {%- if not resources.global_content_filter.include_input -%} {%- set no_input_class="jp-mod-noInput" -%} {%- endif -%} {%- endblock codecell %} {% block input_group -%} {% endblock input_group %} {% block input %} {%- endblock input %} {% block output_group %} {% endblock output_group %} {% block outputs %} {% endblock outputs %} {% block in_prompt -%} {%- endblock in_prompt %} {% block empty_in_prompt -%} {%- endblock empty_in_prompt %} {# output_prompt doesn't do anything in HTML, because there is a prompt div in each output area (see output block) #} {% block output_prompt %} {% endblock output_prompt %} {% block output_area_prompt %} {% endblock output_area_prompt %} {% block output %} {%- if output.output_type == 'execute_result' -%}