Compare commits

..

No commits in common. 'main' and '6.4' have entirely different histories.
main ... 6.4

@ -0,0 +1,19 @@
[bumpversion]
current_version = 7, 0, 0, 'alpha', 2
commit = False
tag = False
parse = (?P<major>\d+)\,\ (?P<minor>\d+)\,\ (?P<patch>\d+)\,\ \'(?P<release>\S+)\'\,\ (?P<build>\d+)
serialize =
{major}, {minor}, {patch}, '{release}', {build}
[bumpversion:part:release]
optional_value = final
values =
alpha
beta
candidate
final
[bumpversion:part:build]
[bumpversion:file:notebook/_version.py]

@ -1,13 +0,0 @@
FROM mcr.microsoft.com/devcontainers/base:jammy
ARG PIXI_VERSION=v0.42.1
RUN curl -L -o /usr/local/bin/pixi -fsSL --compressed "https://github.com/prefix-dev/pixi/releases/download/${PIXI_VERSION}/pixi-$(uname -m)-unknown-linux-musl" \
&& chmod +x /usr/local/bin/pixi \
&& pixi info
# set some user and workdir settings to work nicely with vscode
USER vscode
WORKDIR /home/vscode
RUN echo 'eval "$(pixi completion -s bash)"' >> /home/vscode/.bashrc

@ -1,21 +0,0 @@
{
"name": "Jupyter Notebook",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"forwardPorts": [8888],
"customizations": {
"vscode": {
"settings": {},
"extensions": ["ms-python.python", "charliermarsh.ruff", "GitHub.copilot"]
}
},
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"mounts": [
"source=${localWorkspaceFolderBasename}-pixi,target=${containerWorkspaceFolder}/.pixi,type=volume"
],
"postCreateCommand": "sudo chown vscode .pixi && pixi install && pixi run develop && pixi run pre-commit install -f"
}

@ -1,3 +1,6 @@
lint-staged.config.js
.eslintrc.js
node_modules
**/build
**/lib
@ -10,7 +13,6 @@ node_modules
coverage
*.map.js
*.bundle.js
app/index.template.js
# jetbrains IDE stuff
.idea/
@ -18,6 +20,3 @@ app/index.template.js
# ms IDE stuff
.history/
.vscode/
# Pixi environments
.pixi

@ -4,7 +4,7 @@ module.exports = {
es6: true,
commonjs: true,
node: true,
'jest/globals': true,
'jest/globals': true
},
root: true,
extends: [
@ -13,12 +13,12 @@ module.exports = {
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'plugin:react/recommended',
'plugin:jest/recommended',
'plugin:jest/recommended'
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.eslint.json',
sourceType: 'module',
sourceType: 'module'
},
plugins: ['@typescript-eslint', 'jest'],
rules: {
@ -29,9 +29,9 @@ module.exports = {
format: ['PascalCase'],
custom: {
regex: '^I[A-Z]',
match: true,
},
},
match: true
}
}
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
@ -42,16 +42,16 @@ module.exports = {
'@typescript-eslint/quotes': [
'error',
'single',
{ avoidEscape: true, allowTemplateLiterals: false },
{ avoidEscape: true, allowTemplateLiterals: false }
],
'jest/no-done-callback': 'off',
curly: ['error', 'all'],
eqeqeq: 'error',
'prefer-arrow-callback': 'error',
'prefer-arrow-callback': 'error'
},
settings: {
react: {
version: 'detect',
},
},
version: 'detect'
}
}
};

@ -1,2 +0,0 @@
# Run auto-formatters: https://github.com/jupyter/notebook/pull/6335
a7717d90f128368296fe3434deba5acd6031edab

2
.gitattributes vendored

@ -1,2 +0,0 @@
# SCM syntax highlighting & preventing 3-way merges
pixi.lock merge=binary linguist-language=YAML linguist-generated=true

@ -1,79 +1,50 @@
---
name: "\U0001F41B Bug report"
about: Create a report to help us repair something that is currently broken
labels: bug, status:Needs Triage
---
<!-- Welcome! Thank you for contributing. These HTML comments will not render in the issue, but you can delete them once you've read them if you prefer! -->
<!--
Right now, you're opening an issue to report a bug in Jupyter Notebook.
Please answer the following questions for yourself before submitting an issue
- [ ] I checked the documentation and found no answer
- [ ] I checked to make sure that this issue has not already been filed
- [ ] I'm reporting the issue to the correct repository
name: Is this a bug in Notebook? Open an issue.
about: If you're not sure, feel free to post your question on Jupyter's Discourse channel.
title: ''
labels: ''
assignees: ''
---<!--
BEFORE YOU OPEN AN ISSUE, PLEASE READ THIS
If you have further questions after reading below, please visit the Jupyter Notebook discourse channel (https://discourse.jupyter.org/) and submit your questions there. There are many more people in the Jupyter community that engage on that channel.
Hello! Thank you for using Jupyter Notebook. We're glad you're here.
NOTE:
Jupyter Notebook 6.x development is in maintenance-only mode. Bugs found in Notebook 6.x and that don't reproduce in Notebook 7.x may not get fixed.
Right now, you're opening an issue. Before you do, let's make sure this is the right place to post your question/issue.
Work in this repository is focused on Jupyter Notebook 7.x, the former RetroLab project. The code base for Notebook 7.x is very different than Notebook 6.x. If you can, please try reproducing Notebook 6.x bugs with Notebook 7.x using the main branch of this repository.
First, it's important to know that Jupyter Notebook development has moved into a phase of maintenance-only. There are very few people with limited time maintaining this repository. This means, we won't likely accept new features here. Instead, we recommend that you check out JupyterLab (https://github.com/jupyterlab/jupyterlab)—Jupyter's next generation Notebook interface.
We recommend that you check out JupyterLab (https://github.com/jupyterlab/jupyterlab), Jupyter's next generation Notebook interface.
Here, we're looking for specific bugs in the Jupyter Notebook codebase. If you think you've identified such a bug, you can continue opening your issue here. We'd appreciate if you include as much detail as possible, i.e. links to the offending code, snapshots of the UI issue, code-blocks with your console logs, etc.
Here, we're looking for specific bugs in the Jupyter Notebook codebase. If you think you've identified such a bug, you can continue opening your issue here. We'd appreciate if you include as much detail as possible, such as links to the offending code, snapshots of the UI issue, code blocks with your console logs, etc.
-->
If you're having issues installing Jupyter Notebook, or you're having another issue and don't know how to proceed, try the following:
## Description
1. scan the "What to do when things go wrong" (https://jupyter-notebook.readthedocs.io/en/stable/troubleshooting.html#what-to-do-when-things-go-wrong) page in our documentation to see if your question has already been answered
<!--Describe the bug clearly and concisely. Include screenshots if possible-->
2. post your question on the Jupyter Notebook discourse channel (https://discourse.jupyter.org/c/notebook/31). There are many more people in the Jupyter community that engage on that channel.
-->
## Reproduce
**Describe the bug**
A clear and concise description of what the bug is.
<!--Describe step-by-step instructions to reproduce the behavior-->
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error '...'
<!--Describe how you diagnosed the issue. See the guidelines at
https://jupyter-notebook.readthedocs.io/en/latest/troubleshooting.html -->
## Expected behavior
<!--Describe what you expected to happen-->
## Context
<!--Complete the following for context, and add any other relevant context-->
- Operating System and version: <!-- e.g. Linux Ubuntu 21.04 -->
- Browser and version: <!-- e.g. Chrome 92 -->
<!-- Please note the Notebook version you are working with. You can find this in the Help -> About Jupyter Notebook menu option or by running `jupyter --version` from your terminal -->
- Jupyter Notebook version: <!-- e.g. 3.1.7 -->
2. Click on '....'
3. Scroll down to '....'
4. See error
<!--The more content you provide, the more we can help!-->
**Expected behavior**
A clear and concise description of what you expected to happen.
<details><summary>Troubleshoot Output</summary>
<pre>
Paste the output from running `jupyter troubleshoot` from the command line here.
You may want to sanitize the paths in the output.
</pre>
</details>
**Screenshots**
If applicable, add screenshots to help explain your problem.
<details><summary>Command Line Output</summary>
<pre>
Paste the output from your command line running `jupyter notebook` here, use `--debug` if possible.
</pre>
</details>
**Desktop (please complete the following information):**
<details><summary>Browser Output</summary>
<!--See https://webmasters.stackexchange.com/a/77337 for how to access the JavaScript console-->
<pre>
Paste the output from your browser Javascript console here, if applicable.
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
</pre>
</details>
**Additional context**
Add any other context about the problem here.

@ -1,14 +1,11 @@
blank_issues_enabled: false
blank_issues_enabled: true
contact_links:
- name: Is this a common issue? See our Docs.
url: https://jupyter-notebook.readthedocs.io/en/latest/troubleshooting.html#what-to-do-when-things-go-wrong
about: Before opening an issue, make sure your issue hasn't already been addressed in the documentation.
- name: 🤔 Support and all other questions, including if you're not sure what to do.
url: https://jupyter-notebook.readthedocs.io/en/stable/troubleshooting.html#what-to-do-when-things-go-wrong
about: Before posting an issue here, make sure your issue hasn't already been addressed here.
- name: Do you need support or a question answered? See Jupyter Discourse.
url: https://discourse.jupyter.org/c/notebook/31
about: If you have a question or you're having issues installing Jupyter Notebook, try posting on Discourse.
- name: 💬 Chat with the devs
url: https://jupyter.zulipchat.com/
about: Ask short questions about using Jupyter Notebook
- name: 📝 Do you have a feature request that may be applied upstream? See JupyterLab.
about: If you have a question or you're having issues installing Jupyter Notebook, try posting on Discourse. There are lots of friendly Joyvans there to help!
- name: Do you have a feature request? See JupyterLab.
url: https://github.com/jupyterlab/jupyterlab
about: We recommend that you cross-reference JupyterLab for information when requesting new features and support for Notebook 7. We won't likely accept new features for Jupyter Notebook 6.x.
about: Jupyter Notebook is in a maintenance-only phase. We won't likely accept new features; instead, we recommend you check out JupyterLab for new features and support.

@ -1,41 +0,0 @@
---
name: "\U0001F680 Feature Request"
about: Suggest a new feature or a change
labels: enhancement, status:Needs Triage
---
<!-- Welcome! These HTML comments will not render in the issue, but you can delete them once you've read them if you prefer! -->
<!--
Thanks for thinking of a way to improve Jupyter Notebook. If this solves a problem for you, then it probably solves that problem for lots of people! So the whole community will benefit from this request.
NOTE: Please note that Jupyter Notebook 6.x development is in maintenance-only mode.
Finally, please answer the following questions for yourself before submitting an issue.
- [ ] I checked to make sure that this issue has not already been filed
- [ ] I'm reporting the issue to the correct repository
-->
### Problem
<!-- Provide a clear and concise description of what problem this feature will solve. For example:
* I'm always frustrated when [...] because [...]
* I would like it if [...] happened when I [...] because [...]
-->
### Proposed Solution
<!-- Provide a clear and concise description of a way to accomplish what you want. For example:
* Add an option so that when [...] [...] will happen
-->
### Additional context
<!-- Add any other context or screenshots about the feature request here. You can also include links to examples of other programs that have something similar to your request. For example:
* Another project [...] solved this by [...]
-->

@ -1,7 +1,7 @@
name: 'Build Jupyter Notebook'
description: 'Build Jupyter Notebook from source'
name: "Build Jupyter Notebook"
description: "Build Jupyter Notebook from source"
runs:
using: 'composite'
using: "composite"
steps:
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@ -9,18 +9,18 @@ runs:
- name: Install dependencies
shell: bash
run: |
python -m pip install hatch
python -m pip install --upgrade jupyter_packaging~=0.10 "jupyterlab>=4.0.0a22,<5" build
- name: Build pypi distributions
shell: bash
run: |
hatch build
python -m build
- name: Build npm distributions
shell: bash
run: |
mkdir pkgs
hatch run npm_pack
jlpm lerna exec -- npm pack
cp packages/*/*.tgz pkgs
- name: Build checksum file
@ -32,13 +32,13 @@ runs:
sha256sum * | tee SHA256SUMS
- name: Upload distributions
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: notebook-dist-${{ github.run_number }}
path: ./dist
- name: Upload distributions
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: notebook-pkgs-${{ github.run_number }}
path: ./pkgs

@ -1,14 +0,0 @@
version: 2
updates:
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
groups:
actions:
patterns:
- "*"
- package-ecosystem: 'pip'
directory: '/'
schedule:
interval: 'weekly'

@ -1,2 +0,0 @@
addBinderLink: false
triageLabel: 'status:Needs Triage'

@ -1,17 +0,0 @@
# https://github.com/marketplace/actions/auto-author-assign
name: 'Auto Author Assign'
on:
pull_request_target:
types: [opened, reopened]
permissions:
contents: read
jobs:
assign-author:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: toshimaru/auto-author-assign@v2.1.1

@ -3,9 +3,6 @@ on:
pull_request_target:
types: [opened]
permissions:
contents: read
jobs:
binder:
runs-on: ubuntu-latest

@ -4,11 +4,10 @@ on:
push:
branches: ['main']
pull_request:
schedule:
- cron: '0 0 * * *'
permissions:
contents: read
contents:
write
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
@ -19,136 +18,81 @@ env:
defaults:
run:
shell: bash -eux {0}
shell: bash -l {0}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Checkout
uses: actions/checkout@v2
- name: Build
uses: ./.github/actions/build-dist
- name: Build
uses: ./.github/actions/build-dist
test:
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
# used by the jupyterlab/maintainer-tools base-setup action
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Test the package
run: hatch run cov:test
- name: JavaScript tests
run: |
hatch run js_test
- name: Integration Tests
run: |
pip install .
cd
jupyter labextension list 2>&1 | grep -ie "@jupyter-notebook/lab-extension.*enabled.*ok" -
jupyter server extension list 2>&1 | grep -ie "notebook.*enabled" -
python -m jupyterlab.browser_check
- uses: jupyterlab/maintainer-tools/.github/actions/upload-coverage@v1
coverage:
runs-on: ubuntu-latest
needs:
- test
steps:
- uses: actions/checkout@v6
- uses: jupyterlab/maintainer-tools/.github/actions/report-coverage@v1
with:
fail_under: 78
test_docs:
name: Test Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- run: |
sudo apt-get update
sudo apt install enchant-2 # for spelling
# pandoc is not up to date in the ubuntu repos, so we install directly
wget https://github.com/jgm/pandoc/releases/download/2.14.2/pandoc-2.14.2-1-amd64.deb && sudo dpkg -i pandoc-2.14.2-1-amd64.deb
- run: hatch run docs:build
test_minimum_versions:
name: Test Minimum Versions
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
with:
dependency_type: minimum
python_version: '3.10'
- name: Run the unit tests
run: |
hatch run test:nowarn || hatch run test:nowarn --lf
test_prereleases:
name: Test Prereleases
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v6
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
with:
dependency_type: pre
- name: Run the tests
run: |
hatch run test:nowarn || hatch run test:nowarn --lf
- name: Checkout
uses: actions/checkout@v2
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install dependencies
run: |
python -m pip install -U jupyter_packaging~=0.10
- name: Install the package
run: |
python -m pip install .
jupyter labextension list 2>&1 | grep -ie "@jupyter-notebook/lab-extension.*enabled.*ok" -
jupyter server extension list 2>&1 | grep -ie "notebook.*enabled" -
python -m jupyterlab.browser_check
- name: Lint
run: |
jlpm
jlpm run eslint:check
jlpm run prettier:check
- name: Test
run: |
jlpm run build:test
jlpm run test
install:
needs: [build]
runs-on: ${{ matrix.os }}
timeout-minutes: 15
runs-on: ${{ matrix.os }}-latest
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python: ['3.9', '3.11', '3.13']
os: [ubuntu, macos, windows]
python: ['3.7', '3.10']
include:
- python: '3.9'
- python: '3.7'
dist: 'notebook*.tar.gz'
- python: '3.11'
dist: 'notebook*.whl'
- python: '3.13'
- python: '3.10'
dist: 'notebook*.whl'
- os: windows-latest
- os: windows
py_cmd: python
- os: macos-latest
- os: macos
py_cmd: python3
- os: ubuntu-latest
- os: ubuntu
py_cmd: python
steps:
- name: Install Python
uses: actions/setup-python@v6
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
allow-prereleases: true
- uses: actions/download-artifact@v6
architecture: 'x64'
- uses: actions/download-artifact@v2
with:
name: notebook-dist-${{ github.run_number }}
path: ./dist
- name: Install the prerequisites
run: |
${{ matrix.py_cmd }} -m pip install -U pip wheel
${{ matrix.py_cmd }} -m pip install pip wheel
- name: Install the package
run: |
cd dist
@ -165,50 +109,3 @@ jobs:
jupyter server extension list 2>&1 | grep -ie "notebook.*enabled" -
jupyter notebook --version
jupyter notebook --help
check_links:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1
with:
ignore_links: 'https://playwright.dev/docs/test-cli/ https://blog.jupyter.org/.* https://mybinder.org/v2/gh/jupyter/notebook/main https://nbviewer.jupyter.org https://stackoverflow.com https://github.com/[^/]+/?$'
ignore_glob: 'ui-tests/test/notebooks/*'
test_lint:
name: Test Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- 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 docs/source *.md
npm install -g yarn
yarn
yarn eslint:check
yarn prettier:check
yarn build:utils
yarn integrity
tests_check: # This job does nothing and is only used for the branch protection
if: always()
needs:
- coverage
- install
- test_lint
- test_docs
- test_minimum_versions
- test_prereleases
- check_links
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) }}

@ -13,72 +13,71 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
permissions:
contents: read
jobs:
versioning:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install dependencies
run: |
python -m pip install -U "jupyterlab>=4.6.0a0,<4.7" hatch
jlpm
jlpm run build
- name: Configure git identity to commit
run: |
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
- name: Reset version
run: |
hatch version 9.8.7
jlpm run lerna version 9.8.7 --no-push --force-publish --no-git-tag-version --yes
git commit -am "Release 9.8.7"
- name: Patch Release
run: |
jlpm release:patch --force
- name: Minor Release
run: |
jlpm release:bump minor --force
- name: Release Cycle
run: |
# beta
jlpm release:bump release --force
# rc
jlpm release:bump release --force
# final
jlpm release:bump release --force
- name: Major Release
run: |
jlpm release:bump major --force
- name: Checkout
uses: actions/checkout@v2
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install dependencies
run: |
python -m pip install -U "jupyterlab>=4.0.0a22,<5" jupyter_packaging~=0.10
jlpm
jlpm run build
- name: Configure git identity to commit
run: |
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
- name: Reset version
run: |
# TODO: improve this with a mock package?
# This step is to ensure the workflow always starts with a final version
sed -i -E "s/VersionInfo\(.*\)/VersionInfo\(9, 8, 7, 'final', 0\)/" notebook/_version.py
sed -i -E "s/current_version = .*/current_version = 9, 8, 7, 'final', 0/" .bumpversion.cfg
jlpm run lerna version 9.8.7 --no-push --force-publish --no-git-tag-version --yes
git commit -am "Release 9.8.7"
- name: Patch Release
run: |
jlpm release:patch --force
- name: Minor Release
run: |
jlpm release:bump minor --force
- name: Release Cycle
run: |
# beta
jlpm release:bump release --force
# rc
jlpm release:bump release --force
# final
jlpm release:bump release --force
- name: Major Release
run: |
jlpm release:bump major --force
npm:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Python
uses: actions/setup-python@v6
with:
python-version: '3.10'
architecture: 'x64'
- name: Install dependencies
run: |
python -m pip install -U "jupyterlab>=4.6.0a0,<4.7" pip
jlpm
jlpm run build
- name: Checkout
uses: actions/checkout@v2
- name: Install Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
architecture: 'x64'
- name: Install dependencies
run: |
python -m pip install -U "jupyterlab>=4.0.0a22,<5" jupyter_packaging~=0.10 pip
jlpm
jlpm run build

@ -1,11 +1,12 @@
name: Check Release
on:
push:
branches: ['main']
branches: ["main"]
pull_request:
permissions:
contents: read
contents:
write
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
@ -14,20 +15,24 @@ concurrency:
jobs:
check_release:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
group: [check_release, link_check]
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v2
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install Dependencies
run: |
pip install -e .
- name: Check Release
uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2
if: ${{ matrix.group == 'check_release' }}
uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
version_spec: next
- name: Upload Distributions
uses: actions/upload-artifact@v5
with:
name: notebook-jupyter-releaser-dist-${{ github.run_number }}
path: .jupyter_releaser_checkout/dist
- name: Check Links
if: ${{ matrix.group == 'link_check' }}
uses: jupyter-server/jupyter_releaser/.github/actions/check-links@v1

@ -0,0 +1,35 @@
name: Docs Tests
on:
push:
branches: ['main']
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
with:
python_version: '3.7'
- name: Install the Python dependencies
run: |
pip install -e .[test] codecov
pip install -r docs/doc-requirements.txt
wget https://github.com/jgm/pandoc/releases/download/1.19.1/pandoc-1.19.1-1-amd64.deb && sudo dpkg -i pandoc-1.19.1-1-amd64.deb
- name: List installed packages
run: |
pip freeze
pip check
- name: Run tests on documentation
run: |
EXIT_STATUS=0
make -C docs/ html SPHINXOPTS="-W" || EXIT_STATUS=$?
pytest --nbval --current-env docs || EXIT_STATUS=$?
exit $EXIT_STATUS

@ -1,16 +1,11 @@
name: Enforce PR label
permissions:
contents: read
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

@ -5,16 +5,16 @@ on:
- cron: '0 0 * * *'
permissions:
contents: read
issues:
write
pull-requests:
write
jobs:
lock:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: dessant/lock-threads@v5
- uses: dessant/lock-threads@v2
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '180'

@ -1,117 +0,0 @@
name: Update Playwright Snapshots
on:
issue_comment:
types: [created, edited]
permissions:
contents: read
jobs:
update-snapshots:
if: >
(
github.event.issue.author_association == 'OWNER' ||
github.event.issue.author_association == 'COLLABORATOR' ||
github.event.issue.author_association == 'MEMBER' ||
github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'COLLABORATOR' ||
github.event.comment.author_association == 'MEMBER'
) && github.event.issue.pull_request && (
contains(github.event.comment.body, 'please update playwright snapshots') ||
contains(github.event.comment.body, 'please update galata snapshots') ||
contains(github.event.comment.body, 'please update snapshots')
)
runs-on: ubuntu-latest
permissions:
# Required by actions/update-snapshots
contents: write
pull-requests: write
strategy:
fail-fast: false
matrix:
browser: [firefox, chromium]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: React to the triggering comment
run: |
gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions --raw-field 'content=+1'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Configure git to use https
run: git config --global hub.protocol https
- name: Get PR Info
id: pr
env:
PR_NUMBER: ${{ github.event.issue.number }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
COMMENT_AT: ${{ github.event.comment.created_at }}
run: |
pr="$(gh api /repos/${GH_REPO}/pulls/${PR_NUMBER})"
head_sha="$(echo "$pr" | jq -r .head.sha)"
pushed_at="$(echo "$pr" | jq -r .pushed_at)"
if [[ $(date -d "$pushed_at" +%s) -gt $(date -d "$COMMENT_AT" +%s) ]]; then
echo "Updating is not allowed because the PR was pushed to (at $pushed_at) after the triggering comment was issued (at $COMMENT_AT)"
exit 1
fi
echo "head_sha=$head_sha" >> $GITHUB_OUTPUT
- name: Checkout the branch from the PR that triggered the job
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr checkout ${{ github.event.issue.number }}
- name: Validate the fetched branch HEAD revision
env:
EXPECTED_SHA: ${{ steps.pr.outputs.head_sha }}
run: |
actual_sha="$(git rev-parse HEAD)"
if [[ "$actual_sha" != "$EXPECTED_SHA" ]]; then
echo "The HEAD of the checked out branch ($actual_sha) differs from the HEAD commit available at the time when trigger comment was submitted ($EXPECTED_SHA)"
exit 1
fi
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Build
uses: ./.github/actions/build-dist
- uses: actions/download-artifact@v6
with:
name: notebook-dist-${{ github.run_number }}
path: ./dist
- name: Install the package
run: |
cd dist
python -m pip install -vv notebook*.whl
# disable git hooks
git config core.hooksPath no-hooks
- name: Install the test dependencies
run: |
cd ui-tests
jlpm
jlpm playwright install
- name: Update snapshots
uses: jupyterlab/maintainer-tools/.github/actions/update-snapshots@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
npm_client: jlpm
test_folder: ui-tests
start_server_script: 'null'
update_script: test:update --browser ${{ matrix.browser }}
env:
DEBUG: pw:webserver

@ -1,49 +0,0 @@
name: "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
silent:
description: "Set a placeholder in the changelog and don't publish the release."
required: false
type: boolean
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 }}
silent: ${{ github.event.inputs.silent }}
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 }}"

@ -1,34 +0,0 @@
name: "Publish Changelog"
on:
release:
types: [published]
workflow_dispatch:
inputs:
branch:
description: "The branch to target"
required: false
jobs:
publish_changelog:
runs-on: ubuntu-latest
environment: release
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Publish changelog
id: publish-changelog
uses: jupyter-server/jupyter_releaser/.github/actions/publish-changelog@v2
with:
token: ${{ steps.app-token.outputs.token }}
branch: ${{ github.event.inputs.branch }}
- name: "** Next Step **"
run: |
echo "Merge the changelog update PR: ${{ steps.publish-changelog.outputs.pr_url }}"

@ -1,60 +0,0 @@
name: "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
with:
node_version: '24'
- uses: actions/create-github-app-token@v2
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 }}
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 }}
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 }}

@ -2,16 +2,13 @@ name: UI Tests
on:
push:
branches: ['main']
branches: ["main"]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build:
name: Build
@ -19,7 +16,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v2
- name: Build
uses: ./.github/actions/build-dist
@ -27,23 +24,29 @@ jobs:
ui-tests:
needs: [build]
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
browser: [firefox, chromium]
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v2
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
architecture: 'x64'
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v2
with:
name: notebook-dist-${{ github.run_number }}
path: ./dist
- name: Install the prerequisites
run: |
python -m pip install pip wheel
- name: Install the package
run: |
cd dist
@ -52,9 +55,20 @@ jobs:
- name: Install the test dependencies
run: |
cd ui-tests
jlpm
jlpm --frozen-lockfile
jlpm playwright install
- name: Start Jupyter Notebook
run: |
cd ui-tests
jlpm start:detached
- name: Wait for Jupyter Notebook
uses: ifaxity/wait-on-action@v1
with:
resource: http-get://127.0.0.1:8888/
timeout: 360000
- name: Test
run: |
cd ui-tests
@ -62,7 +76,7 @@ jobs:
- name: Upload Playwright Test assets
if: always()
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v2
with:
name: notebook-${{ matrix.browser }}-test-assets
path: |
@ -70,7 +84,7 @@ jobs:
- name: Upload Playwright Test report
if: always()
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v2
with:
name: notebook-${{ matrix.browser }}-test-report
path: |
@ -87,7 +101,7 @@ jobs:
- name: Upload updated snapshots
if: failure()
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v2
with:
name: notebook-${{ matrix.browser }}-updated-snapshots
path: ui-tests/test

@ -1,128 +0,0 @@
name: Check for latest JupyterLab releases
on:
# schedule:
# - cron: 30 17 * * *
workflow_dispatch:
inputs:
version:
description: 'JupyterLab version'
default: latest
required: true
type: string
branch:
description: 'The branch to target'
default: main
required: false
type: string
target_repo:
description: 'Target repository'
required: false
default: jupyter/notebook
type: string
env:
version_tag: 'latest'
permissions:
actions: write
contents: write
pull-requests: write
jobs:
check_for_lab_updates:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
ref: ${{ inputs.branch || 'main' }}
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install Node
uses: actions/setup-node@v6
with:
node-version: '20.x'
- name: Install npm dependencies and build buildutils
run: |
python -m pip install -e ".[dev]"
jlpm
jlpm run build:utils
- name: Check for new releases and update
shell: bash
run: |
set -eux
for version in ${{ inputs.version || env.version_tag }}
do
if [[ "${version}" == "latest" ]]; then
export LATEST=$(jlpm run get:lab:version --set-version ${version})
else
export LATEST=${version}
fi
done
echo "latest=${LATEST}" >> $GITHUB_ENV
jlpm upgrade:lab:dependencies --set-version ${LATEST}
if [[ ! -z "$(git status --porcelain package.json)" ]]; then
jlpm
jlpm deduplicate
cd ui-tests
jlpm
jlpm deduplicate
fi
- uses: prefix-dev/setup-pixi@v0.9.3
with:
pixi-version: v0.41.4
manifest-path: pyproject.toml
locked: false
- name: Update pixi.lock
run: pixi install
- name: Create a PR
env:
GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
run: |
set -eux
export LATEST=${{ env.latest }}
export BRANCH_NAME=update-to-v${LATEST}
# if resulted in any change:
if [[ ! -z "$(git status --porcelain package.json)" ]]; then
# if branch already exists.
if git ls-remote --heads origin | grep "refs/heads/${BRANCH_NAME}$" > /dev/null; then
echo "Branch '${BRANCH_NAME}' exists."
else
# new branch is created
git checkout -b "${BRANCH_NAME}"
git config user.name "github-actions[bot]"
git config user.email 'github-actions[bot]@users.noreply.github.com'
git commit . -m "Update to JupyterLab v${LATEST}"
git push --set-upstream origin "${BRANCH_NAME}"
PR_ARGS=(
--base "${{ inputs.branch || 'main' }}"
--title "Update to JupyterLab v${LATEST}"
--body "New JupyterLab release [v${LATEST}](https://github.com/jupyterlab/jupyterlab/releases/tag/v${LATEST}) is available. Please review the lock file carefully."
)
# Add --repo flag only if target_repo is specified
if [[ -n "${{ inputs.target_repo }}" ]]; then
PR_ARGS+=(--repo "${{ inputs.target_repo }}")
fi
gh pr create "${PR_ARGS[@]}"
fi
fi

22
.gitignore vendored

@ -126,25 +126,3 @@ ui-tests/playwright-report
# VSCode
.vscode
# RTC
.jupyter_ystore.db
# yarn >=2.x local files
.yarn/*
.pnp.*
ui-tests/.yarn/*
ui-tests/.pnp.*
# keep potential upstream patches
!.yarn/patches
# generated html
notebook/templates/*.html
# pixi environments
.pixi
*.egg-info
# Temporary files used for testing
tmp/

@ -1,86 +0,0 @@
ci:
autoupdate_schedule: monthly
autoupdate_commit_msg: 'chore: update pre-commit hooks'
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.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.30.0
hooks:
- id: check-github-workflows
- repo: https://github.com/codespell-project/codespell
rev: 'v2.3.0'
hooks:
- id: codespell
args: ['-L', 'hart,noteable', '--skip', "*.spec.ts"]
exclude: |
(?x)^(
yarn.lock|
pixi.lock|
binder/example.ipynb|
docs/source/examples/images/FrontendKernel.graffle/data.plist|
)$
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.14.1"
hooks:
- id: mypy
files: "^notebook"
stages: [manual]
args: ["--install-types", "--non-interactive"]
additional_dependencies: ["traitlets>=5.13", "tornado", "jupyter_server>=2.10", "jupyterlab_server>=2.25", "jupyterlab>=4.6.0a0,<4.7"]
- 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.8.6
hooks:
- id: ruff
types_or: [ python, jupyter ]
exclude: '^docs/source/examples/Notebook/Importing Notebooks.ipynb'
args: ['--fix', '--show-fixes']
- id: ruff-format
types_or: [ python, jupyter ]
exclude: '^docs/source/examples/Notebook/Importing Notebooks.ipynb'
- repo: https://github.com/scientific-python/cookie
rev: '2024.08.19'
hooks:
- id: sp-repo-review
additional_dependencies: ['repo-review[cli]']
- repo: local
hooks:
- id: prettier
name: prettier
entry: 'npm run prettier:files'
language: node
types_or: [json, ts, tsx, javascript, jsx, css, markdown]
stages: [manual]
- id: integrity
name: integrity
entry: 'npm run integrity --force'
language: node
stages: [pre-push]

@ -1,12 +1,7 @@
node_modules
.mypy_cache
.ruff_cache
**/node_modules
**/lib
**/package.json
**/static
**/labextension
build
CHANGELOG.md
app/index.template.js
.pixi

@ -1,13 +0,0 @@
version: 2
sphinx:
configuration: docs/source/conf.py
build:
os: ubuntu-22.04
tools:
python: '3.9'
nodejs: '16'
python:
install:
# install notebook itself
- method: pip
path: '.[docs]'

@ -1,5 +0,0 @@
enableImmutableInstalls: false
enableInlineBuilds: false
enableTelemetry: false
httpTimeout: 60000
nodeLinker: node-modules

File diff suppressed because it is too large Load Diff

@ -2,7 +2,7 @@
Thanks for contributing to Jupyter Notebook!
Make sure to follow [Project Jupyter's Code of Conduct](https://jupyter.org/governance/conduct/code-of-conduct)
Make sure to follow [Project Jupyter's Code of Conduct](https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md)
for a friendly and welcoming collaborative environment.
## Setting up a development environment
@ -12,7 +12,7 @@ Note: You will need NodeJS to build the extension package.
The `jlpm` command is JupyterLab's pinned version of [yarn](https://yarnpkg.com/) that is installed with JupyterLab. You may use
`yarn` or `npm` in lieu of `jlpm` below.
**Note**: we recommend using `mamba` to speed up the creation of the environment.
**Note**: we recomment using `mamba` to speed the creating of the environment.
```bash
# create a new environment
@ -22,11 +22,7 @@ mamba create -n notebook -c conda-forge python nodejs -y
mamba activate notebook
# Install package in development mode
pip install -e ".[dev,docs,test]"
# Install dependencies and build packages
jlpm
jlpm build
pip install -e .
# Link the notebook extension and @jupyter-notebook schemas
jlpm develop
@ -70,39 +66,6 @@ Then start Jupyter Notebook with:
jupyter notebook
```
### Local changes in Notebook dependencies
The development installation described above fetches JavaScript dependencies from `npm`.
according to the versions in the _package.json_ file.
However, it is sometimes useful to be able to test changes in Notebook, with dependencies (e.g. `@jupyterlab` packages) that have not yet
been published.
[yalc](https://github.com/wclr/yalc) can help you use local JavaScript packages when building Notebook, acting as a local package repository.
- Install yalc globally in your environment:
`npm install -g yalc`
- Publish your dependency package:\
`yalc publish`, from the package root directory.\
For instance, if you are developing on _@jupyterlab/ui-components_, this command must be executed from
_path_to_jupyterlab/packages/ui-components_.
- Depend on this local repository in Notebook:
- from the Notebook root directory:\
`yalc add your_package` : this will create a _dependencies_ entry in the main _package.json_ file.\
With the previous example, it would be `yalc add @jupyterlab/ui-components`.
- Notebook is a monorepo, so we want this dependency to be 'linked' as a resolution (for all sub-packages) instead
of a dependency.\
The easiest way is to manually move the new entry in _package.json_ from _dependencies_ to _resolutions_.
- Build Notebook with the local dependency:\
`jlpm install && jlpm build`
Changes in the dependency must then be built and pushed using `jlpm build && yalc push` (from the package root directory),
and fetched from Notebook using `yarn install`.
**Warning**: you need to make sure that the dependencies of Notebook and the local package match correctly,
otherwise there will be errors with webpack during build.\
In the previous example, both _@jupyterlab/ui-components_ and Notebook depend on _@jupyterlab/coreutils_. We
strongly advise you to depend on the same version.
## Running Tests
To run the tests:
@ -116,12 +79,6 @@ There are also end to end tests to cover higher level user interactions, located
```bash
cd ui-tests
#install required packages for jlpm
jlpm
#install playwright
jlpm playwright install
# start a new Jupyter server in a terminal
jlpm start
@ -131,117 +88,8 @@ jlpm test
The `test` script calls the Playwright test runner. You can pass additional arguments to `playwright` by appending parameters to the command. For example to run the test in headed mode, `jlpm test --headed`.
Check out the [Playwright Command Line Reference](https://playwright.dev/docs/test-cli/) for more information about the available command line options.
Checkout the [Playwright Command Line Reference](https://playwright.dev/docs/test-cli/) for more information about the available command line options.
Running the end to end tests in headful mode will trigger something like the following:
![playwright-headed-demo](https://user-images.githubusercontent.com/591645/141274633-ca9f9c2f-eef6-430e-9228-a35827f8133d.gif)
## Tasks caching
The repository is configured to use the Lerna caching system (via `nx`) for some of the development scripts.
This helps speed up rebuilds when running `jlpm run build` multiple times to avoid rebuilding packages that have not changed on disk.
You can generate a graph to have a better idea of the dependencies between all the packages using the following command:
```
npx nx graph
```
Running the command will open a browser tab by default with a graph that looks like the following:
![a screenshot showing the nx task graph](https://github.com/jupyter/notebook/assets/591645/34eb46f0-b0e5-44b6-9430-ae5fbd673a4b)
To learn more about Lerna caching:
- https://lerna.js.org/docs/features/cache-tasks
- https://nx.dev/features/cache-task-results
### Updating reference snapshots
Often a PR might make changes to the user interface, which can cause the visual regression tests to fail.
If you want to update the reference snapshots while working on a PR you can post the following sentence as a GitHub comment:
```
bot please update playwright snapshots
```
This will trigger a GitHub Action that will run the UI tests automatically and push new commits to the branch if the reference snapshots have changed.
## Code Styling
All non-python source code is formatted using [prettier](https://prettier.io) and python source code is formatted using [black](https://github.com/psf/black).
When code is modified and committed, all staged files will be
automatically formatted using pre-commit git hooks (with help from
[pre-commit](https://github.com/pre-commit/pre-commit). The benefit of
using code formatters like `prettier` and `black` is that it removes the topic of
code style from the conversation when reviewing pull requests, thereby
speeding up the review process.
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 ".[dev,test]"`
To install `pre-commit` manually, run the following:
```shell
pip install pre-commit
pre-commit install
```
You can invoke the pre-commit hook by hand at any time with:
```shell
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.
You may also use the prettier npm script (e.g. `npm run prettier` or
`yarn prettier` or `jlpm prettier`) to format the entire code base.
We recommend installing a prettier extension for your code editor and
configuring it to format your code with a keyboard shortcut, or
automatically on save.
Some of the hooks only run on CI by default, but you can invoke them by
running with the `--hook-stage manual` argument.
## Documentation
First make sure you have set up a development environment as described above.
Then run the following command to build the docs:
```shell
hatch run docs:build
```
In a separate terminal window, run the following command to serve the documentation:
```shell
hatch run docs:serve
```
Now open a web browser and navigate to `http://localhost:8000` to access the documentation.
## Contributing from the browser
Alternatively you can also contribute to Jupyter Notebook without setting up a local environment, directly from a web browser:
- [GitHub CodeSpaces](https://github.com/codespaces) is directly integrated into GitHub. This repository uses the [pixi](https://pixi.sh/) package manager to set up the development environment. To contribute after the Codespace is started:
- Run `pixi shell` in a terminal to activate the development environment
- Use the commands above for building the extension and running the tests, for example: `jlpm build`
- To start the application: `pixi run start`. A popup should appear with a button to open the Jupyter Notebook in a new browser tab. If the popup does not appear, you can navigate to the "Forwarded ports" panel to find the URL to the application.
- GitHub's [built-in editor](https://docs.github.com/en/repositories/working-with-files/managing-files/editing-files) is suitable for contributing small fixes.
- A more advanced [github.dev](https://docs.github.com/en/codespaces/the-githubdev-web-based-editor) editor can be accessed by pressing the dot (.) key while in the Jupyter Notebook GitHub repository
![playwight-headed-demo](https://user-images.githubusercontent.com/591645/141274633-ca9f9c2f-eef6-430e-9228-a35827f8133d.gif)

@ -1,4 +1,5 @@
BSD 3-Clause License
This project is licensed under the terms of the Modified BSD License
(also known as New or Revised or 3-Clause BSD), as follows:
- Copyright (c) 2001-2015, IPython Development Team
- Copyright (c) 2015-, Jupyter Development Team
@ -8,24 +9,50 @@ 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.
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.
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.
Neither the name of the Jupyter Development Team 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
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 OWNER 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.
## 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.

@ -0,0 +1,26 @@
include LICENSE
include *.md
include pyproject.toml
include setup.py
include jupyter-config/notebook.json
include package.json
include install.json
include ts*.json
graft notebook/labextension
graft notebook/static
graft notebook/templates
# Javascript files
graft src
graft style
prune **/node_modules
prune lib
# Patterns to exclude from any directory
global-exclude *~
global-exclude *.pyc
global-exclude *.pyo
global-exclude .git
global-exclude .ipynb_checkpoints

@ -3,24 +3,22 @@
![Github Actions Status](https://github.com/jupyter/notebook/workflows/Build/badge.svg)
[![Documentation Status](https://readthedocs.org/projects/jupyter-notebook/badge/?version=latest)](https://jupyter-notebook.readthedocs.io/en/latest/?badge=latest)
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyter/notebook/main?urlpath=tree)
[![codecov](https://codecov.io/gh/jupyter/notebook/branch/master/graph/badge.svg)](https://codecov.io/gh/jupyter/notebook)
The Jupyter notebook is a web-based notebook environment for interactive
computing.
![Jupyter notebook example](docs/resources/running_code_med.png 'Jupyter notebook example')
## Maintained versions
### Notice
We maintain the **two most recently released major versions of Jupyter Notebook**,
Classic Notebook v6 and Notebook v7. Notebook v5 is no longer maintained.
All Notebook v5 users are strongly advised to upgrade to Classic Notebook v6 as soon as possible.
The Jupyter Notebook project is currently undertaking a transition to a more modern code base built from the ground-up using JupyterLab components and extensions.
Upgrading to Notebook v7 may require more work, if you use custom extensions, as extensions written
for Notebook v5 or Classic Notebook v6 are not compatible with Notebook v7.
There is new stream of work which was submitted and then accepted as a Jupyter Enhancement Proposal (JEP): https://jupyter.org/enhancement-proposals/79-notebook-v7/notebook-v7.html
### Notebook v7
#### Notebook v7
The newest major version of Notebook is based on:
The next major version of Notebook will be based on:
- JupyterLab components for the frontend
- Jupyter Server for the Python server
@ -29,16 +27,15 @@ This represents a significant change to the `jupyter/notebook` code base.
To learn more about Notebook v7: https://jupyter.org/enhancement-proposals/79-notebook-v7/notebook-v7.html
### Classic Notebook v6
#### Classic Notebook v6
Maintenance and security-related issues [only](https://github.com/jupyter/notebook-team-compass/issues/5#issuecomment-1085254000) are now being addressed in the [`6.5.x`](https://github.com/jupyter/notebook/tree/6.5.x) branch.
It depends on [`nbclassic`](https://github.com/jupyter/nbclassic) for the HTML/JavaScript/CSS assets.
Maintainance and security-related issues are now being addressed in the [`6.4.x`](https://github.com/jupyter/notebook/tree/6.4.x) branch.
New features and continuous improvement is now focused on Notebook v7 (see section above).
If you have an open pull request with a new feature or if you were planning to open one, we encourage switching over to the Jupyter Server and JupyterLab architecture, and distribute it as a server extension and / or JupyterLab prebuilt extension. That way your new feature will also be compatible with the new Notebook v7.
## Jupyter notebook, the language-agnostic evolution of IPython notebook
### Jupyter notebook, the language-agnostic evolution of IPython notebook
Jupyter notebook is a language-agnostic HTML notebook application for
Project Jupyter. In 2015, Jupyter notebook was released as a part of
@ -79,7 +76,7 @@ jupyter notebook
### Running in a remote installation
You need some configuration before starting Jupyter notebook remotely. See [Running a notebook server](https://jupyter-server.readthedocs.io/en/latest/operators/public-server.html).
You need some configuration before starting Jupyter notebook remotely. See [Running a notebook server](https://jupyter-notebook.readthedocs.io/en/stable/public_server.html).
## Development Installation
@ -98,36 +95,8 @@ This repository is a Jupyter project and follows the Jupyter
- [Project Jupyter website](https://jupyter.org)
- [Online Demo at jupyter.org/try](https://jupyter.org/try)
- [Documentation for Jupyter notebook](https://jupyter-notebook.readthedocs.io/en/latest/)
- [Documentation for Jupyter notebook](https://jupyter-notebook.readthedocs.io/en/latest/) [[PDF](https://media.readthedocs.org/pdf/jupyter-notebook/latest/jupyter-notebook.pdf)]
- [Korean Version of Installation](https://github.com/ChungJooHo/Jupyter_Kor_doc/)
- [Documentation for Project Jupyter](https://jupyter.readthedocs.io/en/latest/index.html)
- [Documentation for Project Jupyter](https://jupyter.readthedocs.io/en/latest/index.html) [[PDF](https://media.readthedocs.org/pdf/jupyter/latest/jupyter.pdf)]
- [Issues](https://github.com/jupyter/notebook/issues)
- [Technical support - Jupyter Google Group](https://discourse.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.
```

@ -1,40 +1,9 @@
# Releasing Jupyter Notebook
## Using `jupyter_releaser`
## Automated releases
The recommended way to make a release is to use [`jupyter_releaser`](https://jupyter-releaser.readthedocs.io/en/latest/get_started/making_release_from_repo.html).
The recommended way to make a release is to use [`jupyter_releaser`](https://github.com/jupyter-server/jupyter_releaser#checklist-for-adoption).
## Manual Release
We follow a similar bump strategy as in JupyterLab: https://github.com/jupyterlab/jupyterlab/blob/master/RELEASE.md#bump-version
To create a manual release, perform the following steps:
### Set up
```bash
pip install hatch twine
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
hatch version ${new_version}
git tag -a ${new_version} -m "Release ${new_version}"
```
### Build the artifacts
```bash
rm -rf dist
hatch build
```
### Publish the artifacts to pypi
```bash
twine check dist/*
twine upload dist/*
```
If you would still like to do the release manually instead, read below.

@ -0,0 +1,338 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
// Inspired by: https://github.com/jupyterlab/jupyterlab/blob/master/dev_mode/index.js
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
require('./style.js');
require('./extraStyle.js');
function loadScript(url) {
return new Promise((resolve, reject) => {
const newScript = document.createElement('script');
newScript.onerror = reject;
newScript.onload = resolve;
newScript.async = true;
document.head.appendChild(newScript);
newScript.src = url;
});
}
async function loadComponent(url, scope) {
await loadScript(url);
// From MIT-licensed https://github.com/module-federation/module-federation-examples/blob/af043acd6be1718ee195b2511adf6011fba4233c/advanced-api/dynamic-remotes/app1/src/App.js#L6-L12
// eslint-disable-next-line no-undef
await __webpack_init_sharing__('default');
const container = window._JUPYTERLAB[scope];
// Initialize the container, it may provide shared modules and may need ours
// eslint-disable-next-line no-undef
await container.init(__webpack_share_scopes__.default);
}
async function createModule(scope, module) {
try {
const factory = await window._JUPYTERLAB[scope].get(module);
return factory();
} catch (e) {
console.warn(
`Failed to create module: package: ${scope}; module: ${module}`
);
throw e;
}
}
/**
* The main function
*/
async function main() {
// load extra packages
require('@jupyterlab/celltags');
const mimeExtensionsMods = [
require('@jupyterlab/javascript-extension'),
require('@jupyterlab/json-extension'),
require('@jupyterlab/pdf-extension'),
require('@jupyterlab/vega5-extension')
];
const mimeExtensions = await Promise.all(mimeExtensionsMods);
const disabled = [];
// TODO: formalize the way the set of initial extensions and plugins are specified
let baseMods = [
// @jupyter-notebook plugins
require('@jupyter-notebook/application-extension'),
require('@jupyter-notebook/console-extension'),
require('@jupyter-notebook/docmanager-extension'),
require('@jupyter-notebook/documentsearch-extension'),
require('@jupyter-notebook/help-extension'),
require('@jupyter-notebook/notebook-extension'),
// to handle opening new tabs after creating a new terminal
require('@jupyter-notebook/terminal-extension'),
// @jupyterlab plugins
require('@jupyterlab/application-extension').default.filter(({ id }) =>
[
'@jupyterlab/application-extension:commands',
'@jupyterlab/application-extension:context-menu',
'@jupyterlab/application-extension:faviconbusy'
].includes(id)
),
require('@jupyterlab/apputils-extension').default.filter(({ id }) =>
[
'@jupyterlab/apputils-extension:palette',
'@jupyterlab/apputils-extension:settings',
'@jupyterlab/apputils-extension:state',
'@jupyterlab/apputils-extension:themes',
'@jupyterlab/apputils-extension:themes-palette-menu',
'@jupyterlab/apputils-extension:toolbar-registry'
].includes(id)
),
require('@jupyterlab/codemirror-extension').default.filter(({ id }) =>
[
'@jupyterlab/codemirror-extension:services',
'@jupyterlab/codemirror-extension:codemirror'
].includes(id)
),
require('@jupyterlab/completer-extension').default.filter(({ id }) =>
[
'@jupyterlab/completer-extension:base-service',
'@jupyterlab/completer-extension:tracker'
].includes(id)
),
require('@jupyterlab/console-extension').default.filter(({ id }) =>
[
'@jupyterlab/console-extension:completer',
'@jupyterlab/console-extension:factory',
'@jupyterlab/console-extension:foreign',
'@jupyterlab/console-extension:tracker'
].includes(id)
),
require('@jupyterlab/docmanager-extension').default.filter(({ id }) =>
[
'@jupyterlab/docmanager-extension:plugin',
'@jupyterlab/docmanager-extension:download'
].includes(id)
),
require('@jupyterlab/docprovider-extension'),
require('@jupyterlab/documentsearch-extension').default.filter(({ id }) =>
['@jupyterlab/documentsearch-extension:plugin'].includes(id)
),
require('@jupyterlab/filebrowser-extension').default.filter(({ id }) =>
['@jupyterlab/filebrowser-extension:factory'].includes(id)
),
require('@jupyterlab/fileeditor-extension').default.filter(({ id }) =>
['@jupyterlab/fileeditor-extension:plugin'].includes(id)
),
require('@jupyterlab/mainmenu-extension'),
require('@jupyterlab/markedparser-extension'),
require('@jupyterlab/mathjax2-extension'),
require('@jupyterlab/notebook-extension').default.filter(({ id }) =>
[
'@jupyterlab/notebook-extension:code-console',
'@jupyterlab/notebook-extension:export',
'@jupyterlab/notebook-extension:factory',
'@jupyterlab/notebook-extension:tracker',
'@jupyterlab/notebook-extension:widget-factory'
].includes(id)
),
require('@jupyterlab/rendermime-extension'),
require('@jupyterlab/shortcuts-extension'),
// so new terminals can be create from the menu
require('@jupyterlab/terminal-extension'),
require('@jupyterlab/theme-light-extension'),
require('@jupyterlab/theme-dark-extension'),
require('@jupyterlab/translation-extension'),
// Add the "Hub Control Panel" menu option when running in JupyterHub
require('@jupyterlab/user-extension'),
require('@jupyterlab/hub-extension')
];
// The motivation here is to only load a specific set of plugins dependending on
// the current page
const page = PageConfig.getOption('notebookPage');
switch (page) {
case 'tree': {
baseMods = baseMods.concat([
require('@jupyterlab/filebrowser-extension').default.filter(({ id }) =>
[
'@jupyterlab/filebrowser-extension:browser',
'@jupyterlab/filebrowser-extension:download',
'@jupyterlab/filebrowser-extension:file-upload-status',
'@jupyterlab/filebrowser-extension:open-with',
'@jupyterlab/filebrowser-extension:share-file'
].includes(id)
),
require('@jupyter-notebook/tree-extension'),
require('@jupyterlab/running-extension')
]);
break;
}
case 'notebooks': {
baseMods = baseMods.concat([
require('@jupyterlab/notebook-extension').default.filter(({ id }) =>
['@jupyterlab/notebook-extension:completer'].includes(id)
),
require('@jupyterlab/tooltip-extension').default.filter(({ id }) =>
[
'@jupyterlab/tooltip-extension:manager',
'@jupyterlab/tooltip-extension:notebooks'
].includes(id)
)
]);
break;
}
case 'consoles': {
baseMods = baseMods.concat([
require('@jupyterlab/tooltip-extension').default.filter(({ id }) =>
[
'@jupyterlab/tooltip-extension:manager',
'@jupyterlab/tooltip-extension:consoles'
].includes(id)
)
]);
break;
}
case 'edit': {
baseMods = baseMods.concat([
require('@jupyterlab/fileeditor-extension').default.filter(({ id }) =>
['@jupyterlab/fileeditor-extension:completer'].includes(id)
),
require('@jupyterlab/filebrowser-extension').default.filter(({ id }) =>
['@jupyterlab/filebrowser-extension:browser'].includes(id)
)
]);
break;
}
}
/**
* Iterate over active plugins in an extension.
*
* #### Notes
* This also populates the disabled
*/
function* activePlugins(extension) {
// Handle commonjs or es2015 modules
let exports;
if (Object.prototype.hasOwnProperty.call(extension, '__esModule')) {
exports = extension.default;
} else {
// CommonJS exports.
exports = extension;
}
let plugins = Array.isArray(exports) ? exports : [exports];
for (let plugin of plugins) {
if (PageConfig.Extension.isDisabled(plugin.id)) {
disabled.push(plugin.id);
continue;
}
yield plugin;
}
}
const extension_data = JSON.parse(
PageConfig.getOption('federated_extensions')
);
const mods = [];
const federatedExtensionPromises = [];
const federatedMimeExtensionPromises = [];
const federatedStylePromises = [];
const extensions = await Promise.allSettled(
extension_data.map(async data => {
await loadComponent(
`${URLExt.join(
PageConfig.getOption('fullLabextensionsUrl'),
data.name,
data.load
)}`,
data.name
);
return data;
})
);
extensions.forEach(p => {
if (p.status === 'rejected') {
// There was an error loading the component
console.error(p.reason);
return;
}
const data = p.value;
if (data.extension) {
federatedExtensionPromises.push(createModule(data.name, data.extension));
}
if (data.mimeExtension) {
federatedMimeExtensionPromises.push(
createModule(data.name, data.mimeExtension)
);
}
if (data.style) {
federatedStylePromises.push(createModule(data.name, data.style));
}
});
// Add the base frontend extensions
const baseFrontendMods = await Promise.all(baseMods);
baseFrontendMods.forEach(p => {
for (let plugin of activePlugins(p)) {
mods.push(plugin);
}
});
// Add the federated extensions.
const federatedExtensions = await Promise.allSettled(
federatedExtensionPromises
);
federatedExtensions.forEach(p => {
if (p.status === 'fulfilled') {
for (let plugin of activePlugins(p.value)) {
mods.push(plugin);
}
} else {
console.error(p.reason);
}
});
// Add the federated mime extensions.
const federatedMimeExtensions = await Promise.allSettled(
federatedMimeExtensionPromises
);
federatedMimeExtensions.forEach(p => {
if (p.status === 'fulfilled') {
for (let plugin of activePlugins(p.value)) {
mimeExtensions.push(plugin);
}
} else {
console.error(p.reason);
}
});
// Load all federated component styles and log errors for any that do not
(await Promise.allSettled(federatedStylePromises))
.filter(({ status }) => status === 'rejected')
.forEach(({ reason }) => {
console.error(reason);
});
const NotebookApp = require('@jupyter-notebook/application').NotebookApp;
const app = new NotebookApp({ mimeExtensions });
app.registerPluginModules(mods);
// Expose global app instance when in dev mode or when toggled explicitly.
const exposeAppInBrowser =
(PageConfig.getOption('exposeAppInBrowser') || '').toLowerCase() === 'true';
if (exposeAppInBrowser) {
window.jupyterapp = app;
}
await app.start();
}
window.addEventListener('load', main);

@ -1,244 +0,0 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
// Inspired by: https://github.com/jupyterlab/jupyterlab/blob/master/dev_mode/index.js
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
import { PluginRegistry } from '@lumino/coreutils';
require('./style.js');
require('./extraStyle.js');
function loadScript(url) {
return new Promise((resolve, reject) => {
const newScript = document.createElement('script');
newScript.onerror = reject;
newScript.onload = resolve;
newScript.async = true;
document.head.appendChild(newScript);
newScript.src = url;
});
}
async function loadComponent(url, scope) {
await loadScript(url);
// From MIT-licensed https://github.com/module-federation/module-federation-examples/blob/af043acd6be1718ee195b2511adf6011fba4233c/advanced-api/dynamic-remotes/app1/src/App.js#L6-L12
// eslint-disable-next-line no-undef
await __webpack_init_sharing__('default');
const container = window._JUPYTERLAB[scope];
// Initialize the container, it may provide shared modules and may need ours
// eslint-disable-next-line no-undef
await container.init(__webpack_share_scopes__.default);
}
async function createModule(scope, module) {
try {
const factory = await window._JUPYTERLAB[scope].get(module);
const instance = factory();
instance.__scope__ = scope;
return instance;
} catch (e) {
console.warn(
`Failed to create module: package: ${scope}; module: ${module}`
);
throw e;
}
}
/**
* The main function
*/
async function main() {
const mimeExtensionsMods = [
{{#each notebook_mime_extensions}}
require('{{ @key }}'),
{{/each}}
];
const mimeExtensions = await Promise.all(mimeExtensionsMods);
// Load the base plugins available on all pages
let baseMods = [
{{#each notebook_plugins}}
{{#if (ispage @key '/')}}
{{{ list_plugins }}}
{{/if}}
{{/each}}
];
const page = `/${PageConfig.getOption('notebookPage')}`;
switch (page) {
{{#each notebook_plugins}}
{{#unless (ispage @key '/')}}
// list all the other plugins grouped by page
case '{{ @key }}': {
baseMods = baseMods.concat([
{{{ list_plugins }}}
]);
break;
}
{{/unless}}
{{/each}}
}
// populate the list of disabled extensions
const disabled = [];
const availablePlugins = [];
/**
* Iterate over active plugins in an extension.
*
* #### Notes
* This also populates the disabled
*/
function* activePlugins(extension) {
// Handle commonjs or es2015 modules
let exports;
if (Object.prototype.hasOwnProperty.call(extension, '__esModule')) {
exports = extension.default;
} else {
// CommonJS exports.
exports = extension;
}
let plugins = Array.isArray(exports) ? exports : [exports];
for (let plugin of plugins) {
const isDisabled = PageConfig.Extension.isDisabled(plugin.id);
availablePlugins.push({
id: plugin.id,
description: plugin.description,
requires: plugin.requires ?? [],
optional: plugin.optional ?? [],
provides: plugin.provides ?? null,
autoStart: plugin.autoStart,
enabled: !isDisabled,
extension: extension.__scope__
});
if (isDisabled) {
disabled.push(plugin.id);
continue;
}
yield plugin;
}
}
const extension_data = JSON.parse(
PageConfig.getOption('federated_extensions')
);
const mods = [];
const federatedExtensionPromises = [];
const federatedMimeExtensionPromises = [];
const federatedStylePromises = [];
const extensions = await Promise.allSettled(
extension_data.map(async data => {
await loadComponent(
`${URLExt.join(
PageConfig.getOption('fullLabextensionsUrl'),
data.name,
data.load
)}`,
data.name
);
return data;
})
);
extensions.forEach(p => {
if (p.status === 'rejected') {
// There was an error loading the component
console.error(p.reason);
return;
}
const data = p.value;
if (data.extension) {
federatedExtensionPromises.push(createModule(data.name, data.extension));
}
if (data.mimeExtension) {
federatedMimeExtensionPromises.push(
createModule(data.name, data.mimeExtension)
);
}
if (data.style && !PageConfig.Extension.isDisabled(data.name)) {
federatedStylePromises.push(createModule(data.name, data.style));
}
});
// Add the base frontend extensions
const baseFrontendMods = await Promise.all(baseMods);
baseFrontendMods.forEach(p => {
for (let plugin of activePlugins(p)) {
mods.push(plugin);
}
});
// Add the federated extensions.
const federatedExtensions = await Promise.allSettled(
federatedExtensionPromises
);
federatedExtensions.forEach(p => {
if (p.status === 'fulfilled') {
for (let plugin of activePlugins(p.value)) {
mods.push(plugin);
}
} else {
console.error(p.reason);
}
});
// Add the federated mime extensions.
const federatedMimeExtensions = await Promise.allSettled(
federatedMimeExtensionPromises
);
federatedMimeExtensions.forEach(p => {
if (p.status === 'fulfilled') {
for (let plugin of activePlugins(p.value)) {
mimeExtensions.push(plugin);
}
} else {
console.error(p.reason);
}
});
// Load all federated component styles and log errors for any that do not
(await Promise.allSettled(federatedStylePromises))
.filter(({ status }) => status === 'rejected')
.forEach(({ reason }) => {
console.error(reason);
});
// Set the list of base notebook multi-page plugins so the app is aware of all
// its built-in plugins even if they are not loaded on the current page.
// For example this is useful so the Settings Editor can list the debugger
// plugin even if the debugger is only loaded on the notebook page.
PageConfig.setOption('allPlugins', '{{{ json notebook_plugins }}}');
const pluginRegistry = new PluginRegistry();
const NotebookApp = require('@jupyter-notebook/application').NotebookApp;
pluginRegistry.registerPlugins(mods);
const IServiceManager = require('@jupyterlab/services').IServiceManager;
const serviceManager = await pluginRegistry.resolveRequiredService(IServiceManager);
const app = new NotebookApp({
pluginRegistry,
serviceManager,
mimeExtensions,
availablePlugins
});
// Expose global app instance when in dev mode or when toggled explicitly.
const exposeAppInBrowser =
(PageConfig.getOption('exposeAppInBrowser') || '').toLowerCase() === 'true';
if (exposeAppInBrowser) {
window.jupyterapp = app;
}
await app.start();
}
window.addEventListener('load', main);

@ -1,428 +1,226 @@
{
"name": "@jupyter-notebook/app",
"version": "7.6.0-alpha.0",
"version": "7.0.0-alpha.2",
"private": true,
"scripts": {
"build": "rspack",
"build:prod": "rspack --config ./rspack.prod.config.js",
"build": "webpack",
"build:prod": "webpack --mode=production",
"clean": "rimraf build && jlpm run clean:static",
"clean:static": "rimraf -g \"../notebook/static/!(favicons)\"",
"watch": "rspack --watch --config rspack.config.js"
"prepublishOnly": "yarn run build",
"watch": "webpack --config ./webpack.config.watch.js"
},
"resolutions": {
"@codemirror/state": "~6.5.2",
"@codemirror/view": "~6.38.1",
"@jupyter-notebook/application": "~7.6.0-alpha.0",
"@jupyter-notebook/application-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/console-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/docmanager-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/documentsearch-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/help-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/notebook-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/terminal-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/tree": "~7.6.0-alpha.0",
"@jupyter-notebook/tree-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/ui-components": "~7.6.0-alpha.0",
"@jupyter/react-components": "~0.16.7",
"@jupyter/web-components": "~0.16.7",
"@jupyter/ydoc": "~3.1.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/application-extension": "~4.6.0-alpha.0",
"@jupyterlab/apputils": "~4.7.0-alpha.0",
"@jupyterlab/apputils-extension": "~4.6.0-alpha.0",
"@jupyterlab/attachments": "~4.6.0-alpha.0",
"@jupyterlab/audio-extension": "~4.6.0-alpha.0",
"@jupyterlab/cell-toolbar": "~4.6.0-alpha.0",
"@jupyterlab/cell-toolbar-extension": "~4.6.0-alpha.0",
"@jupyterlab/celltags-extension": "~4.6.0-alpha.0",
"@jupyterlab/codeeditor": "~4.6.0-alpha.0",
"@jupyterlab/codemirror": "~4.6.0-alpha.0",
"@jupyterlab/codemirror-extension": "~4.6.0-alpha.0",
"@jupyterlab/completer": "~4.6.0-alpha.0",
"@jupyterlab/completer-extension": "~4.6.0-alpha.0",
"@jupyterlab/console": "~4.6.0-alpha.0",
"@jupyterlab/console-extension": "~4.6.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/csvviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/debugger": "~4.6.0-alpha.0",
"@jupyterlab/debugger-extension": "~4.6.0-alpha.0",
"@jupyterlab/docmanager": "~4.6.0-alpha.0",
"@jupyterlab/docmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/documentsearch": "~4.6.0-alpha.0",
"@jupyterlab/documentsearch-extension": "~4.6.0-alpha.0",
"@jupyterlab/extensionmanager": "~4.6.0-alpha.0",
"@jupyterlab/extensionmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/filebrowser": "~4.6.0-alpha.0",
"@jupyterlab/filebrowser-extension": "~4.6.0-alpha.0",
"@jupyterlab/fileeditor": "~4.6.0-alpha.0",
"@jupyterlab/fileeditor-extension": "~4.6.0-alpha.0",
"@jupyterlab/help-extension": "~4.6.0-alpha.0",
"@jupyterlab/htmlviewer": "~4.6.0-alpha.0",
"@jupyterlab/htmlviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/hub-extension": "~4.6.0-alpha.0",
"@jupyterlab/imageviewer": "~4.6.0-alpha.0",
"@jupyterlab/imageviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/javascript-extension": "~4.6.0-alpha.0",
"@jupyterlab/json-extension": "~4.6.0-alpha.0",
"@jupyterlab/logconsole-extension": "~4.6.0-alpha.0",
"@jupyterlab/lsp": "~4.6.0-alpha.0",
"@jupyterlab/lsp-extension": "~4.6.0-alpha.0",
"@jupyterlab/mainmenu": "~4.6.0-alpha.0",
"@jupyterlab/mainmenu-extension": "~4.6.0-alpha.0",
"@jupyterlab/markdownviewer": "~4.6.0-alpha.0",
"@jupyterlab/markdownviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/markedparser-extension": "~4.6.0-alpha.0",
"@jupyterlab/mathjax-extension": "~4.6.0-alpha.0",
"@jupyterlab/mermaid": "~4.6.0-alpha.0",
"@jupyterlab/mermaid-extension": "~4.6.0-alpha.0",
"@jupyterlab/metadataform": "~4.6.0-alpha.0",
"@jupyterlab/metadataform-extension": "~4.6.0-alpha.0",
"@jupyterlab/notebook": "~4.6.0-alpha.0",
"@jupyterlab/notebook-extension": "~4.6.0-alpha.0",
"@jupyterlab/observables": "~5.6.0-alpha.0",
"@jupyterlab/outputarea": "~4.6.0-alpha.0",
"@jupyterlab/pdf-extension": "~4.6.0-alpha.0",
"@jupyterlab/pluginmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/rendermime": "~4.6.0-alpha.0",
"@jupyterlab/rendermime-interfaces": "~3.14.0-alpha.0",
"@jupyterlab/running-extension": "~4.6.0-alpha.0",
"@jupyterlab/services": "~7.6.0-alpha.0",
"@jupyterlab/services-extension": "~4.6.0-alpha.0",
"@jupyterlab/settingeditor": "~4.6.0-alpha.0",
"@jupyterlab/settingeditor-extension": "~4.6.0-alpha.0",
"@jupyterlab/settingregistry": "~4.6.0-alpha.0",
"@jupyterlab/shortcuts-extension": "~5.4.0-alpha.0",
"@jupyterlab/statedb": "~4.6.0-alpha.0",
"@jupyterlab/statusbar": "~4.6.0-alpha.0",
"@jupyterlab/terminal": "~4.6.0-alpha.0",
"@jupyterlab/terminal-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-dark-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-dark-high-contrast-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-light-extension": "~4.6.0-alpha.0",
"@jupyterlab/toc-extension": "~6.6.0-alpha.0",
"@jupyterlab/tooltip": "~4.6.0-alpha.0",
"@jupyterlab/tooltip-extension": "~4.6.0-alpha.0",
"@jupyterlab/translation": "~4.6.0-alpha.0",
"@jupyterlab/translation-extension": "~4.6.0-alpha.0",
"@jupyterlab/ui-components": "~4.6.0-alpha.0",
"@jupyterlab/ui-components-extension": "~4.6.0-alpha.0",
"@jupyterlab/vega5-extension": "~4.6.0-alpha.0",
"@jupyterlab/video-extension": "~4.6.0-alpha.0",
"@lezer/common": "~1.2.1",
"@lezer/highlight": "~1.2.0",
"@lumino/algorithm": "~2.0.4",
"@lumino/application": "~2.4.5",
"@lumino/commands": "~2.3.3",
"@lumino/coreutils": "~2.2.2",
"@lumino/disposable": "~2.1.5",
"@lumino/domutils": "~2.0.4",
"@lumino/dragdrop": "~2.1.7",
"@lumino/messaging": "~2.0.4",
"@lumino/properties": "~2.0.4",
"@lumino/signaling": "~2.1.5",
"@lumino/virtualdom": "~2.0.4",
"@lumino/widgets": "~2.7.2",
"react": "~18.2.0",
"react-dom": "~18.2.0",
"yjs": "~13.6.8"
"@jupyter-notebook/application": "~7.0.0-alpha.2",
"@jupyter-notebook/application-extension": "~7.0.0-alpha.2",
"@jupyter-notebook/console-extension": "~7.0.0-alpha.2",
"@jupyter-notebook/docmanager-extension": "~7.0.0-alpha.2",
"@jupyter-notebook/documentsearch-extension": "~7.0.0-alpha.2",
"@jupyter-notebook/help-extension": "~7.0.0-alpha.2",
"@jupyter-notebook/notebook-extension": "~7.0.0-alpha.2",
"@jupyter-notebook/terminal-extension": "~7.0.0-alpha.2",
"@jupyter-notebook/tree-extension": "~7.0.0-alpha.2",
"@jupyter-notebook/ui-components": "~7.0.0-alpha.2",
"@jupyterlab/application": "~4.0.0-alpha.7",
"@jupyterlab/application-extension": "~4.0.0-alpha.7",
"@jupyterlab/apputils": "~4.0.0-alpha.7",
"@jupyterlab/apputils-extension": "~4.0.0-alpha.7",
"@jupyterlab/celltags": "~4.0.0-alpha.7",
"@jupyterlab/codeeditor": "~4.0.0-alpha.7",
"@jupyterlab/codemirror-extension": "~4.0.0-alpha.7",
"@jupyterlab/completer": "~4.0.0-alpha.7",
"@jupyterlab/completer-extension": "~4.0.0-alpha.7",
"@jupyterlab/console": "~4.0.0-alpha.7",
"@jupyterlab/console-extension": "~4.0.0-alpha.7",
"@jupyterlab/coreutils": "~6.0.0-alpha.7",
"@jupyterlab/docmanager": "~4.0.0-alpha.7",
"@jupyterlab/docmanager-extension": "~4.0.0-alpha.7",
"@jupyterlab/docprovider": "~4.0.0-alpha.7",
"@jupyterlab/docprovider-extension": "~4.0.0-alpha.7",
"@jupyterlab/documentsearch": "~4.0.0-alpha.7",
"@jupyterlab/documentsearch-extension": "~4.0.0-alpha.7",
"@jupyterlab/filebrowser": "~4.0.0-alpha.7",
"@jupyterlab/filebrowser-extension": "~4.0.0-alpha.7",
"@jupyterlab/fileeditor": "~4.0.0-alpha.7",
"@jupyterlab/fileeditor-extension": "~4.0.0-alpha.7",
"@jupyterlab/hub-extension": "~4.0.0-alpha.7",
"@jupyterlab/javascript-extension": "~4.0.0-alpha.7",
"@jupyterlab/json-extension": "~4.0.0-alpha.7",
"@jupyterlab/mainmenu": "~4.0.0-alpha.7",
"@jupyterlab/mainmenu-extension": "~4.0.0-alpha.7",
"@jupyterlab/markedparser-extension": "~4.0.0-alpha.6",
"@jupyterlab/mathjax2-extension": "~4.0.0-alpha.7",
"@jupyterlab/notebook": "~4.0.0-alpha.7",
"@jupyterlab/notebook-extension": "~4.0.0-alpha.7",
"@jupyterlab/observables": "~5.0.0-alpha.7",
"@jupyterlab/outputarea": "~4.0.0-alpha.7",
"@jupyterlab/pdf-extension": "~4.0.0-alpha.7",
"@jupyterlab/rendermime": "~4.0.0-alpha.7",
"@jupyterlab/rendermime-extension": "~4.0.0-alpha.7",
"@jupyterlab/rendermime-interfaces": "~4.0.0-alpha.7",
"@jupyterlab/running-extension": "~4.0.0-alpha.7",
"@jupyterlab/services": "~7.0.0-alpha.7",
"@jupyterlab/settingregistry": "~4.0.0-alpha.7",
"@jupyterlab/shared-models": "~4.0.0-alpha.7",
"@jupyterlab/shortcuts-extension": "~4.0.0-alpha.7",
"@jupyterlab/statedb": "~4.0.0-alpha.7",
"@jupyterlab/statusbar": "~4.0.0-alpha.7",
"@jupyterlab/terminal": "~4.0.0-alpha.7",
"@jupyterlab/terminal-extension": "~4.0.0-alpha.7",
"@jupyterlab/theme-dark-extension": "~4.0.0-alpha.7",
"@jupyterlab/theme-light-extension": "~4.0.0-alpha.7",
"@jupyterlab/tooltip": "~4.0.0-alpha.7",
"@jupyterlab/tooltip-extension": "~4.0.0-alpha.7",
"@jupyterlab/translation": "~4.0.0-alpha.7",
"@jupyterlab/translation-extension": "~4.0.0-alpha.7",
"@jupyterlab/ui-components": "~4.0.0-alpha.22",
"@jupyterlab/user": "~4.0.0-alpha.7",
"@jupyterlab/user-extension": "~4.0.0-alpha.7",
"@jupyterlab/vega5-extension": "~4.0.0-alpha.7",
"@lumino/algorithm": "~1.9.1",
"@lumino/application": "~1.28.1",
"@lumino/commands": "~1.20.0",
"@lumino/coreutils": "~1.12.0",
"@lumino/disposable": "~1.10.1",
"@lumino/domutils": "~1.8.1",
"@lumino/dragdrop": "~1.14.0",
"@lumino/messaging": "~1.10.1",
"@lumino/properties": "~1.8.1",
"@lumino/signaling": "~1.10.1",
"@lumino/virtualdom": "~1.14.1",
"@lumino/widgets": "~1.31.1",
"react": "~17.0.2",
"react-dom": "~17.0.2",
"yjs": "~13.5.28"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyter-notebook/application-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/console-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/docmanager-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/documentsearch-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/help-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/notebook-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/terminal-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/tree": "^7.6.0-alpha.0",
"@jupyter-notebook/tree-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/ui-components": "^7.6.0-alpha.0",
"@jupyterlab/application-extension": "~4.6.0-alpha.0",
"@jupyterlab/apputils-extension": "~4.6.0-alpha.0",
"@jupyterlab/attachments": "~4.6.0-alpha.0",
"@jupyterlab/audio-extension": "~4.6.0-alpha.0",
"@jupyterlab/cell-toolbar-extension": "~4.6.0-alpha.0",
"@jupyterlab/celltags-extension": "~4.6.0-alpha.0",
"@jupyterlab/codemirror": "~4.6.0-alpha.0",
"@jupyterlab/codemirror-extension": "~4.6.0-alpha.0",
"@jupyterlab/completer-extension": "~4.6.0-alpha.0",
"@jupyterlab/console-extension": "~4.6.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/csvviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/debugger-extension": "~4.6.0-alpha.0",
"@jupyterlab/docmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/documentsearch-extension": "~4.6.0-alpha.0",
"@jupyterlab/extensionmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/filebrowser-extension": "~4.6.0-alpha.0",
"@jupyterlab/fileeditor-extension": "~4.6.0-alpha.0",
"@jupyterlab/help-extension": "~4.6.0-alpha.0",
"@jupyterlab/htmlviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/hub-extension": "~4.6.0-alpha.0",
"@jupyterlab/imageviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/javascript-extension": "~4.6.0-alpha.0",
"@jupyterlab/json-extension": "~4.6.0-alpha.0",
"@jupyterlab/logconsole-extension": "~4.6.0-alpha.0",
"@jupyterlab/lsp": "~4.6.0-alpha.0",
"@jupyterlab/lsp-extension": "~4.6.0-alpha.0",
"@jupyterlab/mainmenu-extension": "~4.6.0-alpha.0",
"@jupyterlab/markdownviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/markedparser-extension": "~4.6.0-alpha.0",
"@jupyterlab/mathjax-extension": "~4.6.0-alpha.0",
"@jupyterlab/mermaid-extension": "~4.6.0-alpha.0",
"@jupyterlab/metadataform-extension": "~4.6.0-alpha.0",
"@jupyterlab/notebook-extension": "~4.6.0-alpha.0",
"@jupyterlab/pdf-extension": "~4.6.0-alpha.0",
"@jupyterlab/pluginmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/running-extension": "~4.6.0-alpha.0",
"@jupyterlab/services-extension": "~4.6.0-alpha.0",
"@jupyterlab/settingeditor": "~4.6.0-alpha.0",
"@jupyterlab/settingeditor-extension": "~4.6.0-alpha.0",
"@jupyterlab/shortcuts-extension": "~5.4.0-alpha.0",
"@jupyterlab/terminal-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-dark-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-dark-high-contrast-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-light-extension": "~4.6.0-alpha.0",
"@jupyterlab/toc-extension": "~6.6.0-alpha.0",
"@jupyterlab/tooltip-extension": "~4.6.0-alpha.0",
"@jupyterlab/translation-extension": "~4.6.0-alpha.0",
"@jupyterlab/ui-components-extension": "~4.6.0-alpha.0",
"@jupyterlab/vega5-extension": "~4.6.0-alpha.0",
"@jupyterlab/video-extension": "~4.6.0-alpha.0",
"@lumino/coreutils": "~2.2.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"yjs": "^13.5.40"
"@jupyter-notebook/application": "^7.0.0-alpha.2",
"@jupyter-notebook/application-extension": "^7.0.0-alpha.2",
"@jupyter-notebook/console-extension": "^7.0.0-alpha.2",
"@jupyter-notebook/docmanager-extension": "^7.0.0-alpha.2",
"@jupyter-notebook/documentsearch-extension": "^7.0.0-alpha.2",
"@jupyter-notebook/help-extension": "^7.0.0-alpha.2",
"@jupyter-notebook/notebook-extension": "^7.0.0-alpha.2",
"@jupyter-notebook/terminal-extension": "^7.0.0-alpha.2",
"@jupyter-notebook/tree-extension": "^7.0.0-alpha.2",
"@jupyter-notebook/ui-components": "^7.0.0-alpha.2",
"@jupyterlab/application-extension": "^4.0.0-alpha.7",
"@jupyterlab/apputils-extension": "^4.0.0-alpha.7",
"@jupyterlab/celltags": "^4.0.0-alpha.7",
"@jupyterlab/codemirror-extension": "^4.0.0-alpha.7",
"@jupyterlab/completer-extension": "^4.0.0-alpha.7",
"@jupyterlab/console-extension": "^4.0.0-alpha.7",
"@jupyterlab/coreutils": "~6.0.0-alpha.7",
"@jupyterlab/docmanager-extension": "^4.0.0-alpha.7",
"@jupyterlab/docprovider-extension": "^4.0.0-alpha.7",
"@jupyterlab/documentsearch-extension": "^4.0.0-alpha.7",
"@jupyterlab/filebrowser-extension": "^4.0.0-alpha.7",
"@jupyterlab/fileeditor-extension": "^4.0.0-alpha.7",
"@jupyterlab/hub-extension": "^4.0.0-alpha.7",
"@jupyterlab/javascript-extension": "^4.0.0-alpha.7",
"@jupyterlab/json-extension": "^4.0.0-alpha.7",
"@jupyterlab/mainmenu-extension": "^4.0.0-alpha.7",
"@jupyterlab/markedparser-extension": "^4.0.0-alpha.6",
"@jupyterlab/mathjax2-extension": "^4.0.0-alpha.7",
"@jupyterlab/notebook-extension": "^4.0.0-alpha.7",
"@jupyterlab/pdf-extension": "^4.0.0-alpha.7",
"@jupyterlab/rendermime-extension": "^4.0.0-alpha.7",
"@jupyterlab/running-extension": "^4.0.0-alpha.7",
"@jupyterlab/shortcuts-extension": "^4.0.0-alpha.7",
"@jupyterlab/terminal-extension": "^4.0.0-alpha.7",
"@jupyterlab/theme-dark-extension": "^4.0.0-alpha.7",
"@jupyterlab/theme-light-extension": "^4.0.0-alpha.7",
"@jupyterlab/tooltip-extension": "^4.0.0-alpha.7",
"@jupyterlab/translation-extension": "^4.0.0-alpha.7",
"@jupyterlab/user-extension": "^4.0.0-alpha.7",
"@jupyterlab/vega5-extension": "^4.0.0-alpha.7"
},
"devDependencies": {
"@jupyterlab/builder": "~4.6.0-alpha.0",
"@jupyterlab/buildutils": "~4.6.0-alpha.0",
"@rspack/cli": "^1.1.8",
"@rspack/core": "^1.1.8",
"@types/rimraf": "^3.0.2",
"@jupyterlab/builder": "^4.0.0-alpha.7",
"@jupyterlab/buildutils": "^4.0.0-alpha.7",
"@types/rimraf": "^3.0.0",
"css-loader": "~5.0.1",
"file-loader": "~5.0.2",
"fs-extra": "^8.1.0",
"glob": "~7.1.6",
"handlebars": "^4.7.7",
"rimraf": "^3.0.2",
"webpack-bundle-analyzer": "^4.8.0",
"webpack-merge": "^5.8.0",
"mini-css-extract-plugin": "~0.9.0",
"npm-run-all": "^4.1.5",
"raw-loader": "~4.0.0",
"rimraf": "~3.0.2",
"style-loader": "~1.0.1",
"svg-url-loader": "~6.0.0",
"url-loader": "~4.1.1",
"watch": "~1.0.2",
"webpack": "^5.7.0",
"webpack-bundle-analyzer": "^4.1.0",
"webpack-cli": "^4.2.0",
"webpack-merge": "^5.1.2",
"whatwg-fetch": "^3.0.0"
},
"jupyterlab": {
"name": "Jupyter Notebook",
"mimeExtensions": {
"@jupyterlab/javascript-extension": true,
"@jupyterlab/json-extension": true,
"@jupyterlab/pdf-extension": true,
"@jupyterlab/vega5-extension": true
},
"plugins": {
"/": {
"@jupyter-notebook/application-extension": true,
"@jupyter-notebook/console-extension": true,
"@jupyter-notebook/docmanager-extension": true,
"@jupyter-notebook/documentsearch-extension": true,
"@jupyter-notebook/help-extension": true,
"@jupyter-notebook/notebook-extension": true,
"@jupyter-notebook/terminal-extension": true,
"@jupyterlab/application-extension": [
"@jupyterlab/application-extension:commands",
"@jupyterlab/application-extension:context-menu",
"@jupyterlab/application-extension:faviconbusy",
"@jupyterlab/application-extension:router",
"@jupyterlab/application-extension:top-bar",
"@jupyterlab/application-extension:top-spacer"
],
"@jupyterlab/apputils-extension": [
"@jupyterlab/apputils-extension:kernels-settings",
"@jupyterlab/apputils-extension:palette",
"@jupyterlab/apputils-extension:notification",
"@jupyterlab/apputils-extension:sanitizer",
"@jupyterlab/apputils-extension:sessionDialogs",
"@jupyterlab/apputils-extension:settings",
"@jupyterlab/apputils-extension:state",
"@jupyterlab/apputils-extension:themes",
"@jupyterlab/apputils-extension:themes-palette-menu",
"@jupyterlab/apputils-extension:toolbar-registry",
"@jupyterlab/apputils-extension:utilityCommands"
],
"@jupyterlab/audio-extension": true,
"@jupyterlab/codemirror-extension": true,
"@jupyterlab/completer-extension": [
"@jupyterlab/completer-extension:base-service",
"@jupyterlab/completer-extension:inline-completer",
"@jupyterlab/completer-extension:inline-completer-factory",
"@jupyterlab/completer-extension:inline-history",
"@jupyterlab/completer-extension:manager"
],
"@jupyterlab/console-extension": [
"@jupyterlab/console-extension:cell-executor",
"@jupyterlab/console-extension:completer",
"@jupyterlab/console-extension:factory",
"@jupyterlab/console-extension:foreign",
"@jupyterlab/console-extension:tracker"
],
"@jupyterlab/csvviewer-extension": true,
"@jupyterlab/docmanager-extension": [
"@jupyterlab/docmanager-extension:plugin",
"@jupyterlab/docmanager-extension:download",
"@jupyterlab/docmanager-extension:contexts",
"@jupyterlab/docmanager-extension:manager"
],
"@jupyterlab/documentsearch-extension": [
"@jupyterlab/documentsearch-extension:plugin"
],
"@jupyterlab/filebrowser-extension": [
"@jupyterlab/filebrowser-extension:factory",
"@jupyterlab/filebrowser-extension:default-file-browser"
],
"@jupyterlab/fileeditor-extension": [
"@jupyterlab/fileeditor-extension:plugin",
"@jupyterlab/fileeditor-extension:widget-factory"
],
"@jupyterlab/help-extension": [
"@jupyterlab/help-extension:resources"
],
"@jupyterlab/htmlviewer-extension": true,
"@jupyterlab/hub-extension": true,
"@jupyterlab/imageviewer-extension": true,
"@jupyterlab/lsp-extension": true,
"@jupyterlab/mainmenu-extension": [
"@jupyterlab/mainmenu-extension:plugin"
],
"@jupyterlab/markedparser-extension": true,
"@jupyterlab/mathjax-extension": true,
"@jupyterlab/mermaid-extension": true,
"@jupyterlab/notebook-extension": [
"@jupyterlab/notebook-extension:cell-executor",
"@jupyterlab/notebook-extension:code-console",
"@jupyterlab/notebook-extension:export",
"@jupyterlab/notebook-extension:factory",
"@jupyterlab/notebook-extension:tracker",
"@jupyterlab/notebook-extension:widget-factory"
],
"@jupyterlab/pluginmanager-extension": true,
"@jupyterlab/services-extension": true,
"@jupyterlab/shortcuts-extension": true,
"@jupyterlab/terminal-extension": true,
"@jupyterlab/theme-light-extension": true,
"@jupyterlab/theme-dark-extension": true,
"@jupyterlab/theme-dark-high-contrast-extension": true,
"@jupyterlab/translation-extension": true,
"@jupyterlab/ui-components-extension": true,
"@jupyterlab/video-extension": true
},
"/tree": {
"@jupyterlab/cell-toolbar-extension": true,
"@jupyterlab/extensionmanager-extension": true,
"@jupyterlab/filebrowser-extension": [
"@jupyterlab/filebrowser-extension:browser",
"@jupyterlab/filebrowser-extension:create-new-language-file",
"@jupyterlab/filebrowser-extension:download",
"@jupyterlab/filebrowser-extension:file-upload-status",
"@jupyterlab/filebrowser-extension:open-with",
"@jupyterlab/filebrowser-extension:search",
"@jupyterlab/filebrowser-extension:share-file"
],
"@jupyter-notebook/tree-extension": true,
"@jupyterlab/running-extension": [
"@jupyterlab/running-extension:plugin"
],
"@jupyterlab/settingeditor-extension": true
},
"/notebooks": {
"@jupyterlab/celltags-extension": true,
"@jupyterlab/cell-toolbar-extension": true,
"@jupyterlab/debugger-extension": [
"@jupyterlab/debugger-extension:completions",
"@jupyterlab/debugger-extension:config",
"@jupyterlab/debugger-extension:debug-console",
"@jupyterlab/debugger-extension:main",
"@jupyterlab/debugger-extension:notebooks",
"@jupyterlab/debugger-extension:service",
"@jupyterlab/debugger-extension:sidebar",
"@jupyterlab/debugger-extension:sources",
"@jupyterlab/debugger-extension:display-registry"
],
"@jupyterlab/logconsole-extension": true,
"@jupyterlab/metadataform-extension": true,
"@jupyterlab/notebook-extension": [
"@jupyterlab/notebook-extension:active-cell-tool",
"@jupyterlab/notebook-extension:completer",
"@jupyterlab/notebook-extension:copy-output",
"@jupyterlab/notebook-extension:metadata-editor",
"@jupyterlab/notebook-extension:search",
"@jupyterlab/notebook-extension:toc",
"@jupyterlab/notebook-extension:tools",
"@jupyterlab/notebook-extension:update-raw-mimetype"
],
"@jupyterlab/toc-extension": [
"@jupyterlab/toc-extension:registry",
"@jupyterlab/toc-extension:tracker"
],
"@jupyterlab/tooltip-extension": [
"@jupyterlab/tooltip-extension:manager",
"@jupyterlab/tooltip-extension:notebooks"
]
},
"/consoles": {
"@jupyterlab/tooltip-extension": [
"@jupyterlab/tooltip-extension:manager",
"@jupyterlab/tooltip-extension:consoles"
]
},
"/edit": {
"@jupyterlab/fileeditor-extension": [
"@jupyterlab/fileeditor-extension:completer",
"@jupyterlab/fileeditor-extension:search"
],
"@jupyterlab/markdownviewer-extension": true
}
},
"extensions": [
"@jupyter-notebook/application-extension",
"@jupyter-notebook/console-extension",
"@jupyter-notebook/docmanager-extension",
"@jupyter-notebook/documentsearch-extension",
"@jupyter-notebook/help-extension",
"@jupyter-notebook/notebook-extension",
"@jupyter-notebook/terminal-extension",
"@jupyter-notebook/tree-extension",
"@jupyterlab/application-extension",
"@jupyterlab/apputils-extension",
"@jupyterlab/codemirror-extension",
"@jupyterlab/completer-extension",
"@jupyterlab/console-extension",
"@jupyterlab/docmanager-extension",
"@jupyterlab/documentsearch-extension",
"@jupyterlab/filebrowser-extension",
"@jupyterlab/fileeditor-extension",
"@jupyterlab/hub-extension",
"@jupyterlab/mainmenu-extension",
"@jupyterlab/mathjax2-extension",
"@jupyterlab/markedparser-extension",
"@jupyterlab/notebook-extension",
"@jupyterlab/rendermime-extension",
"@jupyterlab/running-extension",
"@jupyterlab/shortcuts-extension",
"@jupyterlab/terminal-extension",
"@jupyterlab/theme-dark-extension",
"@jupyterlab/theme-light-extension",
"@jupyterlab/tooltip-extension",
"@jupyterlab/translation-extension",
"@jupyterlab/user-extension"
],
"singletonPackages": [
"@codemirror/state",
"@codemirror/view",
"@jupyter-notebook/tree",
"@jupyter/react-components",
"@jupyter/web-components",
"@jupyter/ydoc",
"@jupyterlab/application",
"@jupyterlab/apputils",
"@jupyterlab/cell-toolbar",
"@jupyterlab/celltags",
"@jupyterlab/codeeditor",
"@jupyterlab/codemirror",
"@jupyterlab/completer",
"@jupyterlab/console",
"@jupyterlab/coreutils",
"@jupyterlab/debugger",
"@jupyterlab/docmanager",
"@jupyterlab/docprovider",
"@jupyterlab/documentsearch",
"@jupyterlab/extensionmanager",
"@jupyterlab/filebrowser",
"@jupyterlab/fileeditor",
"@jupyterlab/htmlviewer",
"@jupyterlab/imageviewer",
"@jupyterlab/lsp",
"@jupyterlab/mainmenu",
"@jupyterlab/markdownviewer",
"@jupyterlab/mermaid",
"@jupyterlab/metadataform",
"@jupyterlab/notebook",
"@jupyterlab/observables",
"@jupyterlab/outputarea",
"@jupyterlab/rendermime",
"@jupyterlab/rendermime-interfaces",
"@jupyterlab/services",
"@jupyterlab/settingeditor",
"@jupyterlab/settingregistry",
"@jupyterlab/shared-models",
"@jupyterlab/statedb",
"@jupyterlab/statusbar",
"@jupyterlab/terminal",
"@jupyterlab/tooltip",
"@jupyterlab/translation",
"@jupyterlab/user",
"@jupyterlab/ui-components",
"@lezer/common",
"@lezer/highlight",
"@lumino/algorithm",
"@lumino/application",
"@lumino/commands",
@ -438,6 +236,8 @@
"react",
"react-dom",
"yjs"
]
],
"mimeExtensions": {},
"linkedPackages": {}
}
}

@ -1,15 +0,0 @@
/*
* Copyright (c) Jupyter Development Team.
* Distributed under the terms of the Modified BSD License.
*/
const base = require('./rspack.config');
module.exports = [
{
...base[0],
bail: false,
watch: true,
},
...base.slice(1),
];

@ -1,29 +0,0 @@
/*
* Copyright (c) Jupyter Development Team.
* Distributed under the terms of the Modified BSD License.
*/
const merge = require('webpack-merge').default;
const config = require('./rspack.config');
const WPPlugin = require('@jupyterlab/builder').WPPlugin;
config[0] = merge(config[0], {
mode: 'production',
devtool: 'source-map',
output: {
// Add version argument when in production so the Jupyter server
// allows caching of files (i.e., does not set the CacheControl header to no-cache to prevent caching static files)
filename: '[name].[contenthash].js?v=[contenthash]',
},
optimization: {
minimize: false,
},
plugins: [
new WPPlugin.JSONLicenseWebpackPlugin({
excludedPackageTest: (packageName) =>
packageName === '@jupyter-notebook/app',
}),
],
});
module.exports = config;

@ -0,0 +1 @@
import '@jupyterlab/celltags/style/index.js';

@ -1,45 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{page_config['appName'] | e}} - Console</title>
{% block favicon %}
<link
rel="icon"
type="image/x-icon"
href="{{ page_config['fullStaticUrl'] | e }}/favicons/favicon-console.ico"
class="favicon"
/>
{% endblock %} {% if custom_css %}
<link
rel="stylesheet"
type="text/css"
href="{{ base_url | escape }}custom/custom.css"
/>
{% endif %}
</head>
<body class="jp-ThemedContainer">
{# Copy so we do not modify the page_config with updates. #} {% set
page_config_full = page_config.copy() %} {# Set a dummy variable - we just
want the side effect of the update. #} {% set _ =
page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} {# Sentinel value
to say that we are on the tree page #} {% set _ =
page_config_full.update(notebookPage='consoles') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({}, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -1,39 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{page_config['appName'] | e}} - Edit</title>
{% block favicon %}
<link
rel="icon"
type="image/x-icon"
href="{{ base_url | escape }}static/favicons/favicon-file.ico"
class="favicon"
/>
{% endblock %}
</head>
<body class="jp-ThemedContainer" data-notebook="edit">
{# Copy so we do not modify the page_config with updates. #} {% set
page_config_full = page_config.copy() %} {# Set a dummy variable - we just
want the side effect of the update. #} {% set _ =
page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} {# Sentinel value
to say that we are on the tree page #} {% set _ =
page_config_full.update(notebookPage='edit') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({}, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -1,45 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{page_config['appName'] | e}} - Notebook</title>
{% block favicon %}
<link
rel="icon"
type="image/x-icon"
href="{{ base_url | escape }}static/favicons/favicon-notebook.ico"
class="favicon"
/>
{% endblock %} {% if custom_css %}
<link
rel="stylesheet"
type="text/css"
href="{{ base_url | escape }}custom/custom.css"
/>
{% endif %}
</head>
<body class="jp-ThemedContainer" data-notebook="notebooks">
{# Copy so we do not modify the page_config with updates. #} {% set
page_config_full = page_config.copy() %} {# Set a dummy variable - we just
want the side effect of the update. #} {% set _ =
page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} {# Sentinel value
to say that we are on the tree page #} {% set _ =
page_config_full.update(notebookPage='notebooks') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({}, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -1,45 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{page_config['appName'] | e}} - Terminal</title>
{% block favicon %}
<link
rel="icon"
type="image/x-icon"
href="{{ base_url | escape }}static/favicons/favicon-terminal.ico"
class="favicon"
/>
{% endblock %} {% if custom_css %}
<link
rel="stylesheet"
type="text/css"
href="{{ base_url | escape }}custom/custom.css"
/>
{% endif %}
</head>
<body class="jp-ThemedContainer">
{# Copy so we do not modify the page_config with updates. #} {% set
page_config_full = page_config.copy() %} {# Set a dummy variable - we just
want the side effect of the update. #} {% set _ =
page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} {# Sentinel value
to say that we are on the tree page #} {% set _ =
page_config_full.update(notebookPage='terminals') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({}, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -1,45 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Home</title>
{% block favicon %}
<link
rel="icon"
type="image/x-icon"
href="{{ base_url | escape }}static/favicons/favicon.ico"
class="favicon"
/>
{% endblock %} {% if custom_css %}
<link
rel="stylesheet"
type="text/css"
href="{{ base_url | escape }}custom/custom.css"
/>
{% endif %}
</head>
<body class="jp-ThemedContainer">
{# Copy so we do not modify the page_config with updates. #} {% set
page_config_full = page_config.copy() %} {# Set a dummy variable - we just
want the side effect of the update. #} {% set _ =
page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} {# Sentinel value
to say that we are on the tree page #} {% set _ =
page_config_full.update(notebookPage='tree') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({}, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -2,25 +2,22 @@
// Distributed under the terms of the Modified BSD License.
// Heavily inspired (and slightly tweaked) from:
// https://github.com/jupyterlab/jupyterlab/blob/master/examples/federated/core_package/rspack.config.js
// https://github.com/jupyterlab/jupyterlab/blob/master/examples/federated/core_package/webpack.config.js
const fs = require('fs-extra');
const path = require('path');
const rspack = require('@rspack/core');
const webpack = require('webpack');
const merge = require('webpack-merge').default;
const Handlebars = require('handlebars');
const { ModuleFederationPlugin } = rspack.container;
const BundleAnalyzerPlugin =
require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { ModuleFederationPlugin } = webpack.container;
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
.BundleAnalyzerPlugin;
const Build = require('@jupyterlab/builder').Build;
const WPPlugin = require('@jupyterlab/builder').WPPlugin;
const HtmlWebpackPlugin = require('html-webpack-plugin');
const baseConfig = require('@jupyterlab/builder/lib/webpack.config.base');
const data = require('./package.json');
const names = Object.keys(data.dependencies).filter((name) => {
const names = Object.keys(data.dependencies).filter(name => {
const packageData = require(path.join(name, 'package.json'));
return packageData.jupyterlab !== undefined;
});
@ -32,73 +29,25 @@ if (fs.existsSync(buildDir)) {
}
fs.ensureDirSync(buildDir);
// Handle the extensions.
const { mimeExtensions, plugins } = data.jupyterlab;
// Create the list of extension packages from the package.json metadata
const extensionPackages = new Set();
Object.keys(plugins).forEach((page) => {
const pagePlugins = plugins[page];
Object.keys(pagePlugins).forEach((name) => {
extensionPackages.add(name);
});
});
Handlebars.registerHelper('json', function (context) {
return JSON.stringify(context);
});
// custom help to check if a page corresponds to a value
Handlebars.registerHelper('ispage', function (key, page) {
return key === page;
});
// custom helper to load the plugins on the index page
Handlebars.registerHelper('list_plugins', function () {
let str = '';
const page = this;
Object.keys(this).forEach((extension) => {
const plugin = page[extension];
if (plugin === true) {
str += `require(\'${extension}\'),\n `;
} else if (Array.isArray(plugin)) {
const plugins = plugin.map((p) => `'${p}',`).join('\n');
str += `
require(\'${extension}\').default.filter(({id}) => [
${plugins}
].includes(id)),
`;
}
});
return str;
});
// Create the entry point and other assets in build directory.
const source = fs.readFileSync('index.template.js').toString();
const template = Handlebars.compile(source);
const extData = {
notebook_plugins: plugins,
notebook_mime_extensions: mimeExtensions,
};
const indexOut = template(extData);
fs.writeFileSync(path.join(buildDir, 'index.js'), indexOut);
// Copy extra files
const index = path.resolve(__dirname, 'index.js');
const cssImports = path.resolve(__dirname, 'style.js');
fs.copySync(index, path.resolve(buildDir, 'index.js'));
fs.copySync(cssImports, path.resolve(buildDir, 'extraStyle.js'));
const extras = Build.ensureAssets({
packageNames: names,
output: buildDir,
schemaOutput: path.resolve(__dirname, '..', 'notebook'),
schemaOutput: path.resolve(__dirname, '..', 'notebook')
});
/**
* Create the rspack ``shared`` configuration
* Create the webpack ``shared`` configuration
*/
function createShared(packageData) {
// Set up module federation sharing config
const shared = {};
const extensionPackages = packageData.jupyterlab.extensions;
// Make sure any resolutions are shared
for (let [pkg, requiredVersion] of Object.entries(packageData.resolutions)) {
@ -109,7 +58,7 @@ function createShared(packageData) {
for (let pkg of extensionPackages) {
if (!shared[pkg]) {
shared[pkg] = {
requiredVersion: require(`${pkg}/package.json`).version,
requiredVersion: require(`${pkg}/package.json`).version
};
}
}
@ -122,7 +71,7 @@ function createShared(packageData) {
let pkgShared = {};
let {
dependencies = {},
jupyterlab: { sharedPackages = {} } = {},
jupyterlab: { sharedPackages = {} } = {}
} = require(`${pkg}/package.json`);
for (let [dep, requiredVersion] of Object.entries(dependencies)) {
if (!shared[dep]) {
@ -205,70 +154,27 @@ if (process.argv.includes('--analyze')) {
extras.push(new BundleAnalyzerPlugin());
}
const htmlPlugins = [];
['consoles', 'edit', 'error', 'notebooks', 'terminals', 'tree'].forEach(
(name) => {
htmlPlugins.push(
new HtmlWebpackPlugin({
chunksSortMode: 'none',
template: path.join(
path.resolve('./templates'),
`${name}_template.html`
),
title: name,
filename: path.join(
path.resolve(__dirname, '..', 'notebook/templates'),
`${name}.html`
),
})
);
}
);
module.exports = [
merge(baseConfig, {
mode: 'development',
entry: ['./publicpath.js', './' + path.relative(__dirname, entryPoint)],
output: {
path: path.resolve(__dirname, '..', 'notebook/static/'),
publicPath: '{{page_config.fullStaticUrl}}/',
library: {
type: 'var',
name: ['_JUPYTERLAB', 'CORE_OUTPUT'],
},
filename: '[name].[contenthash].js',
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
jlab_core: {
test: /[\\/]node_modules[\\/]@(jupyterlab|jupyter-notebook|lumino(?!\/datagrid))[\\/]/,
name: 'notebook_core',
},
},
name: ['_JUPYTERLAB', 'CORE_OUTPUT']
},
},
resolve: {
fallback: { util: false },
filename: 'bundle.js'
},
plugins: [
...htmlPlugins,
new WPPlugin.JSONLicenseWebpackPlugin({
excludedPackageTest: (packageName) =>
packageName === '@jupyter-notebook/app',
}),
new ModuleFederationPlugin({
library: {
type: 'var',
name: ['_JUPYTERLAB', 'CORE_LIBRARY_FEDERATION'],
name: ['_JUPYTERLAB', 'CORE_LIBRARY_FEDERATION']
},
name: 'CORE_FEDERATION',
shared: createShared(data),
}),
],
}),
shared: createShared(data)
})
]
})
].concat(extras);
const logPath = path.join(buildDir, 'build_log.json');
fs.writeFileSync(logPath, JSON.stringify(module.exports, null, ' '));

@ -0,0 +1,17 @@
const base = require('./webpack.config');
const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin');
module.exports = [
{
...base[0],
bail: false,
watch: true,
plugins: [
...base[0].plugins,
new ExtraWatchWebpackPlugin({
files: ['../packages/_metapackage/tsconfig.tsbuildinfo']
})
]
},
...base.slice(1)
];

@ -1,12 +1,13 @@
name: notebook
channels:
- conda-forge
- conda-forge
dependencies:
- ipywidgets=8
- jupyterlab=4
- jupyterlab-language-pack-fr-FR
- matplotlib
- numpy
- nodejs=20
- python >=3.10,<3.11
- xeus-python
- ipywidgets=7.6
- jupyterlab=3
- jupyterlab-language-pack-fr-FR
- jupyterlab-link-share>=0.2
- matplotlib
- numpy
- nodejs
- python >=3.9,<3.10
- xeus-python

@ -199,7 +199,6 @@
"outputs": [],
"source": [
"from ipywidgets import IntSlider\n",
"\n",
"slider = IntSlider()\n",
"slider"
]
@ -229,15 +228,12 @@
"outputs": [],
"source": [
"from IPython.display import Latex\n",
"\n",
"Latex(\n",
" r\"\"\"\\begin{eqnarray}\n",
"Latex(r\"\"\"\\begin{eqnarray}\n",
"\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} & = \\frac{4\\pi}{c}\\vec{\\mathbf{j}} \\\\\n",
"\\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\\n",
"\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\\n",
"\\nabla \\cdot \\vec{\\mathbf{B}} & = 0\n",
"\\end{eqnarray}\"\"\"\n",
")"
"\\nabla \\cdot \\vec{\\mathbf{B}} & = 0 \n",
"\\end{eqnarray}\"\"\")"
]
},
{
@ -277,7 +273,8 @@
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import HTML, display\n",
"from IPython.display import HTML\n",
"from IPython.display import display\n",
"\n",
"s = \"\"\"<table>\n",
"<tr>\n",

@ -1,5 +1,6 @@
#!/bin/bash
set -euo pipefail
python -m pip install -e ".[dev,test]"
jlpm develop
python -m pip install -e .
jlpm && jlpm run build
jlpm run develop

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/buildutils",
"version": "7.6.0-alpha.0",
"version": "7.0.0-alpha.2",
"private": true,
"description": "Jupyter Notebook - Build Utilities",
"homepage": "https://github.com/jupyter/notebook",
@ -26,19 +26,18 @@
"scripts": {
"build": "tsc",
"clean": "rimraf lib && rimraf tsconfig.tsbuildinfo",
"prepublishOnly": "npm run build",
"watch": "tsc -w --listEmittedFiles"
},
"dependencies": {
"@jupyterlab/buildutils": "~4.6.0-alpha.0",
"@jupyterlab/buildutils": "^4.0.0-alpha.7",
"commander": "^6.2.0",
"fs-extra": "^9.1.0",
"semver": "^7.6.3",
"typescript": "~5.5.4"
"typescript": "~4.1.3"
},
"devDependencies": {
"@types/fs-extra": "^9.0.10",
"@types/node": "^22.13.4",
"@types/semver": "^7.5.8",
"rimraf": "^3.0.2"
"@types/node": "^14.6.1",
"rimraf": "~3.0.0"
}
}

@ -22,7 +22,7 @@ commander
const prefix = run(
'python -c "import sys; print(sys.prefix)"',
{
stdio: 'pipe',
stdio: 'pipe'
},
true
);
@ -43,10 +43,10 @@ commander
);
if (overwrite) {
try {
fs.removeSync(destDir);
console.log('Removed previous destination:', destDir);
fs.unlinkSync(destDir);
console.log('Removed previous symlink:', destDir);
} catch (e) {
console.info('Skip unlink', destDir);
console.info('Skip unlinkink', destDir);
}
}
console.log('Symlinking:', sourceDir, destDir);

@ -12,25 +12,18 @@ function ensureResolutions(): string[] {
const corePath = path.join(basePath, 'app', 'package.json');
const corePackage = fs.readJSONSync(corePath);
corePackage.jupyterlab.mimeExtensions = {};
corePackage.jupyterlab.linkedPackages = {};
corePackage.resolutions = {};
const packages = Object.keys(corePackage.dependencies).concat(
corePackage.jupyterlab.singletonPackages
);
packages.forEach(async (name) => {
let version = '';
try {
const data = require(`${name}/package.json`);
version = data.version;
} catch {
const modulePath = require.resolve(name);
const parentDir = path.dirname(path.dirname(modulePath));
const data = require(path.join(parentDir, 'package.json'));
version = data.version;
}
packages.forEach(name => {
const data = require(`${name}/package.json`);
// Insist on a restricted version in the yarn resolution.
corePackage.resolutions[name] = `~${version}`;
corePackage.resolutions[name] = `~${data.version}`;
});
// Write the package.json back to disk.

@ -1,86 +0,0 @@
import * as fs from 'fs-extra';
import * as semver from 'semver';
function convertPythonVersion(version: string): string {
return version
.replace('a', '-alpha')
.replace('b', '-beta')
.replace('rc', '-rc');
}
function extractVersionFromReleases(
releases: any,
versionTag: string,
currentVersion: string
): string | null {
const npmCurrentVersion = convertPythonVersion(currentVersion);
const isCurrentPreRelease = semver.prerelease(npmCurrentVersion) !== null;
if (versionTag === 'latest') {
// Find first version that is newer than current and matches pre-release criteria
const release = releases.find((r: any) => {
const version = r['tag_name'].substring(1); // Remove 'v' prefix for semver
const npmVersion = convertPythonVersion(version);
return (
(isCurrentPreRelease || !r['prerelease']) &&
semver.gte(npmVersion, npmCurrentVersion)
);
});
return release ? release['tag_name'] : null;
} else {
// Find exact version match
const release = releases.find((r: any) => r['tag_name'] === versionTag);
return release ? release['tag_name'] : null;
}
}
function extractCurrentJupyterLabVersion(): string {
const toml = fs.readFileSync('pyproject.toml', 'utf8');
const match = toml.match(/jupyterlab>=([^,]+)/);
if (!match) {
throw new Error('Could not find JupyterLab version in pyproject.toml');
}
return match[1];
}
async function findVersion(versionTag: string): Promise<string> {
const url = 'https://api.github.com/repos/jupyterlab/jupyterlab/releases';
const response = await fetch(url);
if (!response.ok) {
const error_message = `Failed to fetch package.json from ${url}. HTTP status code: ${response.status}`;
throw new Error(error_message);
}
const currentVersion = extractCurrentJupyterLabVersion();
const releases: any = await response.json();
const version: string | null = extractVersionFromReleases(
releases,
versionTag,
currentVersion
);
if (version === null) {
const error_message = 'Invalid release tag';
throw new Error(error_message);
}
return version.substring(1);
}
async function getLatestLabVersion(): Promise<void> {
const args: string[] = process.argv.slice(2);
if (args.length !== 2 || args[0] !== '--set-version') {
console.error('Usage: node script.js --set-version <version>');
process.exit(1);
}
const version_tag: string = args[1];
try {
const result: string = await findVersion(version_tag);
console.log(result);
} catch (error: any) {
console.error('Error:', error.message);
process.exit(1);
}
}
getLatestLabVersion();

@ -51,6 +51,9 @@ commander
if (options.indexOf(spec) === -1) {
throw new Error(`Version spec must be one of: ${options}`);
}
if (isFinal && spec === 'release') {
throw new Error('Use "major" or "minor" to switch back to alpha release');
}
if (isFinal && spec === 'build') {
throw new Error('Cannot increment a build on a final release');
}
@ -60,6 +63,7 @@ commander
// Handle dry runs.
if (opts.dryRun) {
utils.run(`bumpversion --dry-run --verbose ${spec}`);
return;
}
@ -67,7 +71,7 @@ commander
// just the Python version.
if (prev.indexOf('a') !== -1 && spec === 'major') {
// Bump the version.
utils.run(`hatch version ${spec}`);
utils.run(`bumpversion ${spec}`);
// Run the post-bump script.
postbump(commit);
@ -109,37 +113,7 @@ commander
}
// Bump the version.
let pySpec = spec;
if (spec === 'release') {
if (prev.indexOf('a') !== -1) {
pySpec = 'beta';
} else if (prev.indexOf('b') !== -1) {
pySpec = 'rc';
} else if (prev.indexOf('rc') !== -1) {
pySpec = 'release';
} else {
pySpec = 'alpha';
}
} else if (spec === 'build') {
if (prev.indexOf('a') !== -1) {
pySpec = 'a';
} else if (prev.indexOf('b') !== -1) {
pySpec = 'b';
} else if (prev.indexOf('rc') !== -1) {
pySpec = 'rc';
}
} else if (spec === 'major' || spec === 'minor') {
if (prev.indexOf('a') !== -1) {
pySpec = `${spec},beta`;
} else if (prev.indexOf('b') !== -1) {
pySpec = `${spec},rc`;
} else if (prev.indexOf('rc') !== -1) {
pySpec = `${spec},release`;
} else {
pySpec = `${spec},alpha`;
}
}
utils.run(`hatch version ${pySpec}`);
utils.run(`bumpversion ${spec} --allow-dirty`);
// Run the post-bump script.
postbump(commit);

@ -33,7 +33,10 @@ commander
utils.prebump();
// Patch the python version
utils.run('hatch version patch');
utils.run('bumpversion patch'); // switches to alpha
utils.run('bumpversion release --allow-dirty'); // switches to beta
utils.run('bumpversion release --allow-dirty'); // switches to rc.
utils.run('bumpversion release --allow-dirty'); // switches to final.
// Version the changed
let cmd =

@ -1,170 +0,0 @@
import fs from 'fs';
import path from 'path';
const PACKAGE_JSON_PATHS: string[] = [
'app/package.json',
'buildutils/package.json',
'package.json',
'packages/application-extension/package.json',
'packages/application/package.json',
'packages/console-extension/package.json',
'packages/docmanager-extension/package.json',
'packages/documentsearch-extension/package.json',
'packages/help-extension/package.json',
'packages/lab-extension/package.json',
'packages/notebook-extension/package.json',
'packages/terminal-extension/package.json',
'packages/tree-extension/package.json',
'packages/tree/package.json',
'packages/ui-components/package.json',
'ui-tests/package.json',
];
const DEPENDENCY_GROUP = '@jupyterlab';
interface IVersion {
major: number;
minor: number;
patch: number;
preRelease?: string;
}
function parseVersion(version: string): IVersion {
const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:(a|b|rc)(\d+))?$/);
if (!match) {
throw new Error(`Invalid version format: ${version}`);
}
const [, major, minor, patch, type, preVersion] = match;
const baseVersion = {
major: parseInt(major, 10),
minor: parseInt(minor, 10),
patch: parseInt(patch, 10),
};
if (type && preVersion) {
return {
...baseVersion,
preRelease: `${type}${preVersion}`,
};
}
return baseVersion;
}
function getVersionRange(version: IVersion): string {
const baseVersion = `${version.major}.${version.minor}.${version.patch}${
version.preRelease ?? ''
}`;
return `>=${baseVersion},<${version.major}.${version.minor + 1}`;
}
function updateVersionInFile(
filePath: string,
pattern: RegExp,
version: IVersion
): void {
const content = fs.readFileSync(filePath, 'utf-8');
const versionRange = getVersionRange(version);
const updatedContent = content.replace(pattern, `$1${versionRange}`);
fs.writeFileSync(filePath, updatedContent);
}
async function updatePackageJson(newVersion: string): Promise<void> {
const url = `https://raw.githubusercontent.com/jupyterlab/jupyterlab/v${newVersion}/jupyterlab/staging/package.json`;
const response = await fetch(url);
if (!response.ok) {
const errorMessage = `Failed to fetch package.json from ${url}. HTTP status code: ${response.status}`;
throw new Error(errorMessage);
}
// fetch the new galata version
const galataUrl = `https://raw.githubusercontent.com/jupyterlab/jupyterlab/v${newVersion}/galata/package.json`;
const galataResponse = await fetch(galataUrl);
if (!galataResponse.ok) {
const errorMessage = `Failed to fetch galata/package.json from ${galataUrl}. HTTP status code: ${galataResponse.status}`;
throw new Error(errorMessage);
}
const newPackageJson = await response.json();
const galataPackageJson = await galataResponse.json();
for (const packageJsonPath of PACKAGE_JSON_PATHS) {
const filePath: string = path.resolve(packageJsonPath);
const existingPackageJson = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
const newDependencies = {
...newPackageJson.devDependencies,
...newPackageJson.resolutions,
[galataPackageJson.name]: galataPackageJson.version,
};
updateDependencyVersion(existingPackageJson, newDependencies);
fs.writeFileSync(
filePath,
JSON.stringify(existingPackageJson, null, 2) + '\n'
);
}
}
function updateDependencyVersion(existingJson: any, newJson: any): void {
if (!existingJson) {
return;
}
const sectionPaths: string[] = [
'resolutions',
'dependencies',
'devDependencies',
];
for (const section of sectionPaths) {
if (!existingJson[section]) {
continue;
}
const updated = existingJson[section];
for (const [pkg, version] of Object.entries<string>(
existingJson[section]
)) {
if (pkg.startsWith(DEPENDENCY_GROUP) && pkg in newJson) {
if (version[0] === '^' || version[0] === '~') {
updated[pkg] = version[0] + absoluteVersion(newJson[pkg]);
} else {
updated[pkg] = absoluteVersion(newJson[pkg]);
}
}
}
}
}
function absoluteVersion(version: string): string {
if (version.length > 0 && (version[0] === '^' || version[0] === '~')) {
return version.substring(1);
}
return version;
}
const versionPattern = /(jupyterlab)(>=[\d.]+(?:[a|b|rc]\d+)?,<[\d.]+)/g;
const FILES_TO_UPDATE = ['pyproject.toml', '.pre-commit-config.yaml'];
async function upgradeLabDependencies(): Promise<void> {
const args: string[] = process.argv.slice(2);
if (args.length < 2) {
throw new Error('Please provide the set-version flag and version');
}
const version = parseVersion(args[1]);
await updatePackageJson(args[1]); // Keep original string version for package.json
for (const file of FILES_TO_UPDATE) {
updateVersionInFile(path.resolve(file), versionPattern, version);
}
}
upgradeLabDependencies();

@ -4,7 +4,7 @@ import { run } from '@jupyterlab/buildutils';
* Get the current version of notebook
*/
export function getPythonVersion(): string {
const cmd = 'hatch version';
const cmd = 'python setup.py --version';
const lines = run(cmd, { stdio: 'pipe' }, true).split('\n');
return lines[lines.length - 1];
}

@ -0,0 +1,9 @@
coverage:
status:
project:
default:
target: auto
threshold: 10
patch:
default:
target: 0%

@ -0,0 +1,5 @@
sphinx>=1.3.6
pydata-sphinx-theme
nbsphinx
sphinxcontrib_github_alt
myst_parser

@ -0,0 +1,20 @@
name: notebook_docs
channels:
- conda-forge
dependencies:
- python=3.8
- pydata-sphinx-theme
- jinja2
- tornado
- nbformat
- jupyter_client
- ipykernel
- pip
- sphinx
- terminado
- myst-parser
- pip:
- nbsphinx
- Send2Trash
- prometheus_client
- sphinxcontrib_github_alt

@ -1,14 +1,14 @@
exports.handlers = {
newDoclet: function (e) {
newDoclet: function(e) {
// e.doclet will refer to the newly created doclet
// you can read and modify properties of that doclet if you wish
if (typeof e.doclet.name === 'string') {
if (e.doclet.name[0] === '_') {
if (e.doclet.name[0] == '_') {
console.log(
'Private method "' + e.doclet.longname + '" not documented.'
);
e.doclet.memberof = '<anonymous>';
}
}
},
}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@ -0,0 +1,397 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg3390"
version="1.1"
inkscape:version="0.91 r13725"
width="705"
height="243"
viewBox="0 0 705 243"
sodipodi:docname="blank_notebook_ui.svg">
<metadata
id="metadata3396">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3394" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1855"
inkscape:window-height="1176"
id="namedview3392"
showgrid="false"
inkscape:zoom="0.86307147"
inkscape:cx="437.41347"
inkscape:cy="67.074282"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg3390" />
<image
width="705"
height="243"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAsEAAADzCAIAAADo/lysAAAAA3NCSVQICAjb4U/gAAAAGXRFWHRT
b2Z0d2FyZQBnbm9tZS1zY3JlZW5zaG907wO/PgAAIABJREFUeJzt3X98E/UdP/B30jRJpbHBFpqW
ssYN26jtKBYkBV3jplA3kCo4Cuq3YV+lVUGr4Ky4jbJNqMqPCkwKui9xE1ofUMmASUE24py0CJVo
qw2F2VSxjdKaYFvyo0nu+8e1IW0v/ZGmv+jr+eDBo71c7j73uUvvdZ/P5y48hmEIAAAAoJ/4w10A
AAAAGJWQIQAAAMAfyBAAAADgD2QIAAAA8AcyBAAAAPhDMJA3u91uPr9bCmHcxLiv/srjE4/PMAyP
x6urqystPTp+/PgFC+4TiUQDWTUAAAAMrwG1Q3QKEAxDbhcREY9PfMHVfzw+EfEYNzHM0aNHL168
WFlZWVX1ORG53W7u5QIAAMCI5387hNPpvHTpUlRUFBExbhePH0S8IMZhZb753FlvYFrNxOPxQ8cH
Rd3Mm3QLL1hMRBHhN9TXNzgcDqlUSkQ8Hi9QmzF42BaU4S4FAADAiMPz+xlTb7/9dvUX1b/81S9n
z5pFPJ675XtX+d62s4fIfFEcRHw+j4hcbsbu5vFu+FHQtPkC5VJeSNiZ0x+Pv+GGKVOmBHQrBpfN
ZnO73dddd91wFwQAAGAE8b8dQiAQ8Pg8xu0iHs9e9S/e0VeFly8yLrebyOnmkbs9mvAZd9D3xmDd
dsdn/+T/as2M22cFqOR95XdDAjvao6ysbO/evXfeeeevf/1rl8sVFBQU8BICAACMRv5niEWLFv38
LtXESJnj1DtBh/8oCOZb21wuQQgvNJyRRpEwhIgY+xXG0uBs/d7ltIl/qLNrHnOm/0k84wFyu6n7
YMxAY0/5bIBgm1v8CBPV1dU//PCDr9aaLqNKuQeZEhH6RAAA4JozgHaIoKCJkbK2qveFR/98Jeg6
p+LnwVNmi2Kn8cMiSSD0zMa02emH75zGT2znP3J/8a/r3vuD6/qJQfF3EMPQIJ9Tg4KC3G633W7n
8/nsbSD9OpGzc4aEhLjdbrb5oXsjBJsY2FUEBwfz+Xxfq+DxeDabTSAQCAQDuhcGAABghPB/PAQR
uc31V7YtFP50TtCdjwaFT+59/sa6Nt3OtuoPx+W8y5NM8DWb3W5/7bXX7Hb7E088ER4eTkQ2m23T
pk1tbW1PPfXUDTfcQB1poLKysqSk5KabbnrooYfYNgC9Xl9SUnL33Xenpqbu27fv+PHjly5dGjdu
3G233bZo0aLJkyezs+3du/fLL7+88847U1NT2Sns/59++unBgwcjIyOXL1+u1+vfffddk8nU1NQU
Hh4eHR3tcDhUKtWcOXOcTqdAIHC5XP/85z+PHz/+1VdfBQcHT5s2bf78+YmJiZ42j7Nnzx48ePDe
e+9NSEh44403Tp069cgjj9x77739rWdLsXL8klNTdzfo1bIuLxly5Te/bFpwwqJVifu7WLLps+XT
dn4bv6HWkCvnWqcx66yxMKn/C/aUTLyj1pDdddEAAHBtGMA1McM4P3tPtOAPwVPvJWIfC8EQj8/R
usAwxLiJx+dHxIoWrQ86e6jt0/eEs/8PEXE2Rbjd7rKyMh6PZ7VaPVNOnz7N5/PtdjsRMQzDZohL
ly6dP3/e6XR63ms2m2tra6urq0+fPn369OnJkydPmjTJYDCUl5d/9tlnv//973/84x8TUWhoaHV1
dWNj45133sm2JbCNB//+979ramomTZpERK2trfX19Var1e12t7a2mkymtra21tZWdmar1frKK69U
V1fHxsY+8MAD33333UcffXT27Nnf/va3M2bMYEOG2Wy+cOHCl19++f7773/++ecul8vlcvlf4YFg
M2jyNBZVTk6ajIhIKiWyiMVcLwEAAPRsABnC1SZIms8PiyTGTcQjHp989RLweMQLIiJiGCJGMG2+
+/K35HZSULCvZY8bN85qtXp3Clx33XUOh4OdwuO1N58IBAK32y0WX71SFgqFVqv1P//5j0AgWLt2
7S233EJEjY2N27ZtMxgMf/nLX15++WWBQHDXXXeVlJR8/fXX58+fj4+PZ0dOtLS0fPLJJ3a7fe7c
uUR0++23p6Sk7Nmzp7S09L777vv1r3/tcDiEQiHDMEFBQXv27Dl37tyCBQuWLFnCrjotLe1Pf/pT
YWFhQkICWySxWGyz2U6cOHHlypXHHnvstttu8y7qsLDpC19+2WjJyE6TiUmclG9g8jlfAgAA6M0A
BjYKhO0BgrPtgROPRzw+MW5+WGQPAYKI3G53lydQeU/x9L8wDNNlTrZXwmq1PvXUU7fccgs7Q0RE
xJNPPhkUFFRbW1tZWUlEEolEqVSKRKKTJ09Sx9OuPvvsM7vdfvPNN7PtEHw+n8/n83g89n8ejycU
CtkfLl26dOzYsYiICDZAsOVJSEi4/fbb2SDiST9Op7OxsfE3v/nNXXfdFRYWhqdzAgDANWNgN0ew
nRf9xeP3dxAGe+bu45x8Pl8mk02bNs3tdrO/ut3uiRMnJicni8Vig8HAzpmammqz2T766CN2qCMR
ffzxx3w+PzU1lYhcLpdnjZ6M4na72c6IyspKPp+fnJzscDiuXLnicDhaW1vtdvtPfvITsVhcW1vL
zs+mEKlUOnv2bJfLNZChJ31j0Sp5PHm+waTLT1dIeTweTyxTqgv1FiIiMmmSeOOXnCL6due0EJ4s
R2+zaJU8njhDZ+v+Uvdl6woylAqZmMfjiWVJ6blaY+d5TKW56UlyKY8nlilU6gKdqfsiAADgmjKw
DOHvjRX9vcvRMwCi17ezp+3w8PCgoCDPbZbsyXvSpEk8Hs9sNrNTFArFjTfe+MMPP3z22Wc8Hu+H
H344ffo0j8ebPn06EXluCu2yOvbnb775xu12a7XajIyMhx9+OCMj45FHHsnIyHjrrbecTud3333n
XZ7IyEihUOi9wMFlKc1OSiuwqHK3bNmQmWQ79dbjSrXWQkSyNM2JoqdjiURztxw5oc1RXO2y6OEl
IiKboVAlu+uZd0yytOznn386XW78x8v336gqMNg6Xi9Qyu99+R8GsTLz6ew0haX4mbvSCut8ldCm
SxdLM8r9DRm2crVMzhVziDpFHalcla1h85OxUCFWlfq/wgyZPNfg57vJVq6W8hT5Rt8v+96cPrPo
cpQynliltQxsOcPCVpomVRQYh7sYRESWUrUqd6A7I6D6XDkDO8gHyKbLVuX4/ZGGUWw03Wfo3YXR
fSLnr97YsQhssHA6ncHBwb/4xS/+9re/ffjhh7fffntlZaXL5Zo9e/b111/P5hVPaum+TKfTyefz
k5KSpkyZ0tbW5gkHbHCJi4vzfu9QP5bq8geG9BMGjUpKRJSdJpVPe620WG9LV4llSao0pYxes8lV
KlWSmOjq+aaHl4hMxerHP6DUHbWl2XI2XOTn5iZNe/kZdXFGuVpGpmL1M6fsYQsOGLTp7HjMfG2G
4v537EO30SyjJi1pmV61oVCrSZKRsTQ/e5kyg4yl6qEuSCdiRY6myKQY1JGqNmNxsUF5xKRNkw7m
aq51tvK8XFN2qZ+3Io1lYlVeRl56gaE8VzHcRYGhNUK/+7vLaZvP5wcFBTEM47lTgzpGSLCPZOjy
Xu87Naij8aCxsZGIxo8f75mSkpJCRB9//LHVaj179izDMD/72c+o8wOpODOKRCIRCATTpk176KGH
1Gp1ZoeHH3546dKl06dPH9avE5ual6fqOJOIFWkKIhrQ9YGptPAUidJy06U2SzubPDtvJtGpYr2N
yFKuOUU0Nb8g3XOalKXn50/t73qMxWqlTMzj8XhSRVp+uYVdd45KzvafKHO0JiIyFqhUb31b95pS
kaHrvFmW0pwcnWJHuTY3XamQyxWqbI12i6K8UGskIiKbQaNOkol5PKkiQ9M+SV/ITuLJlNnF7a0q
Jl1umlzK4/GkivSC8s6X9TZ9vlIqyyg2Edl06bKkAg1bPK9ZTbr8NIWUbQbJYTt8LOW56nwjERkL
k2QZxZpsJfuejGJjl82x6bNlPM4mD67KubqHNGmqnd9e/se9ivRSC9d2GQsU4qRCExGRIVfO4yUV
GomIDPlycZLG1GlR3Sq8fxXFsfkcW01ENkNxtpLdHel5Oouth7X3Wg8db5MmqQsLVVJlsYW7JL2x
lOZr5TlpMiJDrlzmOb4MuXJpus7mY0O4y9ytnCaNUny1k9BYmCRW5Bt81S1n5XTe5dxHKcdBzlFj
3BvCXY1cxePcZFlGtlSTp0NTxFgzQjNElwEQAoFAKpUKBIJvv/2WiJxOJ5se6urq2BEP1HF2ZwdR
Xrx40WKxsHOybQYul4u95yIuLo6I2OQxfvz4lJQUhmHKysoqKyuvv/76hIQE6mirYHMA2znSZfDm
lClTbDbbf/7zH/Z2Tbvd7nA4HA4HWzDvp1UOw7MpRfLAXvLaTOVGIvs/7o0a7+XGJaeIyGSyEJkM
RqJIpbLTWmVKZWS/VmMqzlCXygvKG8zm6mKV4YXsYhNZSrMzNOK88gZzgy5XXKjOLbeRPEeny4yM
fbrcUNz5kRg2vUZnU+VlyL2mKXL0lnL2ARX2U3m6tGKjxVyWJ9Xm5JbbyFKqVuUYMooNZnN1YVLp
ElVOuY2MhelpGll+udlcXZxuzE2/2q5tsxgK0lQFssLy4gx2Uy2fPpNnyS41mWu16abcNLXWQiZN
Rlo+5ZQ2mM3l+XJtRlpB5zxg+/ad3FKlxsAWIztXJ+u0OWJ5dmFRYbengHBWjndlq0t1WbGRmWVG
bZqUa7ukaekyQ3G5hchUrjMRGYr1FiJTebFJrlZ5rY2rwqkfFeVj87tttc2mz01bolUU6M1mfaFS
V3DK7nPtvdaDsSAtXSvP15vN+gJZ4eMfXCbyWZIeWcoLy+VqZQ8tOd03hLvMHOWUpeUkWbQa9iRs
LC00KHIyFNx1y1k5nfg6Srsf5D6OnO4bwl2NXMXztZukqgyprhD9GWNNIDJEv4YK9m1mdgAE+7PL
5RIIBD/5yU8EAsG//vUvIgoODhYIBJ9//vnRo0fb2trYE7bntO12u20221//+le32+15LmRRUVFj
Y+OkSZM8KYFd/l133eVyufbt2/fdd9/dddddQUFBXR7hIBaLXS7Xl19+yT6Jku2YuPXWWydPnvzV
V1+VlJQEBQWJRCKhUCgUCgUCgSdz9KNOAmxQGmIjM3cfOdGNJnBN57K0YoNek5Ekk4qlUrlUZLFY
SExks9lMJptYpswpNRkLlD1sm81ivCxV+L4vNT4vP0MhFkuV6Rlym8lCltI8rTRPk6uSS6WK9ALN
Ypu2UP9pcb4+qSA/QyGVKtLytMX5ae0Pz7DpC9KSnilPK9Z4hRTR3IKCDIVUKlflFWaLS/N1n2nz
y+X5hdlKmVSqyCgoUBoLCrt0rsfn5KvZYqjltm4DT6VJ6Rlpim6VylU5vnBtl0GWrpLqi/U2i15r
THo6U2YoNtgs+mKjLD1N7vVezgrve0UZfW5+l6226QuKTXML2ysvV5MT63PtvdWDzVBYYFB69kPB
4jCinkrim81QbJByVH4nXXcfd5m59pdMlaM0aYuNxEaIpJx0OXfdnjrFVTneDD6O0u4Hue8jp+se
4axGzl1PvnaTNEkpLi/tU4sPXDv8zxBMm8154RQREY9Hblfv4YBhyO1ih2E6L5STq83XjJ6HQHhP
vOeee2w22yeffPL73//+nXfe2bx58+9+97vbbrvN5XKxHRyeRoKgoKDw8PAzZ848++yzJSUlBw8e
XLdu3cGDBwUCweOPPx4cHMye4NnMwaaBS5cuBQcHs3dkeLII+4NCobDZbB9//PFrr722Z8+empoa
IgoODn7iiSdCQkJKSkrWrFlz4MCB0tLSkpKSV155ZfPmzeTVKMLj8QberyGWyUVERl33T6fFUF5H
JOvhzDlwYlmSjMhikSlVXpQKMZFYKhUTyRRyom/LyztdGlv05d/2c0Wm0ty0JIVcoUzP05rsRETi
NI2uMEmXowjhyZLU+T3f6yGWSkU2Y5dzq0WvLS412IhIJOvSPGMymux1L9wsZknveueyxfSdRW+R
KuTtpxGxPF2d3j689NujpTL1XLE2t73dt71mFJ5ZlXKynL9osJBc3rEesVwh7Vqiq8UQ9yvsda8c
n3NybJdFnKRWUrlWb9DqZelqtZL0WoO+WC9O69Rsw13hfa4om8XX5nfbaovJIlPIOypAppSJfK29
13owGSxXo6NYrpSJiHyXpAc2k9EilXdrA+qk24b4KjPH/pKpspWmYo3BZtQWGpU56TIfdXv5Mlfl
eBfU51Ha7SDnLgnXhnBVo49jydduEksVUouBqwcKrmH+ZwhesNjdVGcr/q37yg/EDyIejxiG3E5i
3IzbTQzD9iswbhe5ne3fjsEPcrear+x5lrHUU1Aw+Ti5ut1u9hzMXvSz5/LExMQnnngiLCzsiy++
KCkpKS8vz8zMfPLJJz1PbfIkDz6fHxMTk5eXxzBMcXHx3/72t08//TQuLu4Pf/iDQqHwvr+DfbTU
zJkzxWLxjBkzJk2a1P3uj1tvvfX+++8XCAQffvjhoUOH6urq2DfedNNNa9eunTp16hdffLF37943
33yzqKiooqIiNDTUsxC2iWLgz5USJ2Wnh9HltzJySr0/oDaDRq3+gCg2Qz2o45hkaeqpZP9HTv7V
CzmbvkCVcldant5GRFJldirRp7m5VzuwLaW5uZ/2ayUWbYYqj3K0eqNBX16clxRGRGQzGsWqvFKD
zdpQmivTZqh6un1BrFArbaV5nXrRjcXq+9WF3H/VpDKZaOqOWls7q7nBWHxfpFxqMXr+KBq1BZr2
vubIrNLiQk2hSp9ztR/BZjJ0nJhsRr2JpJNjFFIyGj2vGw0WsTwALTWcleML13alicVJ6iRLqUaj
I6VKkZShMJVqNDpSZXS+A4ezwvtcUWJpnzdfKpeaDJ5MbDKY7L7W3ms9SOVii6GjJDaT3mRnz2YD
3RE2TyeWyeA7fnCW2cf+kqXlKE1aja5YY1Tmsi14XHU7ZyJX5XgRS30dpd30/cjhqkbuY4n686mE
ax/jN7ebcbtbty60v/pze3mxu7mxl9l/+M5x8m37y6mtry9tfzvHIt1ut/vbb7+9//77H3zwQYvF
4v0SwzCXL1/W6/VVVVXNzc3s9MuXL7e0tDAMwz6Aoby8fOHChS+++CL76v/+97+zZ89evHjReyEe
LpfL7XY///zzixYtqqqq8iyku6+++uqTTz753//+53A4uiyqqanp888//+yzz4xGY2trq/e7HA7H
5cuXu0z0j/lIFtuiGTZ17uLMrMzFC1LjRUREotQtZ62euQ7MJBItPmG9+kbrkVQi0YKOSeYDM4ko
dvGG3QfOmjvP3+WloplEkVnssq1nn59KRBQ5c/HTzz//dObcWCISzd1d27GS6i0zRUQkip+b+fTT
WQumhhFFTg0jit9Ry3RnPbFAFLbgSIPZw2ptKJpJkVlHas3m2hO7s+KJIrPKrA07plLk4qLqBrO5
9sSGmSK2PNayzMjIzDJr9+VWb5hKFLt4y5GztQ0N1WVFWVNFNHVDtZWp3REvSj3S/o7aLewvDQfm
hkUu2H22wWquLdsxNyxs8QkzU71lqig2s6jabK49sSU1LGzxCStjLVscGft8NcMwTO2OmaKwBUfM
7EYQxbcX+fmZorC5B8xMw+6ZorAFO842WM3VRZmxovhOa+9UjIYdU0WpR6ydN8d89kDRkWpzlw3j
rJzOm342K7ZjIZzbxTANu2cSkWjuETPDNOyY6vm504o4K7zPFdXL5ntttfXs87EUm1lUbbY2lG1J
FRHFb6nlXnuv9VC9IV4Um3mg2mxtOLFhpohoZpGPHdEza1lmZPyGavYY2RFPkZkHaq1Wc9mGmSL2
E8S1IZxl9rm/zAdSRaLYsMirH1GuuuWsnE5F5ax8roOcuyScxyF3NXIUz+dusp59Ojb26bO91TNc
WwaWIRjGZTG1rv8Z86eEH/50h23PM44PNU7DB85vql2NX7ka65wXv2j74oTjg/9n/ftTP/xxFvPn
xNb8X7SnDa4M4XQ6GYbR6/UPPvjgypUr2V89upzgu/zKzlxeXr5o0aLf/e533dMA59u1Wu2vf/3r
P/zhD0y3hOG1odzTfQWOwdJQtiMrdWpspIiIKCwyfuaC5w90/sPYe4ZgzEeypoYREcVvqO4yf+eX
vDMEwzDW2iPPL5gaG0ZEFBY7dfGGI7Vd/r57Xg+LT128paz2QGpPGaJzkhUtPmE+u2VurIiIIqcu
2HKgKDNWFJlZZj67Y0F8WHt4WrzlLHvKaziwOFZEYZ22k7OYMzN3lJkZhvvPK8Mw5rIt7YsPm7p4
R/u21h54OjVWRERh8Qu2lJkZxjtDMEz1hniKzDxhtZ5YEBab+Xzm1EgiCoufu6GsvXAnNsyNDyMi
UWzq0wdqrd5r5/zb7b051rNZkeRZlddmcVWOtdMMVzOEj+1iarfEE03d3cAwDFP9fCxRalHXsMJY
OSu8rxXVy+Z32mprdVHmzEgRUVj8gg07FsdO3VLra+291YO19kDWzEgiUeTMp3fvmBmWesDMXZJe
mA/MjWTfyzDmsudTI4koLDb1+aItMyN9ZQjuMvvcX+YDc0UU1mnfcdUtV+V0xlH5nAc5Z0kM3HuE
sxo5iudrNzXsnhnJ9aGEa9qAvreTYdxEfNd3/3O9s0pk+R853W6GrE7GzRewz6/kMW6e2xki4PF5
REF8e3h8cMZmfsSPevji78bGxq1bt54/f37evHmeb+P0WiPDdNx46bn3kv2BnfPUqVObN2+Oj4//
4x//SB2DJHw95vLIkSN//etfg4ODN2zYIJfLu6yr85a2r7f7DJ6XOFfE9OfbxmEUsenSZdnKcgPu
hx9upnKdUa5Usn35hnyFyqAxanoafeuTRZuWpMnRj82HbAy4Gi3aNGVxrr7Yj28QhlFsQPdl8Hh8
Ho8EkT8R/t/djp8ubHUFEVEwn4LcziCXI8jl4LudwXwiolZ3sGPa4uDf/LWHAGG3219//fVnnnnm
/PnzMpls/vz51O2czQ53YL/AwjOF/YE9kbPPqHY4HO2b13lmz2xNTU1//vOf2Xs3srOz5XI5wzC+
AoT3ent4qcuKuhQPAAaDzVSsVqUX6i1ENmNxXoFJ2WWQR99J0/LSjAWlY3JU4ICr0aQtsKjzECDG
nAE9p9LldNXU1DBuV/wttwrT84KmL3KcPeS6UM58/zXjaiMinkDoDP8RMyVFnDQvaNItRMS43Tzf
1/plZWV8Pj8tLS09Pf3666/vV2HYs3VYWFhMTMyNN97Y82x8Pr+iokImk/3mN7+ZMWNGDy0QADCS
iZPytQXqDNX4Zy6LwmJVudpi/5sRxMr8fFl6gT49f8w9qnKA1Wgrz9MkFZSiUW7s8b8vg2EY3Qld
fX09wzCREyfefc8vePwgIiK3k2lpYlrNDEP80Bt4oeHUPt1NPF7PX7Fx+fJlz40MfvcCuFwuziaB
Ls6dOxcTEzNu3Dh0NwAAAPjB/3aItra2L7/8ko0g//vyyzsdPxOL+IzbxQsS8K6P5F3v9ZRCt4uI
R3240A8LCyMi9vs2/T6v9/H7KeLj46ljFIV/KwIAABjL/D99CgSCmJgYsVgsEomiJ0ULhULi8XhB
AiLqeDKEu/3BU/ygvgQI6his0JdWhIFj77ZAgAAAAPDPgO7LsFqtn336mcvl+unUn3o/WwkAAACu
eQPKEAAAADBmoSUfAAAA/IEMAQAAAP5AhgAAAAB/IEMAAACAP5AhAAAAwB/IEAAAAOAPZAgAAADw
BzIEAAAA+AMZAgAAAPwhMJlMw10GAAAAGH368axrk8k0fvz4QS0NAAAAjBboywAAAAB/IEMAAACA
P5AhAAAAwB/IEAAAAOAPZAgAAADwBzIEAAAA+AMZAgAAAPyBDAEAAAD+QIYAAAAAfyBDAAAAgD+Q
IQAAAMAfQXl5eX2ctaWlJSQkpD8Lv/T+llf+VqrzdqZFcdt1xzduPk5JM2NtZdsKdDcop4YH9b/g
A8JRMJ1BOn1GlKjTbG3n//7K3isJt1HpK2yBBV8f2Pz/jD+efpNkEEtsPr0jf69JcXv81ZWwk6bc
/uMfDraXpF/7YXBZK9/489++U9we2EppG4qqZllry7T7te+9996xf5frjRax7EdRkmDuWc0dR+wP
g3/otp3/+/pdX/5YeXMYu47m84de33rQKL1FERUSuLWah2BDave9sv2zmFmJ4zvW0dZwZPNG3fXK
5Eiueh6CIgFAgAgGewWyeSvUCaFeKwwJcSrTF7VEhBK1DPbKe9K1YCTwdV4Ojugo8JAYr1DGHC4t
N6XdP7n9L6z5whlTaEK6LDjYOaQlGQvMZ/9eqDXJ756XkS4LJcuF/x7Wvrmfch6ZJhnuknXSXH3g
zf3GmIzsB28eWQUDgDFt0DOEQBzatfWi5eJxbVVa7k0TvKa1NZw+rNVVmVqcoTHT09LTEif4uBIc
zIIREbVdqizVluovtggiFNMVNicRkY0tcMQFjUbf4qQ3t7c8vOLBGwetgBLFHfLD2vKLbZPZdZgN
5SZp0qKo4E5V163GBGe2bdcrcx6fIaFL72/Z/l/xvJzHZ4ynSx9uKaxS5Tw+FCdF8+kdbxrvuFtc
rtNftAgiEuY9/GDieGo+f2T/4TNGi1MQGjN9Xsa97FmQY4+bT+/QGO9QCXSldeOu/6GuxTXoVW09
X1pqjJi3YskM9gtpx8+4P8NpevOMwTxtxvihPyZ9MFfue1NrUmQ8Ov+mjp3YY+1dnLJwhvEfX3fb
EcPwKetVD0Vqqy0qKJXfLTfozhgtggiFKj09ZfIIaoADgJEyHsJ6XqspbUxYtCI3d8U82YX9mtKv
24alIG0Nx9/eb4hIy87NzZ4XYyy/6PR6cXyKWp0UKlU+OphnNSKiEPkdU8hQbrQSEZHZcKYxQjl9
QqdZOGpMPEUR2lh10UrUfNHYQtRYZbISNV+sapEmyYfq4tXZUnX8Qkz6itzcR1Viw+HjtW3W84f3
6wWqR1fnrlbfITijPf51G3f524hgbQJLAAAeBklEQVSILIZSvfiOjMUP/mbZEFR1m0lvdMpVCd7f
aD8h5fEXHpsxfqQck87Gs0WF+y/IvQNEb7W36I7xQd13xEjZIm+9FclmKtXZpj+8OjcnQ9Fy/G1t
tXW4SgoAnAa9HeLi/vy1+zt+kU5/dMX8yd3msV7QGcSq7DtvHE9EN6elJ1TtP2NKmzx5UE/UnQpG
JFVmr7g3wlRe1TJlXlrihBCiG+9MV57ZbhjMMvgSIlcqBG+XG6033RxyqeqMRaZUjO80A1eNNd49
XS4+U2VqkzsNFpkyqaWqqrFNbquyhCqmjOdez2CIUN49bUIw0WRFkvR4lZMERE6ns6XFKYianPLw
6iRnSLCvPa4iJ4Uq5907bQJR29dDUFanzWITx4RyfQh8lXBo2Qz7NRekMqnNqL9ovemmkJ7LdrX2
zBe774jh3CKn06D589rO02L6UsmCKWntn0bVvOn6N/9rtN58M5oiAEaOQc8QEWnZDyvEHWsTj+fK
BS2WFqfl+PY/6djSOJ1OwRTbkBasvWhtthZbaIS0o1JCY0IFw5IhKDhGmSB+878XmqfIDGcsMlWX
CMFdYwJZUgxpDaZGpylUoUoyVR02NJpaTIIpd0uHruSC0I7hGgL24Aq+KV09T6cr3X78bbEsIUml
Ut0cEuxzjwukQznaQyAWC5yWLoeataH6QktExHAck105SSBPz37wZmfZG9v3769c8UiihKiHz4t3
7XXbEcPyKesojECenp0e0/HBcjbqNG839qFIglBZRHtkCJbGSOmCxUaEDAEwcgx6hhCHSseP7+VT
Lw4NFcjuWPF4e6d0m7XZRr5Gxg9uwcRScUujxUlRwURELY0tTo53DoXgKGVSaGG5wSg/0xJz95Su
XRHcNRZsTZLZjuv1RDHpEbKIiBadXm8jeXrEcPZ6t5ktArnqkWn3tjU3GP67f7/G9mjO/FDO8ttO
E5Fg0A/Jq4IjkmKcWp2h+cZETw2bq7TFpVL1CgVnCRuHrnBEJBBPUU6REFFKxrwLBdr9p2OWzRjv
a+/3Vns+3jVEWyQOlY73XEC02cR9K5KzpdFipQkhRNRmMbWQOFRMADCCjIjxEJIpd8gtutKzDc1t
VvPXp4sLtpeaBr3j02mzWb21tREFy6YnhV4oLa28ZG1r/rrssM7C9b6hyRUTpiulF0u15Ta5sluE
8FVjITFJEY1nzlgiFBHBITEJUlO5vkWWJBvWgXO2C9rCNw9XXmp2CsShHaeAvu3xwa9qiWKeKsK4
/819ZecbzM3Nl76uPFRcapKp7o4ZPxzHZA8FnZa+aIrpcPGHl9r8/bwMy6dsoEVyGkqPnzdbreZa
3eFym/yOKWiEABhRhvCirweSmxc9bNFqNRu1NhLLEu5Wp9846H8rTIcL8g97T5jy8O8euSlK9fCi
Fm1pYf5+QYTijrQEyxnvWYKlCrlg/5sbnerVgzyskojGJ9whK9U2TlHKOerCR41J5AkRdFGQIAsh
IvkUKZmkSTHD+2dXkpQ+78L+w9s32ojEsoS7H747KpgomKv8Zq+3DVFVB0+489Ecma70+GFNqcVG
YmmMIu3RtBkTgol6K+EQk9ycnpG0XfP2cfmKeyf7VTbOY2YYt6gPRRJIkxTO42/mm1rEEVNUDy/C
WAiAEYbHMEwfZzWZTOPHD+HgPAAYw9pqizYejnl05Z0Tep8XAIbHiOjLAAAAgFEHGQIAAAD8gb4M
AAAA8AfaIQAAAMAfyBAAAADgD2QIAAAA8AcyBAAAAPgDGQIAAAD80Y8MwePx3G734BUFAAAARpF+
3Ntpt9svX76MGAEAAADUrwwBAAAA4IHxEAAAAOAPZAgAAADwBzIEAAAA+AMZAgAAAPwh6Puszc3N
RqPR4XAEat1CoVAul0skksFbyxCsYlQb7fUz2ss/1nTZXxaL5ZtvvrHZbMNbqlFKLBbHxMSEhYX5
mmHwPgicnzsYm/qRIYxG45QpU0JCQgK1bqvVeuHChcTExMFbyxCswltFRUVycnLAFzt4Sx7K+hmM
TRji/RsQg1EPo2WZXfZXXV3d5MmTBYJ+/BUaa67zfRgb62q/+uqrLgd/pxkG7YPA+bmDsakfn16H
wxHYwzEkJKR7Rg7sWoZgFaPaaK+f0V7+sabL/nI6nSEhIQKBgMfjDWOpRjQf994bjbX79u2bMzet
h7cO3geB83MHYxOuAABg2AgEguDg4OEuxcjlbGsjIqv1Spfp+/btG47iAHSFMZUAMGzQAgEwqiFD
AAAAgD9GaV+GvfFcTYNDEhUnjxANd1n6p/5o3sp1h+va+xKFyWsP7pwfMYDl2Svz5i473ML1Umjq
1kObZo3KodN2u10kCvyetdup81Kb641NwqgRcxA11xvrm+0+XxaFywdYVHtzY7NdJImQDHApdlGn
JXSbAABjRCAyhL0y775lh5u6To5NSZHHqfNWJgf8LGavXLdo2bEWoqgV+w+p5YFdduO5mjqHJHZQ
0kn9oVVL131AwvAH9hxcEy8yapauamohGkiGoOaGFqLQeTv3r4q7WmDjrqXLihoamuxEg5gh7PVH
N236IHrpC+pA7uNm3aq5qz9wUGzm/r0r5QHcCfbKTcs08evXL+xYqP3kmvueKmvfGYFbj7/sJ1ff
91RFT3P4f7w3nzu0bfOuwxUNbHgNjZujXvHskmSHbtexCHU/d5+9Ys3Swwt3rld1HLf1h1evMS7f
tirwn3QAGOEC0g7R3EBztu4MX5dV1EQUvmTPwVXhx9TLKpevXVi5bvUm2hjwPy4Oe/t1fDPZiQL3
579Rt+ah1cfYNBSV+uzGvKXxnUvefK7CKElIjPZnlfVHVy1bVzXrpd3JRXnnri7RXl9vbB/iLAyP
ivbvcq7lcFbaYX/e6D97/aHVS9eVtRB9cK5+p2ZNwPZxk7HGQURUV1NPJA/QQlmO+g82qFeTZuPC
3rKJUTN/0fYGrwmhsanqNXkBDUtDpv7QqmXrPmgiImFUrFxC9TV1Nce2P3WsKErY1BC+Yn6/t8pR
d2z1Q7RxjydGNFYVZalppwYxYrSwN9Y39X5jhTA8eqS00cFIFfi+DKGw46ATSuKXbnx275rV20K3
rhwJF3q9aa4qOmaft/OjvGSqP7l99eqsDfJD69s7A+z1Jw+XVNgTZ4WXrKlYuF7dz+1prshb9mJZ
VOb6JdHNumbPh9de99ZD9xWFR4ULicjR1Jyw7eim5IHWlDA8KlxIjqaGmqKiCtUgtAN5Bwgiorp3
s9QUyBgxmFrK+hgjKHbFnp0Lo0VEZG8ylu1avW5lXtzRUdc5ZDdqVq77oInCU1/YmreQzcT2et26
ZauPNTUM4Pa8pi4xguoQI0YLe2XefVllwnBhL/M1NwkX7i1ZKR+KMsFoFbgMIRSyR2RDyaqsClFD
Dc0hIhLFL1wavmhXxfJNswZ6amyuLNHo6h0OB1E9e6VKTWWa7Q4JkVAYHjd/ydyBNnxL4lLjWnbt
Kql8aWnirOXLE0s2ldXbZ8U7zh0tOdYQrpq3XN1weNuh+OX9D0T2Ss2x5ti4qArNpgoSyecsjxZR
c8XeQy2x4UJasrtEHU1kr1hz3y7fneF9FrV85yG13H5u/aKnairysta/sHXNrAH1lnTVOUCwBhwj
ms/pKloSUpK7XfY0G0+ebJKrkv1q++HWESPm9TKfRBLBPolPIkmckzln+7GTxmaK1szPasg7uD5Z
RETGbfPVxryjm6IOL11WkbkitGjX4aoGYeycF7atnxsdsPIORHPZpl11RHHP7t600FOipoqSk936
HvuvPUasjeuYEIgY4fhG99Yb2o/P11+msNgZ6Y899qu4cX15n0X34nP6pX/JubW3E+NoVFT8TlZW
lveU9S/9eQDLa24g1fqdSxqN4bOia042JyQ7KqqiZsXVnGxKSKaKKsms5OaTFZJk2vDQsSY7BbJD
Ea45AcsQorjlu/fPafKcA0Xhcs+h5+Ac8tdP9srtG97q0lvsqDlcVMP+GNqcrFqTOMCDPXrp1q0N
q9csS9tMREThKeHb16yPS541f8nKuY5zJZs22eeu8vM06ZCo1uxc72ljsJ/bu3oXrdqdp8vKG1iZ
fRNGLdy4TX4sb3Ve8/q8QJ3SuAIEawAxwn5um/qht+ooNOUFzXqvRyM6miu2q7OK6kiY8tLBbXMD
mIRayjaoV9uXN/dx9mZjxeGTzbGq5HBfc9ibjm0vW7tt/6rwmpKVWRu2V6jWD7hBKQDsxmOVDqLk
5fM77X9JysJM9swviVNFDWD5TcdWP0Qr5lydMLAY4TDuefHF98c9+MSLT8Rdd6Xmfc3r614dtyVP
NXEARbwWLMlYTESeGLFz586mxksDXahQKBEJSSiRSEQiu0QiFJJEIhSJSCIRUv2h7Zr4beqBrgLG
gAD2ZYgi5PEBvd7t39opINcfEbNWaXQrGo01DXaJsGbXumPJCx3N4aHGkrxd9XNeyAvQBb29ctNT
m8uaQyuXHm5piVs7GFdOIlE0VW1YNF9I5Gj5YKlD4umVGQh75YZl7QEiNPmBWcZ3jzURUdySefai
w3VEde9mrYw/qFnY77ziaG4haj+zPzCrvYW9qWyTuuhwXfvrAX8qXkvZ5u09zlC34b7pGzy/CVPW
HlwZLyKjr9ljl6yYLxcRJarmR20/FoAGpYBobmohCo3q3GwdrVq6UhWoNTQd217SaUJd0TZdpsaf
u40sJ994z3LPSy+ly4VERLc/lNNmfO49/XeqORPJ8d1Hb72m0Z2/HDxhavoTOem3jiOi1pp/vv76
3tP1wdEz7klq9Szm8z1/ef29Ty+1hd3yyydz1EnSgW3gyOCJETt37lySsXj79p4P3t7ZG8p2rSly
zNm4NmpNnmTV0ooszfy8xLw1zStfkKxe9m5D+AuBKDZc8wKXIRoOZanXVXS5Po2at3P3/MAsXzTr
pT07a5rsROSo2b56ew0Rhaa+kLcwSkhEoujEwIy4sNfrirZrDlU2kUQSkbzkAXtNRZOxqGbOkoVU
VVVvVwWkSb2hoiZuY+n6ZBF7MTAo16tydclHS5odDiKyV+YtK6q0zxpwdxKRJDyUqIlCU9Zq1ifq
lr57jIgoPGXVepVEnVVUR6HhvXaychAlrtq9tmHpurIWaqlgl0lENUXtw0Rjl+zc1v9c0pu4zK2Z
VU+96PtGiKjM3TsXsg0PzcZjm1dvePFoys65vuYWRsjbGymEARzlO2DhseFU0WQ0NtNAG+l8CE1d
uylZk7W5rmNC1ANbN/p3u3Kr8SOj9FdPyK8eQdLZL74xm4iIvnv/1dc/v/W5LWtuajv9et6rBdF/
efH24M81r+61/GrN9nsmXNK+uu70lVlERJaPCl49OeGJV3bfSnpN3quvyre8dI20Y7Axgv1/4ERx
6p37F5JQIhJtXE8i0ZydCSKRKGEjiUS0db+KhBJHxbHeFwNjXcAyhL2ppjH+pRM751692LWfW790
Q30g+jFYEfHJ7J8mu6hESDUOIok8OWVWAHvr7Ma9WYs2NyQ/kLk80aHbvr3k2JydK2Y5Sk42NUnm
LJxnPFqy16haOCsQOUIolEgG+5Z6kYjNJ0KRKEAPtxfJV2r2JFa0JKiSI7yvyIWS5FV796eUNclT
kv06fYii52/cS1y9JLFLBmOcXlzm7p0r4ypX9jSPMDo8Oro9ukQvWZ6iWVPWYJ8rIbJ3NDLYm4x9
7Q0ZJiL5/JTQdw9Xbd9VoerUy2Svr6iihIGOMglNXbt303wq0XRMiHpg626/h9+0WSwkncDZavDN
yfcvJakfTJo4jkiV+aD2mfc+b00a9/5puifvl7dOFNLEBx9L1a1vIyKLXmuUZz53+6RxRLPV6vee
fO98q2pin4ZUjAKBChBEZK/ZlqVJfEGlWbauqtNfB2HC2v0vGFdvlq9fEqh1wTVslD5janDYq7Zt
r+noeW+kkl3G5OTEeHnimpT6kyWb1jtmLV04p+nYrpI49cLEfp7UJFF0LGv21VgvTNka4MIPFUm8
SsX5gkg+SyUfwIK5YkTsA4MWIBIl1K/+BqGImpuaicKjhS2HD5XVJ6RIaoq2lbU4UgJcusASJa54
IeXYi2XvZqkdL+StmJcYIaJmo06zYc1bFcKUl/YPYJQJGyCiierbJ0Q9sHXvmgH0mAVfN45aLa1E
V8/4jm/0py9Fz7il9VLruOgJ7dOlEycEt1pa2+hSmzRJyrZaCKU3SYO/IHK0fnPlyhcblz/EfgdH
W1tbbOclQjtR3PKd60UiUcpRVZcLDKFEIrLv3ipyVAzx/eIwGo3ODBEaHU7UQBQeLQzwpbzQ0VRV
cVLkqCjZ/pYx+aV5ciIiEkXPWrpmVmPF3l3ba5qF4eH9fnSTKDHv6Jk8z69GjXpb4IocsCUNu84x
IvaBwbhftCNA9Ldo4Qnhjl0lZc2b5uRlHlu9+r7ZoVHJC1esSNjc41OhRoCIuet3NqzM2l51eMOy
wxu8Xoias9C/RiMirwDhWdoAAwQRjZPPiK5/733jPQ91dGe06jWvvjFuzYwk6YRxrecvtdKkcURk
+c7SJpSOC5ZOCL5itDhIKiRyWOosbUQkDJ5w3XUz1u56jr0/w2GxXLnumhgPEVDhCaE670saX4QJ
L0SNoI45GIkCkiHC40J1T2U5iOiu6S92ee3dRVnC2CWZgViNhyh+1aEzqwK6SHa5yS+sX/Lihg2r
D0niZi3Zul/duVE2InnpqmRf7x0uolnrD+4xdjwuxlFfkrdrqFYdHpcYTg1NwrhA3ncpip6/ca9w
EB5/SURCuWrF7lXqqwFCEh5OFB7NMSBFrj50Rt1pSvTSkjNLiYgoceXOo1c7QeYuJSJaWHJyYceU
iIV7r/7SH6LwUKIe+v6E4RK/AqMkUa05mnJU81aRrsLY0Ezh8sSUeerlC7vfSNvHcsY+8NLaNVfv
9BGGJmduXbly4GN2J6rUqe+te+nVcY89NCvuujbjac3rn05I33KTkIQzVNJ9mn36NQ/e1HZ6775L
t6jjxgmv++UMx7o33pv13D0Tv3v/Ld1lmkFEE5PumbRXs+/z59LlZHz/tVc/mvXKq7+6NsZDBIwo
fmXJyR778QD6KhAZQhS/quTkIJzSh0HErFU7Dw3+poRGSSqemj2962Rh1AN+hC1JdHyi5895VL28
6cVF07uO2fZvyb2teNb6o2fWB3yxJIqeu2aTz7GLA1huvDovvtOEzq1Dw02UvF43GPVJRESS+Lkr
188NyHlDlLxmTacJEXPXBOiENO7WJ1/58z/feOutvL2XrgRfF52UviYvfZKQiCb9cs0T37z6lxXv
XQ6eMPWXzz05W0pEcernlr7++vrle9uiZyxdest754mIJs55+on61wqe+cfltrCb7nnsuXsQIAAG
z+jsyxjtIuZu0w3CSXJQlwwwFMbF/SrnpV91ny6cOPvJV2c/2W3m5wo8M3f8MPF29Uu3qweviADg
ge/+BgAAAH+gHQIAYOT6z4cfnCo/NdylAODWj3aIoKAgq9UawHVbrdaOL9kYrLUMwSpGtdFeP6O9
/GNNl/0lFAptNtswlmfk6yFAhN9wQ/eD39vgfRA4P3cwNvEYhunjrM3NzUaj0RGgpxURkVAolMvl
Ekmn4dyBXcsQrGJUG+31M9rLP9Z02V8Wi+XixYt2+0h5MPjoEhISMmnSpLCwMF8zDN4HgfNzB2NT
PzIEAAAAgAfGVAIAAIA/kCEAAADAH8gQAAAA4A9kCAAAAPCH4MsvvxzuMgAAAMDoI+Dz0RQBAAAA
/YYMAQAAAP5AhgAAAAB/IEMAAACAPwQ8Hm+4ywAAAACjT2AyBB6YDQAAMNb0ry/DV1ZAYwYAAMBY
03s7hHdu8J4ZbQ8AAABjWU8Zgk0Jnhm6hAa0PQAAAIxlPjMEwzBd0kP3OdEUAQAAMGZxZAjvxNA9
PXhyAwIEAADAWCbo8rt3Muj+c/fcgCQBAAAwNnH3ZXRvimDxeDxfYYJzCQAAAHCt6tQOwdnM4N15
0b0jA1kBAABgbLqaITjzgafVoYckgfs1AAAAxiCf4yG6B4guP3j3dPgaRQEAAADXqvYM0eXE3z03
uN1u6pwePFO6vx0AAACueT2Nh+gSINxutyc99NqjAQAAANe2rn0Z1LkRgrwCBHVOD11mQ4YAAAAY
UzjGVHr/6h0jJk2aNLRlAwAAgJGLTz2mB88ACDQzAAAAgDfu+zJ8/Q8AAADA4vfwmncjBDIEAAAA
eOMYU0kYLwkAAAC9aW+H8PXsak8jBGIEAAAAeOvUl8E5uJLzJQAAABjjOMZDdL8vY6gLBQAAACNe
L2MqPT8gSQAAAIA3fs/hAOkBAAAAOPXUDuGBJAEAAABd9ClDAAAAAHSBDAEAAAD+6ClDsN/0DQAA
ANAd2iEAAADAHz6fdT3A5f5i7xXvXx8XvjfABQIAAMCIwp0hAm7RokVDsyIAAAAYGujLAAAAAH8g
QwAAAIA/kCEAAADAH8gQAAAA4I8hGlMJAWexWOrr6x0Ox3AXBAAAxihkiNHq66+//tGPfiQSiYa7
IAAAMEahL2O0crlcCBAAADCMkCEAAADAH8gQAAAA4A9kCAAAAPAHMgQAAAD4AxkCAAAA/IEMAQAA
AP5Ahgisy1szNNNUmmmqgwe/73Vm10e/ZWf++zN61xAUDgAAIIDwjCnXmd/ufexj71P4DRvevS/t
Bv+XKH920YH7QvswY9DsV9RnHd88Ouff/q8MAABgmCBDBCU+e19xi6N+/7+f/fcN6wqS44XC6AEE
CAAAgDECGYJEsrB4IuENQSQUyqfcEC9kJztOPLE3NzT5IeGFff+93CIMm5+b9sefhwxZqewt1mZH
kOQGIR5FCQAAIxPGQ/TE8fEF+6K0D3WPFKvp0OayM0P3/VauM797554HSo/2PqgCAABgeCBD9OiW
pGVJIURB8T+Pl7d8/5lpuMsDAAAwYqAvoyfCG0Ik7T8FCcnV5HARBQ3JmoNmF6jPDsmaAAAA/IN2
iB4Jh7sAAAAAIxUyxAhlb7HWm6z24S4GAACAL8gQZDddPnfhkvF7Fzkcxgvfn7vQ0jzcRWLHVP4q
432MqQQAgBEL4yFclZsPdjxj6pu1T3wz8GdMAQAAjAXIEEHTX3mEa/Si8K7X1ac8v90Q/44ufugK
hTGVAAAw4qEvI/CMm/dPU/2zb9+X8fdpc96voCA8SAoAAEYdtEMEVthTxeqn+jpz0GzuJhAAAIBR
AO0QAAAA4A9kCAAAAPAHMgQAAAD4AxkCAAAA/IEMAQAAAP5AhhitBAKBwzF0X0YOAADQBe7tHK1i
YmIuXryIGAEAAMMFGWK0kkqlUql0uEsBAABjF/oyAAAAwB/IEAAAAOAPZAgAAADwBzIEAAAA+GOI
xlTu379/aFYEAAAAQ4PX1NRERAzDsP97uN1u9n+PH//4x8NdWgAAABgp0JcBAAAA/ugpQ7CNEwAA
AADdoR0CAAAA/IEMAQAAAP7oU4bg8Xg8Hm+wiwIAAACjCL/ncID0AAAAAJx6aofwpAckCQAAAOiC
I0OwccHzP9IDAAAAdNcpQ3SJC96/IkkAAACAt/YM4d1t4f0ywzC8DkNdNAAAABjBuMdDeEIDAgQA
AABw6mVMJY/H8zRFDFmZAAAAYOTrmiG6DKgkNEUAAAAAFz75GErpHSDYpohhKR8AAACMTLzvv/+e
vL77mzq+AZyI3G53l/893wzuPZv3/wAAADBGCLpPYpsc2LYHhmH4fL7b7fb87x0jPHMSMgQAAMAY
0ylDsKHB+1ci8o4R7KueJEFeUQOdHQAAAGNKe4bwlR68Y4Sn7cGTJAiNEAAAAGNV174MT0ToHiM8
4yupW38HnmgJAAAw1lzNEN75oHtQYCd2TxLoxQAAABibehoPQV6NCl3SQ/cZukDvBgAAwLWN474M
6nzDhXdK8LQ6eGeLHpYAAAAA1yqf4yG6/9xlSveEAQAAAGNHT8+H6PKz96vE1fEBAAAAYwd3XwZx
NUJ0TwxohAAAABizfGYI6hYduiSGXhshkDAAAACuYT1lCFaXMZWc0wEAAGCs6T1DeOvXnZwIGQAA
ANew/mUIXxAXAAAAxhr+cBcAAAAARiVkCAAAAPAHMgQAAAD4AxkCAAAA/IEMAQAAAP5AhgAAAAB/
IEMAAACAP5AhAAAAwB/IEAAAAOAPZAgAAADwBzIEAAAA+AMZAgAAAPyBDAEAAAD+QIYAAAAAfyBD
AAAAgD+QIQAAAMAfyBAAAADgD2QIAAAA8AcyBAAAAPgDGQIAAAD8gQwBAAAA/kCGAAAAAH8gQwAA
AIA/kCEAAADAH8gQAAAA4I//D60k8gEpfjrYAAAAAElFTkSuQmCC
"
id="image3398"
x="0"
y="0" />
<g
id="g3420">
<rect
y="4.3175645"
x="209.71611"
height="33.600925"
width="265.33145"
id="rect3404"
style="opacity:0.70800045;fill:#ffffff" />
<text
sodipodi:linespacing="125%"
id="text3400"
y="29.80792"
x="217.82669"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="29.80792"
x="217.82669"
id="tspan3402"
sodipodi:role="line">⇦ Notebook name</tspan></text>
</g>
<text
sodipodi:linespacing="125%"
id="text3411"
y="70.360764"
x="415.00436"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="70.360764"
x="415.00436"
id="tspan3413"
sodipodi:role="line">Menu bar</tspan></text>
<text
sodipodi:linespacing="125%"
id="text3411-3"
y="102.85388"
x="540.51917"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="102.85388"
x="540.51917"
id="tspan3413-6"
sodipodi:role="line">Toolbar</tspan></text>
<text
sodipodi:linespacing="125%"
id="text3411-7"
y="175.849"
x="194.08205"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="175.849"
x="194.08205"
id="tspan3413-5"
sodipodi:role="line">Code cell</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

@ -1,16 +0,0 @@
<svg width="39" height="51" viewBox="0 0 39 51" version="2.0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(-1638 -2281)">
<use xlink:href="#path0_fill" transform="translate(1669.3 2281.31)" fill="#767677"/>
<use xlink:href="#path1_fill" transform="translate(1639.74 2311.98)" fill="#F37726"/>
<use xlink:href="#path2_fill" transform="translate(1639.73 2285.48)" fill="#F37726"/>
<use xlink:href="#path3_fill" transform="translate(1639.8 2323.81)" fill="#989798"/>
<use xlink:href="#path4_fill" transform="translate(1638.36 2286.06)" fill="#6F7070"/>
</g>
<defs>
<path id="path0_fill" d="M 5.89353 2.844C 5.91889 3.43165 5.77085 4.01367 5.46815 4.51645C 5.16545 5.01922 4.72168 5.42015 4.19299 5.66851C 3.6643 5.91688 3.07444 6.00151 2.49805 5.91171C 1.92166 5.8219 1.38463 5.5617 0.954898 5.16401C 0.52517 4.76633 0.222056 4.24903 0.0839037 3.67757C -0.0542483 3.10611 -0.02123 2.50617 0.178781 1.95364C 0.378793 1.4011 0.736809 0.920817 1.20754 0.573538C 1.67826 0.226259 2.24055 0.0275919 2.82326 0.00267229C 3.60389 -0.0307115 4.36573 0.249789 4.94142 0.782551C 5.51711 1.31531 5.85956 2.05676 5.89353 2.844Z"/>
<path id="path1_fill" d="M 18.2646 7.13411C 10.4145 7.13411 3.55872 4.2576 0 0C 1.32539 3.8204 3.79556 7.13081 7.0686 9.47303C 10.3417 11.8152 14.2557 13.0734 18.269 13.0734C 22.2823 13.0734 26.1963 11.8152 29.4694 9.47303C 32.7424 7.13081 35.2126 3.8204 36.538 0C 32.9705 4.2576 26.1148 7.13411 18.2646 7.13411Z"/>
<path id="path2_fill" d="M 18.2733 5.93931C 26.1235 5.93931 32.9793 8.81583 36.538 13.0734C 35.2126 9.25303 32.7424 5.94262 29.4694 3.6004C 26.1963 1.25818 22.2823 0 18.269 0C 14.2557 0 10.3417 1.25818 7.0686 3.6004C 3.79556 5.94262 1.32539 9.25303 0 13.0734C 3.56745 8.82463 10.4232 5.93931 18.2733 5.93931Z"/>
<path id="path3_fill" d="M 7.42789 3.58338C 7.46008 4.3243 7.27355 5.05819 6.89193 5.69213C 6.51031 6.32607 5.95075 6.83156 5.28411 7.1446C 4.61747 7.45763 3.87371 7.56414 3.14702 7.45063C 2.42032 7.33712 1.74336 7.0087 1.20184 6.50695C 0.660328 6.0052 0.27861 5.35268 0.105017 4.63202C -0.0685757 3.91135 -0.0262361 3.15494 0.226675 2.45856C 0.479587 1.76217 0.931697 1.15713 1.52576 0.720033C 2.11983 0.282935 2.82914 0.0334395 3.56389 0.00313344C 4.54667 -0.0374033 5.50529 0.316706 6.22961 0.987835C 6.95393 1.65896 7.38484 2.59235 7.42789 3.58338L 7.42789 3.58338Z"/>
<path id="path4_fill" d="M 2.27471 4.39629C 1.84363 4.41508 1.41671 4.30445 1.04799 4.07843C 0.679268 3.8524 0.385328 3.52114 0.203371 3.12656C 0.0214136 2.73198 -0.0403798 2.29183 0.0258116 1.86181C 0.0920031 1.4318 0.283204 1.03126 0.575213 0.710883C 0.867222 0.39051 1.24691 0.164708 1.66622 0.0620592C 2.08553 -0.0405897 2.52561 -0.0154714 2.93076 0.134235C 3.33591 0.283941 3.68792 0.551505 3.94222 0.90306C 4.19652 1.25462 4.34169 1.67436 4.35935 2.10916C 4.38299 2.69107 4.17678 3.25869 3.78597 3.68746C 3.39516 4.11624 2.85166 4.37116 2.27471 4.39629L 2.27471 4.39629Z"/>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

@ -1,14 +0,0 @@
<svg width="330" height="85" viewBox="0 0 330 85" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M94.1599 51.9293C94.1599 60.5061 93.5057 63.3065 91.7612 65.3736C89.8569 67.1335 87.3662 68.1068 84.7833 68.1006L85.4375 73.2026C89.4409 73.2581 93.3217 71.8106 96.3259 69.1416C99.4514 65.8868 100.542 61.3858 100.542 54.4805V22.05H94.1453V51.9733L94.1599 51.9293Z" fill="#FFFFFF"/>
<path d="M141.869 48.0214C141.869 51.7161 141.869 54.9707 142.16 57.7711H136.563L136.199 51.9066H136.054C134.876 53.9562 133.177 55.6521 131.133 56.8194C129.089 57.9869 126.773 58.5836 124.424 58.5481C118.9 58.5481 112.3 55.4399 112.3 42.8901V21.9832H118.696V41.8197C118.696 48.6226 120.732 53.1967 126.532 53.1967C128.352 53.1632 130.121 52.5889 131.618 51.5456C133.115 50.5024 134.274 49.0367 134.949 47.3324C135.337 46.2666 135.534 45.1396 135.531 44.0042V22.0126H141.927V48.0214H141.869Z" fill="#FFFFFF"/>
<path d="M153.924 33.6771C153.924 29.1028 153.779 25.4082 153.633 21.9481H159.376L159.666 28.0765H159.812C161.068 25.8807 162.895 24.0728 165.096 22.8481C167.297 21.6233 169.788 21.0282 172.299 21.1271C180.789 21.1271 187.185 28.4577 187.185 39.3069C187.185 52.1647 179.495 58.513 171.194 58.513C169.064 58.6032 166.946 58.1329 165.05 57.1485C163.154 56.164 161.544 54.6992 160.379 52.8979H160.233V72.3239H153.91V33.6184L153.924 33.6771ZM160.248 43.2069C160.265 44.0984 160.362 44.9867 160.539 45.8605C161.06 48.0277 162.287 49.9557 164.024 51.3354C165.761 52.7152 167.908 53.4667 170.119 53.4695C176.879 53.4695 180.789 47.8544 180.789 39.6589C180.789 32.4895 177.082 26.3611 170.337 26.3611C168.068 26.4252 165.886 27.2521 164.137 28.7105C162.388 30.1689 161.173 32.1751 160.684 34.4101C160.428 35.2725 160.281 36.1642 160.248 37.0638V43.1922V43.2069Z" fill="#FFFFFF"/>
<path d="M198.501 22.0166L206.191 43.1433C206.991 45.5038 207.863 48.3188 208.444 50.4739H208.59C209.244 48.3334 209.971 45.5918 210.843 43.0114L217.821 22.0313H224.581L215.001 47.5269C210.421 59.7838 207.31 66.0733 202.949 69.9146C200.746 71.9818 198.044 73.4323 195.114 74.1223L193.515 68.6538C195.565 67.9648 197.465 66.8846 199.111 65.4723C201.438 63.5119 203.279 61.0323 204.49 58.2296C204.749 57.7456 204.921 57.2196 204.999 56.6756C204.942 56.0893 204.794 55.5156 204.563 54.9748L191.567 22.0313H198.544L198.501 22.0166Z" fill="#FFFFFF"/>
<path d="M241.369 11.7334V21.9962H250.513V26.9517H241.369V46.2164C241.369 50.6147 242.605 53.1657 246.167 53.1657C247.416 53.1854 248.663 53.0374 249.874 52.7259L250.164 57.6081C248.345 58.2542 246.422 58.5526 244.495 58.4877C243.216 58.5667 241.936 58.3637 240.744 57.8927C239.551 57.4217 238.475 56.6942 237.59 55.7607C235.772 53.8402 235.118 50.6587 235.118 46.4511V26.9517H229.667V21.9962H235.118V13.4194L241.369 11.7334Z" fill="#FFFFFF"/>
<path d="M262.298 41.0638C262.443 49.8604 267.967 53.4818 274.349 53.4818C277.685 53.5874 281.005 52.9569 284.074 51.6344L285.165 56.2821C281.487 57.8399 277.523 58.5944 273.535 58.4959C262.719 58.4959 256.25 51.2533 256.25 40.4626C256.25 29.6721 262.501 21.1833 272.735 21.1833C284.205 21.1833 287.273 31.4461 287.273 38.0289C287.262 39.0441 287.189 40.0576 287.055 41.0638H262.341H262.298ZM281.036 36.4162C281.109 32.2818 279.364 25.8455 272.183 25.8455C265.714 25.8455 262.894 31.9006 262.385 36.4162H281.051H281.036Z" fill="#FFFFFF"/>
<path d="M296.574 33.1642C296.574 28.9564 296.501 25.3351 296.283 22.0071H301.88L302.098 29.0297H302.389C303.988 24.2209 307.84 21.2007 312.114 21.2007C312.727 21.1917 313.338 21.2656 313.932 21.4206V27.549C313.216 27.3915 312.484 27.3177 311.751 27.3291C307.244 27.3291 304.061 30.8037 303.189 35.6712C303.009 36.673 302.911 37.6881 302.898 38.7061V57.7656H296.574V33.1642Z" fill="#FFFFFF"/>
<path d="M61.9893 5.25676C62.0316 6.23618 61.7848 7.20621 61.2803 8.04418C60.7758 8.88213 60.0362 9.55034 59.1551 9.96428C58.2739 10.3782 57.2908 10.5193 56.3302 10.3696C55.3695 10.2199 54.4745 9.78626 53.7582 9.12344C53.042 8.46064 52.5368 7.59848 52.3066 6.64605C52.0763 5.69361 52.1314 4.69371 52.4647 3.77283C52.7981 2.85193 53.3948 2.05146 54.1793 1.47266C54.9638 0.89386 55.901 0.562748 56.8722 0.521216C58.1732 0.465576 59.443 0.933077 60.4024 1.82101C61.3619 2.70895 61.9327 3.9447 61.9893 5.25676Z" fill="#FFFFFF"/>
<path d="M33.341 63.5235C20.2575 63.5235 8.83118 58.7293 2.89998 51.6333C5.10896 58.0006 9.22591 63.518 14.681 67.4217C20.1361 71.3253 26.6595 73.4223 33.3483 73.4223C40.0371 73.4223 46.5605 71.3253 52.0156 67.4217C57.4706 63.518 61.5876 58.0006 63.7966 51.6333C57.8508 58.7293 46.4246 63.5235 33.341 63.5235Z" fill="#F37726"/>
<path d="M33.3388 17.3655C46.4225 17.3655 57.8488 22.1597 63.78 29.2556C61.571 22.8883 57.454 17.371 51.999 13.4673C46.5438 9.5636 40.0205 7.46663 33.3316 7.46663C26.6428 7.46663 20.1195 9.5636 14.6643 13.4673C9.20923 17.371 5.09228 22.8883 2.8833 29.2556C8.82905 22.1743 20.2553 17.3655 33.3388 17.3655Z" fill="#F37726"/>
<path d="M15.3799 77.3224C15.4335 78.5573 15.1227 79.7804 14.4866 80.837C13.8506 81.8935 12.918 82.736 11.8069 83.2578C10.6959 83.7795 9.45626 83.957 8.24511 83.7678C7.03394 83.5786 5.90568 83.0313 5.00314 82.195C4.10062 81.3588 3.46443 80.2712 3.1751 79.0701C2.88578 77.869 2.95635 76.6083 3.37787 75.4477C3.79939 74.287 4.5529 73.2786 5.54301 72.5502C6.53313 71.8217 7.71531 71.4058 8.93989 71.3553C10.5779 71.2878 12.1756 71.8779 13.3828 72.9965C14.59 74.115 15.3081 75.6707 15.3799 77.3224Z" fill="#989798"/>
<path d="M4.39116 15.7606C3.67269 15.7919 2.96116 15.6075 2.34663 15.2308C1.73209 14.8541 1.24219 14.302 0.938927 13.6444C0.635665 12.9867 0.532676 12.2531 0.642995 11.5364C0.753314 10.8198 1.07198 10.1522 1.55866 9.61823C2.04535 9.08428 2.67816 8.70794 3.37701 8.53686C4.07586 8.36578 4.80933 8.40764 5.48458 8.65715C6.15983 8.90666 6.74651 9.3526 7.17034 9.93853C7.59418 10.5245 7.83613 11.224 7.86556 11.9487C7.90496 12.9185 7.56128 13.8646 6.90993 14.5792C6.25858 15.2938 5.35274 15.7187 4.39116 15.7606Z" fill="#FFFFFF"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.8 KiB

@ -1,14 +0,0 @@
<svg width="330" height="85" viewBox="0 0 330 85" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M94.1599 51.9293C94.1599 60.5061 93.5057 63.3065 91.7612 65.3736C89.8569 67.1335 87.3662 68.1068 84.7833 68.1006L85.4375 73.2026C89.4409 73.2581 93.3217 71.8106 96.3259 69.1416C99.4514 65.8868 100.542 61.3858 100.542 54.4805V22.05H94.1453V51.9733L94.1599 51.9293Z" fill="#4E4E4E"/>
<path d="M141.869 48.0214C141.869 51.7161 141.869 54.9707 142.16 57.7711H136.563L136.199 51.9066H136.054C134.876 53.9562 133.177 55.6521 131.133 56.8194C129.089 57.9869 126.773 58.5836 124.424 58.5481C118.9 58.5481 112.3 55.4399 112.3 42.8901V21.9832H118.696V41.8197C118.696 48.6226 120.732 53.1967 126.532 53.1967C128.352 53.1632 130.121 52.5889 131.618 51.5456C133.115 50.5024 134.274 49.0367 134.949 47.3324C135.337 46.2666 135.534 45.1396 135.531 44.0042V22.0126H141.927V48.0214H141.869Z" fill="#4E4E4E"/>
<path d="M153.924 33.6771C153.924 29.1028 153.779 25.4082 153.633 21.9481H159.376L159.666 28.0765H159.812C161.068 25.8807 162.895 24.0728 165.096 22.8481C167.297 21.6233 169.788 21.0282 172.299 21.1271C180.789 21.1271 187.185 28.4577 187.185 39.3069C187.185 52.1647 179.495 58.513 171.194 58.513C169.064 58.6032 166.946 58.1329 165.05 57.1485C163.154 56.164 161.544 54.6992 160.379 52.8979H160.233V72.3239H153.91V33.6184L153.924 33.6771ZM160.248 43.2069C160.265 44.0984 160.362 44.9867 160.539 45.8605C161.06 48.0277 162.287 49.9557 164.024 51.3354C165.761 52.7152 167.908 53.4667 170.119 53.4695C176.879 53.4695 180.789 47.8544 180.789 39.6589C180.789 32.4895 177.082 26.3611 170.337 26.3611C168.068 26.4252 165.886 27.2521 164.137 28.7105C162.388 30.1689 161.173 32.1751 160.684 34.4101C160.428 35.2725 160.281 36.1642 160.248 37.0638V43.1922V43.2069Z" fill="#4E4E4E"/>
<path d="M198.501 22.0166L206.191 43.1433C206.991 45.5038 207.863 48.3188 208.444 50.4739H208.59C209.244 48.3334 209.971 45.5918 210.843 43.0114L217.821 22.0313H224.581L215.001 47.5269C210.421 59.7838 207.31 66.0733 202.949 69.9146C200.746 71.9818 198.044 73.4323 195.114 74.1223L193.515 68.6538C195.565 67.9648 197.465 66.8846 199.111 65.4723C201.438 63.5119 203.279 61.0323 204.49 58.2296C204.749 57.7456 204.921 57.2196 204.999 56.6756C204.942 56.0893 204.794 55.5156 204.563 54.9748L191.567 22.0313H198.544L198.501 22.0166Z" fill="#4E4E4E"/>
<path d="M241.369 11.7334V21.9962H250.513V26.9517H241.369V46.2164C241.369 50.6147 242.605 53.1657 246.167 53.1657C247.416 53.1854 248.663 53.0374 249.874 52.7259L250.164 57.6081C248.345 58.2542 246.422 58.5526 244.495 58.4877C243.216 58.5667 241.936 58.3637 240.744 57.8927C239.551 57.4217 238.475 56.6942 237.59 55.7607C235.772 53.8402 235.118 50.6587 235.118 46.4511V26.9517H229.667V21.9962H235.118V13.4194L241.369 11.7334Z" fill="#4E4E4E"/>
<path d="M262.298 41.0638C262.443 49.8604 267.967 53.4818 274.349 53.4818C277.685 53.5874 281.005 52.9569 284.074 51.6344L285.165 56.2821C281.487 57.8399 277.523 58.5944 273.535 58.4959C262.719 58.4959 256.25 51.2533 256.25 40.4626C256.25 29.6721 262.501 21.1833 272.735 21.1833C284.205 21.1833 287.273 31.4461 287.273 38.0289C287.262 39.0441 287.189 40.0576 287.055 41.0638H262.341H262.298ZM281.036 36.4162C281.109 32.2818 279.364 25.8455 272.183 25.8455C265.714 25.8455 262.894 31.9006 262.385 36.4162H281.051H281.036Z" fill="#4E4E4E"/>
<path d="M296.574 33.1642C296.574 28.9564 296.501 25.3351 296.283 22.0071H301.88L302.098 29.0297H302.389C303.988 24.2209 307.84 21.2007 312.114 21.2007C312.727 21.1917 313.338 21.2656 313.932 21.4206V27.549C313.216 27.3915 312.484 27.3177 311.751 27.3291C307.244 27.3291 304.061 30.8037 303.189 35.6712C303.009 36.673 302.911 37.6881 302.898 38.7061V57.7656H296.574V33.1642Z" fill="#4E4E4E"/>
<path d="M61.9893 5.25676C62.0316 6.23618 61.7848 7.20621 61.2803 8.04418C60.7758 8.88213 60.0362 9.55034 59.1551 9.96428C58.2739 10.3782 57.2908 10.5193 56.3302 10.3696C55.3695 10.2199 54.4745 9.78626 53.7582 9.12344C53.042 8.46064 52.5368 7.59848 52.3066 6.64605C52.0763 5.69361 52.1314 4.69371 52.4647 3.77283C52.7981 2.85193 53.3948 2.05146 54.1793 1.47266C54.9638 0.89386 55.901 0.562748 56.8722 0.521216C58.1732 0.465576 59.443 0.933077 60.4024 1.82101C61.3619 2.70895 61.9327 3.9447 61.9893 5.25676Z" fill="#767677"/>
<path d="M33.341 63.5235C20.2575 63.5235 8.83118 58.7293 2.89998 51.6333C5.10896 58.0006 9.22591 63.518 14.681 67.4217C20.1361 71.3253 26.6595 73.4223 33.3483 73.4223C40.0371 73.4223 46.5605 71.3253 52.0156 67.4217C57.4706 63.518 61.5876 58.0006 63.7966 51.6333C57.8508 58.7293 46.4246 63.5235 33.341 63.5235Z" fill="#F37726"/>
<path d="M33.3388 17.3655C46.4225 17.3655 57.8488 22.1597 63.78 29.2556C61.571 22.8883 57.454 17.371 51.999 13.4673C46.5438 9.5636 40.0205 7.46663 33.3316 7.46663C26.6428 7.46663 20.1195 9.5636 14.6643 13.4673C9.20923 17.371 5.09228 22.8883 2.8833 29.2556C8.82905 22.1743 20.2553 17.3655 33.3388 17.3655Z" fill="#F37726"/>
<path d="M15.3799 77.3224C15.4335 78.5573 15.1227 79.7804 14.4866 80.837C13.8506 81.8935 12.918 82.736 11.8069 83.2578C10.6959 83.7795 9.45626 83.957 8.24511 83.7678C7.03394 83.5786 5.90568 83.0313 5.00314 82.195C4.10062 81.3588 3.46443 80.2712 3.1751 79.0701C2.88578 77.869 2.95635 76.6083 3.37787 75.4477C3.79939 74.287 4.5529 73.2786 5.54301 72.5502C6.53313 71.8217 7.71531 71.4058 8.93989 71.3553C10.5779 71.2878 12.1756 71.8779 13.3828 72.9965C14.59 74.115 15.3081 75.6707 15.3799 77.3224Z" fill="#989798"/>
<path d="M4.39116 15.7606C3.67269 15.7919 2.96116 15.6075 2.34663 15.2308C1.73209 14.8541 1.24219 14.302 0.938927 13.6444C0.635665 12.9867 0.532676 12.2531 0.642995 11.5364C0.753314 10.8198 1.07198 10.1522 1.55866 9.61823C2.04535 9.08428 2.67816 8.70794 3.37701 8.53686C4.07586 8.36578 4.80933 8.40764 5.48458 8.65715C6.15983 8.90666 6.74651 9.3526 7.17034 9.93853C7.59418 10.5245 7.83613 11.224 7.86556 11.9487C7.90496 12.9185 7.56128 13.8646 6.90993 14.5792C6.25858 15.2938 5.35274 15.7187 4.39116 15.7606Z" fill="#6F7070"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.8 KiB

File diff suppressed because one or more lines are too long

@ -1,3 +1,5 @@
#!/usr/bin/env python3
#
# Jupyter Notebook documentation build configuration file, created by
# sphinx-quickstart on Mon Apr 13 09:51:11 2015.
#
@ -10,23 +12,19 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
import logging
import sys
import os
import shutil
import sys
logger = logging.getLogger(__name__)
logging.basicConfig()
# 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.
# DEBUG for RTD
logger.info("DEBUG:: sys.path")
logger.info("================")
print("DEBUG:: sys.path")
print("================")
for item in sys.path:
logger.info(item)
print(item)
# add repo root to sys.path
# here = root/docs/source
@ -40,63 +38,56 @@ shutil.copy(os.path.join(repo_root, "CHANGELOG.md"), os.path.join(here, "changel
# Copy the contributing file here
shutil.copy(os.path.join(repo_root, "CONTRIBUTING.md"), os.path.join(here, "contributing.md"))
logger.info("repo_root")
logger.info("=====================")
logger.info(repo_root)
print("repo_root")
print("=====================")
print(repo_root)
# DEBUG for post insert on RTD
logger.info("DEBUG:: Post insert to sys.path")
logger.info("===============================")
print("DEBUG:: Post insert to sys.path")
print("===============================")
for item in sys.path:
logger.info(item)
print(item)
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
#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 = [
"sphinx.ext.autodoc",
"sphinx.ext.doctest",
"sphinx.ext.intersphinx",
"sphinx.ext.autosummary",
"sphinx.ext.mathjax",
"IPython.sphinxext.ipython_console_highlighting",
"nbsphinx",
"sphinxcontrib_github_alt",
"myst_parser",
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.autosummary',
'sphinx.ext.mathjax',
'IPython.sphinxext.ipython_console_highlighting',
'nbsphinx',
'sphinxcontrib_github_alt',
'myst_parser'
]
try:
import enchant # noqa: F401
extensions += ["sphinxcontrib.spelling"]
except ImportError:
pass
myst_enable_extensions = ["html_image"]
myst_update_mathjax = False
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
# The encoding of source files.
# source_encoding = 'utf-8-sig'
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = "index"
master_doc = 'index'
# General information about the project.
project = "Jupyter Notebook"
copyright = "2015, Jupyter Team, https://jupyter.org"
author = "The Jupyter Team"
project = 'Jupyter Notebook'
copyright = '2015, Jupyter Team, https://jupyter.org'
author = 'The Jupyter Team'
# ghissue config
github_project_url = "https://github.com/jupyter/notebook"
@ -105,58 +96,54 @@ github_project_url = "https://github.com/jupyter/notebook"
# |version| and |release|, also used in various other places throughout the
# built documents.
#
_version_py = os.path.join(here, "../../notebook/_version.py")
_version_py = '../../notebook/_version.py'
version_ns = {}
exec(compile(open(_version_py).read(), _version_py, "exec"), version_ns) # noqa: S102, SIM115
exec(compile(open(_version_py).read(), _version_py, 'exec'), version_ns)
# The short X.Y version.
version = "{}.{}".format(*version_ns["version_info"][:2])
version = '%i.%i' % version_ns['version_info'][:2]
# The full version, including alpha/beta/rc tags.
release = version_ns["__version__"]
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"
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
#today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
#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 = [
"examples/Notebook/.ipynb_checkpoints",
"examples/Notebook/nbpackage/*.ipynb",
"examples/Notebook/nbpackage/nbs/*.ipynb",
]
exclude_patterns = ['examples/Notebook/.ipynb_checkpoints', 'examples/Notebook/nbpackage/*.ipynb', 'examples/Notebook/nbpackage/nbs/*.ipynb']
# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
#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
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
@ -171,58 +158,17 @@ html_theme = "pydata_sphinx_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 = {
"header_links_before_dropdown": 5,
"icon_links": [
{
"name": "jupyter.org",
"url": "https://jupyter.org",
"icon": "_static/jupyter_logo.svg",
"type": "local",
},
{
"name": "GitHub",
"url": "https://github.com/jupyter/notebook",
"icon": "fab fa-github-square",
},
{
"name": "Discourse",
"url": "https://discourse.jupyter.org/c/notebook/31",
"icon": "fab fa-discourse",
},
{
"name": "Zulip",
"url": "https://jupyter.zulipchat.com/",
"icon": "_static/zulip-icon-square.svg",
"type": "local",
},
],
"logo": {
"alt_text": "Jupyter",
"image_light": "_static/logo-rectangle.svg",
"image_dark": "_static/logo-rectangle-dark.svg",
},
"use_edit_page_button": True,
"navigation_with_keys": False,
}
# Output for github to be used in links
html_context = {
"github_user": "jupyter", # Username
"github_repo": "notebook", # Repo name
"github_version": "main", # Version
"doc_path": "docs/source/", # Path in the checkout to the docs root
}
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
# html_title = None
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
@ -231,7 +177,7 @@ html_logo = "examples/images/jupyter_logo.png"
# 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
#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,
@ -239,127 +185,134 @@ html_logo = "examples/images/jupyter_logo.png"
# NOTE: Sphinx's 'make html' builder will throw a warning about an unfound
# _static directory. Do not remove or comment out html_static_path
# since it is needed to properly generate _static in the build directory
html_static_path = ["_static"]
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 = []
#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'
#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
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
#html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
#html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
#html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
#html_split_index = False
# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
#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'
#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'}
#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'
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = "JupyterNotebookdoc"
# This will ensure that we use the correctly set environment for canonical URLs
# Old Read the Docs injections makes it point only to the default version,
# for instance /en/stable/
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "/")
htmlhelp_basename = 'JupyterNotebookdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {}
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# 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,
"JupyterNotebook.tex",
"Jupyter Notebook Documentation",
"https://jupyter.org",
"manual",
),
(master_doc, 'JupyterNotebook.tex', 'Jupyter Notebook Documentation',
'https://jupyter.org', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
#latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
# latex_appendices = []
#latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
#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, "jupyternotebook", "Jupyter Notebook Documentation", [author], 1)]
man_pages = [
(master_doc, 'jupyternotebook', 'Jupyter Notebook Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
# man_show_urls = False
#man_show_urls = False
# -- Options for link checks ----------------------------------------------
linkcheck_ignore = [r"http://127\.0\.0\.1/*"]
linkcheck_ignore = [
'http://127\.0\.0\.1/*'
]
# -- Options for Texinfo output -------------------------------------------
@ -368,39 +321,29 @@ linkcheck_ignore = [r"http://127\.0\.0\.1/*"]
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
master_doc,
"JupyterNotebook",
"Jupyter Notebook Documentation",
author,
"JupyterNotebook",
"One line description of project.",
"Miscellaneous",
),
(master_doc, 'JupyterNotebook', 'Jupyter Notebook Documentation',
author, 'JupyterNotebook', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
# texinfo_appendices = []
#texinfo_appendices = []
# If false, no module index is generated.
# texinfo_domain_indices = True
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False
#texinfo_no_detailmenu = False
intersphinx_mapping = {
"ipython": ("https://ipython.readthedocs.io/en/stable/", None),
"nbconvert": ("https://nbconvert.readthedocs.io/en/latest/", None),
"nbformat": ("https://nbformat.readthedocs.io/en/latest/", None),
"jupyter": ("https://jupyter.readthedocs.io/en/latest/", None),
'ipython': ('https://ipython.readthedocs.io/en/stable/', None),
'nbconvert': ('https://nbconvert.readthedocs.io/en/latest/', None),
'nbformat': ('https://nbformat.readthedocs.io/en/latest/', None),
'jupyter': ('https://jupyter.readthedocs.io/en/latest/', None),
}
spelling_lang = "en_US"
spelling_word_list_filename = "spelling_wordlist.txt"
def setup(app):
app.add_css_file("https://docs.jupyter.org/en/latest/_static/jupyter.css")
spelling_lang='en_US'
spelling_word_list_filename='spelling_wordlist.txt'

@ -0,0 +1,63 @@
.. _configuration-overview:
Configuration Overview
======================
Beyond the default configuration settings, you can configure a rich array of
options to suit your workflow. Here are areas that are commonly configured
when using Jupyter Notebook:
- :ref:`Jupyter's common configuration system <configure_common>`
- :ref:`Jupyter Server <configure_jupyter_server>`
- :ref:`Notebook extensions <configure_nbextensions>`
Let's look at highlights of each area.
.. _configure_common:
Jupyter's Common Configuration system
-------------------------------------
Jupyter applications, from the Notebook to JupyterHub to nbgrader, share a
common configuration system. The process for creating a configuration file
and editing settings is similar for all the Jupyter applications.
- `Jupyters Common Configuration Approach <https://jupyter.readthedocs.io/en/latest/use/config.html>`_
- `Common Directories and File Locations <https://jupyter.readthedocs.io/en/latest/use/jupyter-directories.html>`_
- `Language kernels <https://jupyter.readthedocs.io/en/latest/projects/kernels.html>`_
- `traitlets <https://traitlets.readthedocs.io/en/latest/config.html#module-traitlets.config>`_
provide a low-level architecture for configuration.
.. _configure_jupyter_server:
Jupyter server
---------------
The Jupyter Server runs the language kernel and communicates with the
front-end Notebook client (i.e. the familiar notebook interface).
- Configuring the Jupyter Server
To create a ``jupyter_server_config.py`` file in the ``.jupyter``
directory, with all the defaults commented out, use the following
command::
$ jupyter server --generate-config
- `Running a Jupyter Server <https://jupyter-server.readthedocs.io/en/stable/operators/public-server.html>`_
- Related: `Configuring a language kernel <https://ipython.readthedocs.io/en/latest/install/kernel_install.html>`_
to run in the Jupyter Server enables your server to run other languages, like R or Julia.
.. _configure_nbextensions:
Notebook extensions
-------------------
The Notebook frontend can be extending with JupyterLab extensions.
See the :ref:`Frontend Extension Guide <frontend_extensions>` for more information.
`Security in Jupyter notebooks: <https://jupyter-server.readthedocs.io/en/stable/operators/security.html>`_
Since security policies vary from organization to organization, we encourage you to
consult with your security team on settings that would be best for your use
cases. Our documentation offers some responsible security practices, and we
recommend becoming familiar with the practices.

@ -1,10 +0,0 @@
# Configuration
```{toctree}
:caption: Configuration
:maxdepth: 1
configuring/config_overview
Security <https://jupyter-server.readthedocs.io/en/stable/operators/security.html>
extending/index.rst
```

@ -0,0 +1,11 @@
=============
Configuration
=============
.. toctree::
:maxdepth: 1
:caption: Configuration
config_overview
Security <https://jupyter-server.readthedocs.io/en/stable/operators/security.html>
extending/index.rst

@ -1,73 +0,0 @@
(configuration-overview)=
# Configuration Overview
Beyond the default configuration settings, you can configure a rich array of
options to suit your workflow. Here are areas that are commonly configured
when using Jupyter Notebook:
> - {ref}`Jupyter's common configuration system <configure-common>`
> - {ref}`Jupyter Server <configure-jupyter-server>`
> - {ref}`Notebook extensions <configure-nbextensions>`
Let's look at highlights of each area.
(configure-common)=
## Jupyter's Common Configuration system
Jupyter applications, from the Notebook to JupyterHub to nbgrader, share a
common configuration system. The process for creating a configuration file
and editing settings is similar for all the Jupyter applications.
> - [Jupyters Common Configuration Approach](https://jupyter.readthedocs.io/en/latest/use/config.html)
> - [Common Directories and File Locations](https://jupyter.readthedocs.io/en/latest/use/jupyter-directories.html)
> - [Language kernels](https://jupyter.readthedocs.io/en/latest/projects/kernels.html)
> - [traitlets](https://traitlets.readthedocs.io/en/latest/config.html#module-traitlets.config)
> provide a low-level architecture for configuration.
### Disabling Custom CSS
Custom CSS is loaded by default as was done with Jupyter Notebook 6. In the jupyter configuration directory, the `/.jupyter/custom/custom.css` file will be loaded unless the the application is initialized with the `custom_css` flag with the argument set to `False` as in `--JupyterNotebookApp.custom_css=False`.
(configure-jupyter-server)=
## Jupyter server
The Jupyter Server runs the language kernel and communicates with the
front-end Notebook client (i.e. the familiar notebook interface).
> - Configuring the Jupyter Server
>
> > To create a `jupyter_server_config.py` file in the `.jupyter`
> > directory, with all the defaults commented out, use the following
> > command:
> >
> > ```
> > $ jupyter server --generate-config
> > ```
>
> - [Running a Jupyter Server](https://jupyter-server.readthedocs.io/en/stable/operators/public-server.html)
>
> - Related: [Configuring a language kernel](https://ipython.readthedocs.io/en/latest/install/kernel_install.html)
> to run in the Jupyter Server enables your server to run other languages, like R or Julia.
```{warning}
Jupyter Notebook 7 is now based on Jupyter Server. This may break some previous `notebook` imports you may have been using, such as `notebook.auth` or `notebook.notebookapp`.
Check out the [migration guide](../migrating/server-imports.md) to learn more on how to update these server imports.
```
(configure-nbextensions)=
## Notebook extensions
The Notebook frontend can be extending with JupyterLab extensions.
See the {ref}`Frontend Extension Guide <frontend-extensions>` for more information.
[Security in Jupyter notebooks:](https://jupyter-server.readthedocs.io/en/stable/operators/security.html)
Since security policies vary from organization to organization, we encourage you to
consult with your security team on settings that would be best for your use
cases. Our documentation offers some responsible security practices, and we
recommend becoming familiar with the practices.

@ -1,62 +0,0 @@
# Interface Customization
Multiple elements in the Notebook interface can be customized via the Settings Editor.
## Layout
By default some widgets are displayed in pre-defined parts of the user interface, which are often called "areas" or "regions".
For example the table of contents will be displayed in the `left` area by default, while the debugger will be displayed in the `right` area.
However the positioning of some of these components can also be customized via the Settings Editor. Below are a few examples of how to do this.
### Open the Markdown Preview on the left
It is often useful to be able to see a rendered preview of a Markdown document while editing it.
By default the Markdown Preview opens on the right side of the application. However it is also possible to open it on the left side by changing the Notebook Shell settings in the Advanced Settings Editor:
```json
{
"layout": {
"Markdown Preview": {
"area": "left"
}
}
}
```
![a screenshot showing the markdown preview in Notebook 7](https://github.com/jupyter/notebook/assets/591645/3faf0823-ec6f-4d5f-a66f-d6f53dc383de)
### Configuring a third-party widget
Third-party extensions can also add widgets to the application shell. This is for example the case with the [Voila extension](https://github.com/voila-dashboards/voila), which adds a preview widget to visualize a notebook as a dashboard.
By default in JupyterLab the Voila Preview is added to the `main` area next to the corresponding notebook. With Notebook 7 it is possible to move the Voila Preview to the `right` area by changing the Notebook Shell setting in the Advanced Settings Editor as follows:
```json
{
"layout": {
"Voila Preview": {
"area": "right"
}
}
}
```
![a screenshot showing the voila preview in Notebook 7](https://github.com/jupyter/notebook/assets/591645/524ade3b-05de-4d3b-8ff9-089f2d38ac77)
```{note}
Refer to the [JupyterLab Layout Documentation](https://jupyterlab.readthedocs.io/en/latest/user/interface_customization.html#layout)
to learn more about the default positioning of other UI elements.
```
## Toolbars, Menu bar and Context Menu
It is also possible to customize toolbars, menus and context menu entries via the Settings Editor.
For example the items of the notebook toolbar can be reordered, or some menu entries can be hidden.
```{note}
Refer to the [JupyterLab Documentation](https://jupyterlab.readthedocs.io/en/latest/user/interface_customization.html)
to learn more about general interface customization via the settings editor.
```

@ -1,21 +0,0 @@
# Managing plugins
Notebook 7 uses the same extension system as JupyterLab. An extension can provide multiple plugins.
```{note}
See the [JupyterLab documentation](https://jupyterlab.readthedocs.io/en/latest/user/extensions.html) to learn more about the extension system.
```
## Examples
### Disabling the download button
By default Notebook 7 provides a way to download files from the file browser. This functionality consists of a context menu entry and a main menu entry. They are provided by an application plugin that can be disabled.
To disable the download entry of file browser context menus, open a terminal and run the following command:
```text
jupyter labextension disable @jupyterlab/filebrowser-extension:download
```
Then restart the application and refresh the page.

@ -1,9 +0,0 @@
# Contributing
```{toctree}
:caption: Contributor Documentation
:maxdepth: 1
contributing
development_faq
```

@ -0,0 +1,10 @@
===========
Contributor
===========
.. toctree::
:maxdepth: 1
:caption: Contributor Documentation
contributing
development_faq

@ -1,79 +0,0 @@
# Applying Custom CSS
To apply custom CSS, you can add a `/custom/custom.css` file in the jupyter `config` directory. You can find the path, `~/.jupyter`, to this directory by running `jupyter --paths`. There you can create a folder named `custom` and create a `custom.css` file within the folder.
## Jupyter Styling
You can use a custom CSS file to modify default Jupyter styling.
```css
/* Modify Jupyter Styles */
#top-panel-wrapper,
#jp-top-bar {
background-color: #aecad4 !important;
}
#menu-panel-wrapper,
#jp-MainMenu,
#menu-panel {
background-color: #aecad4 !important;
}
.jp-NotebookPanel-toolbar {
background-color: #aecad4 !important;
}
.lm-MenuBar-content {
color: #02484d;
}
```
![a screenshot custom jupyter styling](https://user-images.githubusercontent.com/12378147/245519958-17ce04e7-edc2-434e-8d93-a5c2de9fb225.png)
## Markdown
Another potential application for custom CSS is styling markdown.
```css
/* Headings */
h1,
h2 {
font-family: Impact, Charcoal, sans-serif;
font-weight: bold;
text-shadow: 2px 2px 4px #000000;
}
h1 {
font-size: 52px;
margin-bottom: 40px;
color: #10929e;
text-decoration: underline;
}
h2 {
font-size: 448px;
margin-bottom: 32px;
color: #76b4be;
text-transform: uppercase;
}
/* Block Quotes */
blockquote {
font-family: Georgia, serif;
font-size: 16px;
color: #19085c;
border-left: 8px solid #effffc;
background-color: #eafcff;
padding: 20px;
}
/* Lists */
ul,
ol {
font-family: Verdana, Geneva, sans-serif;
font-size: 18px;
color: #333333;
margin-bottom: 24px;
}
```
![a screenshot of custom markdown styling](https://user-images.githubusercontent.com/12378147/245520291-968848d3-d336-4523-a046-023b15082ff8.png)

@ -1,17 +0,0 @@
(development-faq)=
# Developer FAQ
1. How do I install a prerelease version such as a beta or release candidate?
You can install a prerelease version of the notebook using the `--pre` flag with `pip`:
```bash
python -m pip install notebook --pre --upgrade
```
If you are using `conda` or `mamba`, you can install a prerelease version of the notebook using the alpha or beta label. For example, to install the latest alpha release, you can run:
```bash
conda install -c conda-forge -c conda-forge/label/notebook_alpha notebook=7.0.0a18
```

@ -0,0 +1,10 @@
.. _development_faq:
Developer FAQ
=============
1. How do I install a prerelease version such as a beta or release candidate?
.. code-block:: bash
python -m pip install notebook --pre --upgrade

@ -64,7 +64,7 @@
"source": [
"def find_notebook(fullname, path=None):\n",
" \"\"\"find a notebook, given its fully qualified name and an optional path\n",
"\n",
" \n",
" This turns \"foo.bar\" into \"foo/bar.ipynb\"\n",
" and tries turning \"Foo_Bar\" into \"Foo Bar\" if Foo_Bar\n",
" does not exist.\n",
@ -79,7 +79,8 @@
" # let import Notebook_Name find \"Notebook Name.ipynb\"\n",
" nb_path = nb_path.replace(\"_\", \" \")\n",
" if os.path.isfile(nb_path):\n",
" return nb_path"
" return nb_path\n",
" "
]
},
{
@ -117,21 +118,21 @@
"source": [
"class NotebookLoader(object):\n",
" \"\"\"Module Loader for Jupyter Notebooks\"\"\"\n",
"\n",
" def __init__(self, path=None):\n",
" self.shell = InteractiveShell.instance()\n",
" self.path = path\n",
"\n",
" \n",
" def load_module(self, fullname):\n",
" \"\"\"import a notebook as a module\"\"\"\n",
" path = find_notebook(fullname, self.path)\n",
"\n",
" print(\"importing Jupyter notebook from %s\" % path)\n",
"\n",
" \n",
" print (\"importing Jupyter notebook from %s\" % path)\n",
" \n",
" # load the notebook object\n",
" with io.open(path, 'r', encoding='utf-8') as f:\n",
" nb = read(f, 4)\n",
"\n",
" \n",
" \n",
" # create the module and add it to sys.modules\n",
" # if name in sys.modules:\n",
" # return sys.modules[name]\n",
@ -140,22 +141,22 @@
" mod.__loader__ = self\n",
" mod.__dict__['get_ipython'] = get_ipython\n",
" sys.modules[fullname] = mod\n",
"\n",
" \n",
" # extra work to ensure that magics that would affect the user_ns\n",
" # actually affect the notebook module's ns\n",
" save_user_ns = self.shell.user_ns\n",
" self.shell.user_ns = mod.__dict__\n",
"\n",
" \n",
" try:\n",
" for cell in nb.cells:\n",
" if cell.cell_type == 'code':\n",
" # transform the input to executable Python\n",
" code = self.shell.input_transformer_manager.transform_cell(cell.source)\n",
" # run the code in themodule\n",
" exec(code, mod.__dict__)\n",
" for cell in nb.cells:\n",
" if cell.cell_type == 'code':\n",
" # transform the input to executable Python\n",
" code = self.shell.input_transformer_manager.transform_cell(cell.source)\n",
" # run the code in themodule\n",
" exec(code, mod.__dict__)\n",
" finally:\n",
" self.shell.user_ns = save_user_ns\n",
" return mod"
" return mod\n"
]
},
{
@ -193,23 +194,22 @@
"source": [
"class NotebookFinder(object):\n",
" \"\"\"Module finder that locates Jupyter Notebooks\"\"\"\n",
"\n",
" def __init__(self):\n",
" self.loaders = {}\n",
"\n",
" \n",
" def find_module(self, fullname, path=None):\n",
" nb_path = find_notebook(fullname, path)\n",
" if not nb_path:\n",
" return\n",
"\n",
" \n",
" key = path\n",
" if path:\n",
" # lists aren't hashable\n",
" key = os.path.sep.join(path)\n",
"\n",
" \n",
" if key not in self.loaders:\n",
" self.loaders[key] = NotebookLoader(path)\n",
" return self.loaders[key]"
" return self.loaders[key]\n"
]
},
{
@ -308,16 +308,12 @@
"lexer = PythonLexer()\n",
"\n",
"# publish the CSS for pygments highlighting\n",
"display(\n",
" HTML(\n",
" \"\"\"\n",
"display(HTML(\"\"\"\n",
"<style type='text/css'>\n",
"%s\n",
"</style>\n",
"\"\"\"\n",
" % formatter.get_style_defs()\n",
" )\n",
")"
"\"\"\" % formatter.get_style_defs()\n",
"))"
]
},
{
@ -341,7 +337,6 @@
" html.append(\"<pre>%s</pre>\" % cell.source)\n",
" display(HTML('\\n'.join(html)))\n",
"\n",
"\n",
"show_notebook(os.path.join(\"nbpackage\", \"mynotebook.ipynb\"))"
]
},
@ -458,7 +453,6 @@
"outputs": [],
"source": [
"from nbpackage.nbs import other\n",
"\n",
"other.bar(5)"
]
},
@ -483,8 +477,8 @@
"from IPython.paths import get_ipython_package_dir\n",
"\n",
"utils = os.path.join(get_ipython_package_dir(), 'utils')\n",
"shutil.copy(\n",
" os.path.join(\"nbpackage\", \"mynotebook.ipynb\"), os.path.join(utils, \"inside_ipython.ipynb\")\n",
"shutil.copy(os.path.join(\"nbpackage\", \"mynotebook.ipynb\"),\n",
" os.path.join(utils, \"inside_ipython.ipynb\")\n",
")"
]
},
@ -504,7 +498,6 @@
"outputs": [],
"source": [
"from IPython.utils import inside_ipython\n",
"\n",
"inside_ipython.whatsmyname()"
]
},

@ -185,7 +185,7 @@
"source": [
"The first idea of mouse based navigation is that **cells can be selected by clicking on them.** The currently selected cell gets a grey or green border depending on whether the notebook is in edit or command mode. If you click inside a cell's editor area, you will enter edit mode. If you click on the prompt or output area of a cell you will enter command mode.\n",
"\n",
"If you are running this notebook in a live session (not on https://nbviewer.jupyter.org) try selecting different cells and going between edit and command mode. Try typing into a cell."
"If you are running this notebook in a live session (not on http://nbviewer.jupyter.org) try selecting different cells and going between edit and command mode. Try typing into a cell."
]
},
{

@ -100,7 +100,6 @@
"outputs": [],
"source": [
"import time\n",
"\n",
"time.sleep(10)"
]
},
@ -124,14 +123,14 @@
"outputs": [],
"source": [
"import sys\n",
"\n",
"from ctypes import CDLL\n",
"# This will crash a Linux or Mac system\n",
"# equivalent calls can be made on Windows\n",
"\n",
"# Uncomment these lines if you would like to see the segfault\n",
"\n",
"# dll = 'dylib' if sys.platform == 'darwin' else 'so.6'\n",
"# libc = CDLL(\"libc.%s\" % dll)\n",
"# libc = CDLL(\"libc.%s\" % dll) \n",
"# libc.time(-1) # BOOM!!"
]
},
@ -224,7 +223,8 @@
}
],
"source": [
"print(\"hi, stderr\", file=sys.stderr)"
"from __future__ import print_function\n",
"print('hi, stderr', file=sys.stderr)"
]
},
{
@ -267,9 +267,7 @@
}
],
"source": [
"import sys\n",
"import time\n",
"\n",
"import time, sys\n",
"for i in range(8):\n",
" print(i)\n",
" time.sleep(0.5)"

@ -3,4 +3,4 @@
from IPython.display import FileLink, display
files =!ls *.py
for f in files:
display(FileLink(f))
display(FileLink(f))

@ -4,4 +4,4 @@ from IPython.display import FileLinks, display
dirs =!ls -d */
for d in dirs:
if d != '__pycache__/':
display(FileLinks(d))
display(FileLinks(d))

@ -1,17 +0,0 @@
(frontend-extensions)=
# Custom front-end extensions
This describes the basic steps to write a TypeScript extension for the Jupyter
notebook front-end. This allows you to customize the behaviour of the various
pages like the dashboard, the notebook, or the text editor.
Starting with Notebook 7, front-end extensions for the notebook can be developed
as prebuilt JupyterLab extensions.
This means Notebook 7 is able to reuse many of the existing extensions from the JupyterLab ecosystem as is.
If you would like to develop a prebuilt extension for Notebook 7, check out:
- [JupyterLab Extension Tutorial](https://jupyterlab.readthedocs.io/en/latest/extension/extension_tutorial.html): A tutorial to learn how to make a simple JupyterLab extension.
- The [JupyterLab Extension Examples Repository](https://github.com/jupyterlab/extension-examples): A repository containing many examples of JupyterLab extensions for performing various tasks: adding commands, adding a new widget, handling user settings, etc.

@ -0,0 +1,19 @@
.. _frontend_extensions:
===========================
Custom front-end extensions
===========================
This describes the basic steps to write a TypeScript extension for the Jupyter
notebook front-end. This allows you to customize the behaviour of the various
pages like the dashboard, the notebook, or the text editor.
Starting with Notebook v7, front-end extensions for the notebook can be developed
as prebuilt JupyterLab extensions.
This means Notebook v7 is able to reuse many of the existing extensions from the JupyterLab ecosystem as is.
If you would like to develop a prebuilt extension for Notebook v7, check out:
- `JupyterLab Extension Tutorial <https://jupyterlab.readthedocs.io/en/latest/extension/extension_tutorial.html>`_: A tutorial to learn how to make a simple JupyterLab extension.
- The `JupyterLab Extension Examples Repository <https://github.com/jupyterlab/extension-examples>`_: A short tutorial series to learn how to develop extensions for JupyterLab by example.

@ -1,27 +0,0 @@
# Extending the Notebook
```{warning}
Please note that the extension system for Notebook 7 is radically different
from the one used in Notebook 6.5.x and earlier. If you are looking for
information on how to extend the classic Notebook, please refer to the
[documentation for NbClassic](https://nbclassic.readthedocs.io/en/latest/extending/index.html).
```
```{note}
With Notebook 7 being developed on top of JupyterLab and Jupyter Server, the
frontend extension system is now based on the same extension system used by JupyterLab.
Server extensions are also now based on the same system used by Jupyter Server.
You will find below a link to the relevant documentations.
```
Certain subsystems of the notebook server are designed to be extended or
overridden by users. These documents explain these systems, and show how to
override the notebook's defaults with your own custom behavior.
```{toctree}
:maxdepth: 2
Extending the Jupyter Server <https://jupyter-server.readthedocs.io/en/stable/developers/index.html>
frontend_extensions
```

@ -0,0 +1,13 @@
======================
Extending the Notebook
======================
Certain subsystems of the notebook server are designed to be extended or
overridden by users. These documents explain these systems, and show how to
override the notebook's defaults with your own custom behavior.
.. toctree::
:maxdepth: 2
Extending the Jupyter Server <https://jupyter-server.readthedocs.io/en/stable/developers/index.html>
frontend_extensions

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save